Replaced the 'Turn' protocol by the Update' protocol.

Bumped the UQM and netplay protocol versions.
Some cleanups.



git-svn-id: svn://svn.code.sf.net/p/sc2/code/trunk@3537 8092fc87-c524-0410-9efc-e669fe64eaf9
This commit is contained in:
Meep-Eep
2010-04-24 20:59:07 +00:00
parent 91fde6f5e7
commit e4886e60ee
32 changed files with 835 additions and 535 deletions
+14 -5
View File
@@ -302,17 +302,29 @@ SetContext (OldContext);
return (hBattleShip);
}
static QUEUE *
GetShipQueueForSide (COUNT sideNr)
{
if (sideNr == 0)
return &GLOBAL (built_ship_q);
else
return &GLOBAL (npc_built_ship_q);
}
// Get the next ship to use.
HSTARSHIP
GetEncounterStarShip (STARSHIP *LastStarShipPtr, COUNT which_player)
{
HSTARSHIP hBattleShip;
if (LOBYTE (GLOBAL (CurrentActivity)) == IN_HYPERSPACE)
{
// Get the next ship from the battle group.
hBattleShip = GetHeadLink (&race_q[which_player]);
}
else if (LOBYTE (GLOBAL (CurrentActivity)) == SUPER_MELEE)
{
// Let the player chose his own ship. (May be a computer player).
// Let the player chose their own ship. (May be a computer player).
if (!(GLOBAL (CurrentActivity) & IN_BATTLE))
{
@@ -367,10 +379,7 @@ GetEncounterStarShip (STARSHIP *LastStarShipPtr, COUNT which_player)
QUEUE *pQueue;
HSHIPFRAG hNextShip;
if (which_player == 0)
pQueue = &GLOBAL (built_ship_q);
else
pQueue = &GLOBAL (npc_built_ship_q);
pQueue = GetShipQueueForSide (which_player);
hBattleShip = GetHeadLink (&race_q[which_player]);
for (hStarShip = GetHeadLink (pQueue);
+1
View File
@@ -493,6 +493,7 @@ spawn_ship (STARSHIP *StarShipPtr)
return (hShip != 0);
}
// Select a new ship and spawn it.
BOOLEAN
GetNextStarShip (STARSHIP *LastStarShipPtr, COUNT which_side)
{
+7 -2
View File
@@ -208,7 +208,7 @@ DrawFileString (const MeleeTeam *team, const POINT *origin,
}
// returns true if there are any entries in the view, in which case
// pMS->load.bot gets set to the index of the bottom entry in the view.
// pMS->load.bot gets set to the index just past the bottom entry in the view.
// returns false if not, in which case, the entire view remains unchanged.
static bool
FillFileView (MELEE_STATE *pMS)
@@ -350,7 +350,7 @@ DoLoadTeam (MELEE_STATE *pMS)
if (PulsedInputState.menu[KEY_MENU_SELECT])
{
// Copy the selected fleet to the player.
Melee_Change_team (pMS, pMS->side,
Melee_LocalChange_team (pMS, pMS->side,
pMS->load.view[pMS->load.cur - pMS->load.top]);
}
@@ -417,11 +417,16 @@ DoLoadTeam (MELEE_STATE *pMS)
if (newIndex != pMS->load.cur)
{
// The cursor has been moved.
LockMutex (GraphicsLock);
if (newTop == pMS->load.top)
{
// The view itself hasn't changed.
SelectFileString (pMS, false);
}
else
{
// The view is changed.
pMS->load.top = newTop;
DrawFileStrings (pMS);
}
+329 -100
View File
@@ -197,6 +197,7 @@ static BOOLEAN DoConfirmSettings (MELEE_STATE *pMS);
#define DTSHS_BLOCKCUR 8
static BOOLEAN DrawTeamString (MELEE_STATE *pMS, COUNT side,
COUNT HiLiteState, const char *str);
static void DrawFleetValue (MELEE_STATE *pMS, COUNT side, COUNT HiLiteState);
static void Melee_UpdateView_fleetValue (MELEE_STATE *pMS, COUNT side);
static void Melee_UpdateView_ship (MELEE_STATE *pMS, COUNT side,
@@ -363,6 +364,7 @@ DrawTeams (void)
}
DrawTeamString (pMeleeState, side, DTSHS_NORMAL, NULL);
DrawFleetValue (pMeleeState, side, DTSHS_NORMAL);
}
}
@@ -422,6 +424,59 @@ RedrawMeleeFrame (void)
RepairMeleeFrame (&r);
}
static void
GetTeamStringRect (COUNT side, RECT *r)
{
r->corner.x = MELEE_X_OFFS - 1;
r->corner.y = (side + 1) * (MELEE_Y_OFFS
+ ((MELEE_BOX_HEIGHT + MELEE_BOX_SPACE) * NUM_MELEE_ROWS + 2));
r->extent.width = NUM_MELEE_COLUMNS * (MELEE_BOX_WIDTH + MELEE_BOX_SPACE)
- 29;
r->extent.height = 13;
}
static void
GetFleetValueRect (COUNT side, RECT *r)
{
r->corner.x = MELEE_X_OFFS
+ NUM_MELEE_COLUMNS * (MELEE_BOX_WIDTH + MELEE_BOX_SPACE) - 30;
r->corner.y = (side + 1) * (MELEE_Y_OFFS
+ ((MELEE_BOX_HEIGHT + MELEE_BOX_SPACE) * NUM_MELEE_ROWS + 2));
r->extent.width = 29;
r->extent.height = 13;
}
static void
DrawFleetValue (MELEE_STATE *pMS, COUNT side, COUNT HiLiteState)
{
RECT r;
TEXT rtText;
UNICODE buf[30];
COUNT fleetValue;
GetFleetValueRect (side ,&r);
if (HiLiteState == DTSHS_REPAIR)
{
RepairMeleeFrame (&r);
return;
}
SetContextFont (MicroFont);
fleetValue = MeleeSetup_getFleetValue (pMS->meleeSetup, side);
sprintf (buf, "%u", fleetValue);
rtText.pStr = buf;
rtText.align = ALIGN_RIGHT;
rtText.CharCount = (COUNT)~0;
rtText.baseline.y = r.corner.y + r.extent.height - 3;
rtText.baseline.x = r.corner.x + r.extent.width;
SetContextForeGroundColor (!(HiLiteState & DTSHS_SELECTED)
? TEAM_NAME_TEXT_COLOR : TEAM_NAME_EDIT_TEXT_COLOR);
font_DrawText (&rtText);
}
// If teamName == NULL, the team name is taken from pMS->meleeSetup
static BOOLEAN
DrawTeamString (MELEE_STATE *pMS, COUNT side, COUNT HiLiteState,
@@ -430,11 +485,7 @@ DrawTeamString (MELEE_STATE *pMS, COUNT side, COUNT HiLiteState,
RECT r;
TEXT lfText;
r.corner.x = MELEE_X_OFFS - 1;
r.corner.y = (side + 1) * (MELEE_Y_OFFS
+ ((MELEE_BOX_HEIGHT + MELEE_BOX_SPACE) * NUM_MELEE_ROWS + 2));
r.extent.width = NUM_MELEE_COLUMNS * (MELEE_BOX_WIDTH + MELEE_BOX_SPACE);
r.extent.height = 13;
GetTeamStringRect (side, &r);
if (HiLiteState == DTSHS_REPAIR)
{
RepairMeleeFrame (&r);
@@ -446,7 +497,6 @@ DrawTeamString (MELEE_STATE *pMS, COUNT side, COUNT HiLiteState,
lfText.pStr = (teamName != NULL) ? teamName :
MeleeSetup_getTeamName (pMS->meleeSetup, side);
lfText.baseline.y = r.corner.y + r.extent.height - 3;
lfText.baseline.x = r.corner.x + 1;
lfText.align = ALIGN_LEFT;
lfText.CharCount = strlen (lfText.pStr);
@@ -454,20 +504,9 @@ DrawTeamString (MELEE_STATE *pMS, COUNT side, COUNT HiLiteState,
BatchGraphics ();
if (!(HiLiteState & DTSHS_EDIT))
{ // normal or selected state
TEXT rtText;
UNICODE buf[30];
sprintf (buf, "%u", MeleeSetup_getFleetValue (pMS->meleeSetup, side));
rtText.pStr = buf;
rtText.align = ALIGN_RIGHT;
rtText.CharCount = (COUNT)~0;
rtText.baseline.y = lfText.baseline.y;
rtText.baseline.x = lfText.baseline.x + r.extent.width - 1;
SetContextForeGroundColor (!(HiLiteState & DTSHS_SELECTED)
? TEAM_NAME_TEXT_COLOR : TEAM_NAME_EDIT_TEXT_COLOR);
font_DrawText (&lfText);
font_DrawText (&rtText);
}
else
{ // editing state
@@ -476,9 +515,6 @@ DrawTeamString (MELEE_STATE *pMS, COUNT side, COUNT HiLiteState,
BYTE char_deltas[MAX_TEAM_CHARS];
BYTE *pchar_deltas;
// not drawing team bucks
r.extent.width -= 29;
TextRect (&lfText, &text_r, char_deltas);
if ((text_r.extent.width + 2) >= r.extent.width)
{ // the text does not fit the input box size and so
@@ -712,6 +748,8 @@ Deselect (BYTE opt)
// Not currently editing the team name.
DrawTeamString (pMeleeState, pMeleeState->side,
DTSHS_NORMAL, NULL);
DrawFleetValue (pMeleeState, pMeleeState->side,
DTSHS_NORMAL);
}
}
break;
@@ -773,6 +811,8 @@ Select (BYTE opt)
// Not currently editing the team name.
DrawTeamString (pMeleeState, pMeleeState->side,
DTSHS_SELECTED, NULL);
DrawFleetValue (pMeleeState, pMeleeState->side,
DTSHS_SELECTED);
}
}
break;
@@ -942,7 +982,7 @@ static void
DeleteCurrentShip (MELEE_STATE *pMS)
{
FleetShipIndex slotI = GetShipIndex (pMS->row, pMS->col);
Melee_Change_ship (pMS, pMS->side, slotI, MELEE_NONE);
Melee_LocalChange_ship (pMS, pMS->side, slotI, MELEE_NONE);
}
static bool
@@ -992,6 +1032,23 @@ OnTeamNameChange (TEXTENTRY_STATE *pTES)
return ret;
}
static BOOLEAN
TeamNameFrameCallback (TEXTENTRY_STATE *pTES)
{
#ifdef NETPLAY
// Process incoming packets, so that remote changes are displayed
// while we are editing the team name.
// The team name itself isn't modified visually due to remote changes
// while it is being edited.
netInput ();
#endif
(void) pTES;
return TRUE;
// Keep editing
}
static void
BuildPickShipPopup (MELEE_STATE *pMS)
{
@@ -1005,7 +1062,7 @@ BuildPickShipPopup (MELEE_STATE *pMS)
// A ship has been selected.
// Add the currently selected ship to the fleet.
FleetShipIndex index = GetShipIndex (pMS->row, pMS->col);
Melee_Change_ship (pMS, pMS->side, index, pMS->currentShip);
Melee_LocalChange_ship (pMS, pMS->side, index, pMS->currentShip);
AdvanceCursor (pMS);
}
@@ -1122,12 +1179,13 @@ DoEdit (MELEE_STATE *pMS)
tes.MaxSize = MAX_TEAM_CHARS + 1;
tes.CbParam = pMS;
tes.ChangeCallback = OnTeamNameChange;
tes.FrameCallback = 0;
tes.FrameCallback = TeamNameFrameCallback;
DoTextEntry (&tes);
// done entering
pMS->CurIndex = MELEE_STATE_INDEX_DONE;
if (!Melee_Change_teamName (pMS, pMS->side, buf)) {
if (!tes.Success ||
!Melee_LocalChange_teamName (pMS, pMS->side, buf)) {
// The team name was not changed, so it was not redrawn.
// However, because we now leave edit mode, we still
// need to redraw.
@@ -1253,6 +1311,7 @@ DoConfirmSettings (MELEE_STATE *pMS)
if (PulsedInputState.menu[KEY_MENU_CANCEL])
{
// The connection is explicitely cancelled, locally.
pMS->InputFunc = DoMelee;
#ifdef NETPLAY
cancelConfirmations ();
@@ -1266,6 +1325,7 @@ DoConfirmSettings (MELEE_STATE *pMS)
PulsedInputState.menu[KEY_MENU_UP] ||
PulsedInputState.menu[KEY_MENU_DOWN])
{
// The player moves the cursor; cancel the confirmation.
pMS->InputFunc = DoMelee;
#ifdef NETPLAY
cancelConfirmations ();
@@ -1278,7 +1338,9 @@ DoConfirmSettings (MELEE_STATE *pMS)
#ifndef NETPLAY
pMS->InputFunc = DoMelee;
SeedRandomNumbers ();
pMS->meleeStarted = TRUE;
StartMelee (pMS);
pMS->meleeStarted = FALSE;
if (GLOBAL (CurrentActivity) & CHECK_ABORT)
return FALSE;
return TRUE;
@@ -2041,9 +2103,11 @@ Melee (void)
if (LoadMeleeConfig (&MenuState) == -1)
{
PlayerControl[0] = HUMAN_CONTROL | STANDARD_RATING;
Melee_Change_team (&MenuState, 0, MenuState.load.preBuiltList[0]);
Melee_LocalChange_team (&MenuState, 0,
MenuState.load.preBuiltList[0]);
PlayerControl[1] = COMPUTER_CONTROL | STANDARD_RATING;
Melee_Change_team (&MenuState, 1, MenuState.load.preBuiltList[1]);
Melee_LocalChange_team (&MenuState, 1,
MenuState.load.preBuiltList[1]);
}
MenuState.side = 0;
@@ -2186,7 +2250,6 @@ resetFeedback (NetConnection *conn, NetplayResetReason reason,
{
const char *msg;
GLOBAL (CurrentActivity) |= CHECK_ABORT;
flushPacketQueues ();
// If the local side queued a reset packet as a result of a
// remote reset, that packet will not have been sent yet.
@@ -2202,6 +2265,10 @@ resetFeedback (NetConnection *conn, NetplayResetReason reason,
msg = resetReasonString (reason);
if (msg != NULL)
connectionFeedback (conn, msg, false);
// End supermelee. This must not be done before connectionFeedback(),
// otherwise the message will immediately disappear.
GLOBAL (CurrentActivity) |= CHECK_ABORT;
}
void
@@ -2241,15 +2308,24 @@ closeFeedback (NetConnection *conn)
static void
Melee_UpdateView_fleetValue (MELEE_STATE *pMS, COUNT side)
{
if (pMS->meleeStarted)
return;
LockMutex (GraphicsLock);
DrawTeamString (pMS, side, DTSHS_REPAIR, NULL);
DrawFleetValue (pMS, side, DTSHS_REPAIR);
// BUG: The fleet value is always drawn as deselected.
UnlockMutex (GraphicsLock);
}
static void
Melee_UpdateView_ship (MELEE_STATE *pMS, COUNT side, FleetShipIndex index)
{
MeleeShip ship = MeleeSetup_getShip (pMS->meleeSetup, side, index);
MeleeShip ship;
if (pMS->meleeStarted)
return;
ship = MeleeSetup_getShip (pMS->meleeSetup, side, index);
LockMutex (GraphicsLock);
if (ship == MELEE_NONE)
@@ -2266,6 +2342,9 @@ Melee_UpdateView_ship (MELEE_STATE *pMS, COUNT side, FleetShipIndex index)
static void
Melee_UpdateView_teamName (MELEE_STATE *pMS, COUNT side)
{
if (pMS->meleeStarted)
return;
LockMutex (GraphicsLock);
DrawTeamString (pMS, side, DTSHS_REPAIR, NULL);
UnlockMutex (GraphicsLock);
@@ -2273,10 +2352,11 @@ Melee_UpdateView_teamName (MELEE_STATE *pMS, COUNT side)
///////////////////////////////////////////////////////////////////////////
// Melee_Change_xxx() functions are called when some value in the supermelee
// fleet setup screen has changed, eithed locally, or remotely.
// Melee_Change_xxx() functions are helper functions, called when some value
// in the supermelee fleet setup screen has changed, eithed because of a
// local change, or a remote change.
bool
static bool
Melee_Change_ship (MELEE_STATE *pMS, COUNT side, FleetShipIndex index,
MeleeShip ship)
{
@@ -2300,16 +2380,11 @@ Melee_Change_ship (MELEE_STATE *pMS, COUNT side, FleetShipIndex index,
UnlockMutex (GraphicsLock);
}
#ifdef NETPLAY
// Notify network connections of the change.
Netplay_NotifyAll_setShip (pMS, side, index);
#endif /* NETPLAY */
return true;
}
// Pre: 'name' is '\0'-terminated
bool
static bool
Melee_Change_teamName (MELEE_STATE *pMS, COUNT side, const char *name)
{
MeleeSetup *setup = pMS->meleeSetup;
@@ -2329,37 +2404,93 @@ Melee_Change_teamName (MELEE_STATE *pMS, COUNT side, const char *name)
Melee_UpdateView_teamName (pMS, side);
}
return true;
}
///////////////////////////////////////////////////////////////////////////
// Melee_LocalChange_xxx() functions are called when some value in the
// supermelee fleet setup screen has changed because of a local action.
// The behavior of these functions (and the comments therein) follow the
// description in doc/devel/netplay/protocol.
bool
Melee_LocalChange_ship (MELEE_STATE *pMS, COUNT side, FleetShipIndex index,
MeleeShip ship)
{
if (!Melee_Change_ship (pMS, side, index, ship))
return false;
#ifdef NETPLAY
Netplay_NotifyAll_setTeamName (pMS, side);
{
MeleeSetup *setup = pMS->meleeSetup;
MeleeShip sentShip = MeleeSetup_getSentShip (setup, side, index);
if (sentShip == MELEE_UNSET)
{
// State 1.
// Notify network connections of the change.
Netplay_NotifyAll_setShip (pMS, side, index);
MeleeSetup_setSentShip (setup, side, index, ship);
}
}
#endif /* NETPLAY */
return true;
}
// Pre: 'name' is '\0'-terminated
bool
Melee_LocalChange_teamName (MELEE_STATE *pMS, COUNT side, const char *name)
{
if (!Melee_Change_teamName (pMS, side, name))
return false;
#ifdef NETPLAY
{
MeleeSetup *setup = pMS->meleeSetup;
const char *sentName = MeleeSetup_getSentTeamName (setup, side);
if (sentName == NULL)
{
// State 1.
// Notify network connections of the change.
Netplay_NotifyAll_setTeamName (pMS, side);
MeleeSetup_setSentTeamName (setup, side, name);
}
}
#endif /* NETPLAY */
return true;
}
bool
Melee_Change_fleet (MELEE_STATE *pMS, size_t teamNr, const MeleeShip *fleet)
Melee_LocalChange_fleet (MELEE_STATE *pMS, size_t teamNr,
const MeleeShip *fleet)
{
MeleeSetup *setup = pMS->meleeSetup;
FleetShipIndex slotI;
bool changed = false;
for (slotI = 0; slotI < MELEE_FLEET_SIZE; slotI++) {
if (MeleeSetup_setShip (setup, teamNr, slotI, fleet[slotI]))
for (slotI = 0; slotI < MELEE_FLEET_SIZE; slotI++)
{
if (Melee_LocalChange_ship (pMS, teamNr, slotI, fleet[slotI]))
changed = true;
}
return changed;
}
bool
Melee_Change_team (MELEE_STATE *pMS, size_t teamNr, const MeleeTeam *team)
Melee_LocalChange_team (MELEE_STATE *pMS, size_t teamNr,
const MeleeTeam *team)
{
MeleeSetup *setup = pMS->meleeSetup;
const MeleeShip *fleet = MeleeTeam_getFleet (team);
const char *name = MeleeTeam_getTeamName (team);
bool changed = false;
if (Melee_Change_fleet (pMS, teamNr, fleet))
if (Melee_LocalChange_fleet (pMS, teamNr, fleet))
changed = true;
if (MeleeSetup_setTeamName (setup, teamNr, MeleeTeam_getTeamName (team)))
if (Melee_LocalChange_teamName (pMS, teamNr, name))
changed = true;
return changed;
@@ -2367,8 +2498,40 @@ Melee_Change_team (MELEE_STATE *pMS, size_t teamNr, const MeleeTeam *team)
///////////////////////////////////////////////////////////////////////////
// Send the entire team to the remote side. Used when the connection has
// just been established, or after the setup menu is reentered after battle.
void
Melee_bootstrapSyncTeam (MELEE_STATE *meleeState, size_t teamNr)
{
MeleeSetup *setup = meleeState->meleeSetup;
FleetShipIndex slotI;
const char *teamName;
// Send the current fleet.
Netplay_NotifyAll_setFleet(meleeState, teamNr);
// Update the last sent fleet.
for (slotI = 0; slotI < MELEE_FLEET_SIZE; slotI++)
{
MeleeShip ship = MeleeSetup_getShip (setup, teamNr, slotI);
assert (MeleeSetup_getSentShip (setup, teamNr, slotI) == MELEE_UNSET);
MeleeSetup_setSentShip (setup, teamNr, slotI, ship);
}
// Send the current team name.
Netplay_NotifyAll_setTeamName (meleeState, teamNr);
// Update the last sent team name.
teamName = MeleeSetup_getTeamName (setup, teamNr);
MeleeSetup_setSentTeamName (setup, teamNr, teamName);
}
///////////////////////////////////////////////////////////////////////////
// Melee_RemoteChange_xxx() functions are called when some value in the
// supermelee fleet setup screen has changed remotely.
// The behavior of these functions (and the comments therein) follow the
// description in doc/devel/netplay/protocol.
#ifdef NETPLAY
void
@@ -2377,73 +2540,139 @@ Melee_RemoteChange_ship (MELEE_STATE *pMS, NetConnection *conn, COUNT side,
{
MeleeSetup *setup = pMS->meleeSetup;
MeleeShip currentShip = MeleeSetup_getShip (setup, side, index);
MeleeShip sentShip = MeleeSetup_getSentShip (setup, side, index);
MeleeShip currentShip;
if (ship == currentShip)
if (sentShip == MELEE_UNSET)
{
// The remote side has confirmed what we want the value to be.
// If we had made the same local change before, then an update
// has already been sent. If not, then there is nothing to change.
// Either way, we do not need to send an update.
MeleeSetup_setConfirmedShip (setup, side, index, ship);
} else {
// The remote side wants to make a change.
// We accept the change when we don't have any changes of our own,
// or when we do have changes, but we "lose" the tie break.
// If we "win" the tie break, we have already sent an update to the
// remote side when our local change was made, so we do not need to
// send anything. The remote side still needs to confirm this local
// change, of which it will become aware shortly, when the already
// sent update message arrives.
MeleeShip confirmedShip = MeleeSetup_getConfirmedShip (setup, side,
index);
if (currentShip == confirmedShip ||
NetConnection_getDiscriminant(conn))
// State 1
// Change the ship locally.
Melee_Change_ship (pMS, side, index, ship);
// Notify the remote side.
Netplay_NotifyAll_setShip (pMS, side, index);
// A packet has now been received and sent. End of turn.
return;
}
// A packet has been sent and received. End of turn.
MeleeSetup_setSentShip (setup, side, index, MELEE_UNSET);
if (ship != sentShip)
{
// Rule 2c or 3d. The value which we sent is different from the value
// which the opponent sent. We need a tie-breaker to determine which
// value prevails.
if (NetConnection_getPlayerNr (conn) != side)
{
MeleeSetup_setConfirmedShip (setup, side, index, ship);
Melee_Change_ship (pMS, side, index, ship);
// This will also cause a notification of the local
// change to be sent to the remote side, which will act
// as a confirmation.
// Rule 2c+ or 3d+
// We win the tie-breaker. The value which we sent prevails.
}
else
{
// Rule 2c- or 3d-.
// We lose the tie-breaker. We adopt the remote value.
Melee_Change_ship (pMS, side, index, ship);
return;
}
}
/*
else
{
// Rule 2b or 3c. The value which we sent is the value which
// the opponent sent. This confirms the value.
}
*/
// Rule 2b, 2c+, 3c, or 3d+. The value which we sent is confirmed.
currentShip = MeleeSetup_getShip (setup, side, index);
if (currentShip != sentShip)
{
// Rule 3c or 3d+. We had a local change which was yet
// unreported.
// Notify the remote side and keep track of what we sent.
Netplay_NotifyAll_setShip (pMS, side, index);
MeleeSetup_setSentShip (setup, side, index, ship);
}
}
void
Melee_RemoteChange_teamName (MELEE_STATE *pMS, NetConnection *conn, COUNT side,
const char *name)
Melee_RemoteChange_teamName (MELEE_STATE *pMS, NetConnection *conn,
COUNT side, const char *newName)
{
MeleeSetup *setup = pMS->meleeSetup;
const char *currentName = MeleeSetup_getTeamName (setup, side);
const char *sentName = MeleeSetup_getSentTeamName (setup, side);
const char *currentName;
if (strcmp (name, currentName) == 0)
if (sentName == NULL)
{
// The remote side has confirmed what we want the value to be.
// If we had made the same local change before, then an update
// has already been sent. If not, then there is nothing to change.
// Either way, we do not need to send an update.
MeleeSetup_setConfirmedTeamName (setup, side, name);
} else {
// The remote side wants to make a change.
// We accept the change when we don't have any changes of our own,
// or when we do have changes, but we "lose" the tie break.
// If we "win" the tie break, we have already sent an update to the
// remote side when our local change was made, so we do not need to
// send anything. The remote side still needs to confirm this local
// change, of which it will become aware shortly, when the already
// sent update message arrives.
const char *confirmedName =
MeleeSetup_getConfirmedTeamName (setup, side);
if (strcmp (currentName, confirmedName) == 0 ||
NetConnection_getDiscriminant(conn))
// State 1
// Change the team name locally.
Melee_Change_teamName (pMS, side, newName);
// Notify the remote side.
Netplay_NotifyAll_setTeamName (pMS, side);
// A packet has now been received and sent. End of turn.
// The sent team name is still unset, so we don't have to reset it.
return;
}
if (strcmp (newName, sentName) == 0)
{
// Rule 2c or 3d. The value which we sent is different from the value
// which the opponent sent. We need a tie-breaker to determine which
// value prevails.
if (NetConnection_getPlayerNr (conn) != side)
{
MeleeSetup_setConfirmedTeamName (setup, side, name);
Melee_Change_teamName (pMS, side, name);
// This will also cause a notification of the local
// change to be sent to the remote side, which will act
// as a confirmation.
// Rule 2c+ or 3d+
// We win the tie-breaker. The value which we sent prevails.
}
else
{
// Rule 2c- or 3d-.
// We lose the tie-breaker. We adopt the remote value.
Melee_Change_teamName (pMS, side, newName);
MeleeSetup_setSentTeamName (setup, side, NULL);
return;
}
}
/*
else
{
// Rule 2b or 3c. The value which we sent is the value which
// the opponent sent. This confirms the value.
}
*/
// Rule 2b, 2c+, 3c, or 3d+. The value which we sent is confirmed.
currentName = MeleeSetup_getTeamName (setup, side);
if (strcmp (currentName, sentName) != 0)
{
// Rule 3c or 3d+. We had a local change which was yet
// unreported.
// A packet has been sent and received, which ends the turn.
// We don't bother clearing the sent team name, as we're going
// to send a new packet immediately.
// Notify the remote side and keep track of what we sent.
Netplay_NotifyAll_setTeamName (pMS, side);
// Update the last sent message.
MeleeSetup_setSentTeamName (setup, side, newName);
}
else
{
// A packet has been sent and received. End of turn.
MeleeSetup_setSentTeamName (setup, side, NULL);
}
}
+9 -5
View File
@@ -59,6 +59,7 @@ struct melee_state
BOOLEAN (*InputFunc) (struct melee_state *pInputState);
BOOLEAN Initialized;
BOOLEAN meleeStarted;
MELEE_OPTIONS MeleeOption;
COUNT side;
COUNT row;
@@ -108,14 +109,17 @@ void resetFeedback (NetConnection *conn, NetplayResetReason reason,
void errorFeedback (NetConnection *conn);
void closeFeedback (NetConnection *conn);
bool Melee_Change_ship (MELEE_STATE *pMS, COUNT side, FleetShipIndex index,
MeleeShip ship);
bool Melee_Change_teamName (MELEE_STATE *pMS, COUNT side, const char *name);
bool Melee_Change_fleet (MELEE_STATE *pMS, size_t teamNr,
bool Melee_LocalChange_ship (MELEE_STATE *pMS, COUNT side,
FleetShipIndex index, MeleeShip ship);
bool Melee_LocalChange_teamName (MELEE_STATE *pMS, COUNT side,
const char *name);
bool Melee_LocalChange_fleet (MELEE_STATE *pMS, size_t teamNr,
const MeleeShip *fleet);
bool Melee_Change_team (MELEE_STATE *pMS, size_t teamNr,
bool Melee_LocalChange_team (MELEE_STATE *pMS, size_t teamNr,
const MeleeTeam *team);
void Melee_bootstrapSyncTeam (MELEE_STATE *pMS, size_t teamNr);
void Melee_RemoteChange_ship (MELEE_STATE *pMS, NetConnection *conn,
COUNT side, FleetShipIndex index, MeleeShip ship);
void Melee_RemoteChange_teamName (MELEE_STATE *pMS, NetConnection *conn,
+96 -20
View File
@@ -34,6 +34,8 @@ MeleeTeam_init (MeleeTeam *team)
for (slotI = 0; slotI < MELEE_FLEET_SIZE; slotI++)
team->ships[slotI] = MELEE_NONE;
team->name[0] = '\0';
}
void
@@ -158,7 +160,7 @@ MeleeTeam_getTeamName (const MeleeTeam *team)
// Returns true iff the state has actually changed.
void
MeleeTeam_setName (MeleeTeam *team, const UNICODE *name)
MeleeTeam_setName (MeleeTeam *team, const char *name)
{
strncpy (team->name, name, sizeof team->name - 1);
team->name[sizeof team->name - 1] = '\0';
@@ -196,6 +198,26 @@ MeleeTeam_isEqual (const MeleeTeam *team1, const MeleeTeam *team2)
///////////////////////////////////////////////////////////////////////////
#ifdef NETPLAY
static void
MeleeSetup_initSentTeam (MeleeSetup *setup, size_t teamNr)
{
MeleeTeam *team = &setup->sentTeams[teamNr];
FleetShipIndex slotI;
for (slotI = 0; slotI < MELEE_FLEET_SIZE; slotI++)
MeleeTeam_setShip (team, slotI, MELEE_UNSET);
setup->haveSentTeamName[teamNr] = false;
#ifdef DEBUG
// The actual team name should be irrelevant if haveSentTeamName is
// set to false. In a debug build, we set it to invalid, so that
// it is more likely that it will be noticed if it is ever used.
MeleeTeam_setName (team, "<INVALID>");
#endif /* DEBUG */
}
#endif /* NETPLAY */
MeleeSetup *
MeleeSetup_new (void)
{
@@ -209,7 +231,7 @@ MeleeSetup_new (void)
MeleeTeam_init (&result->teams[teamI]);
result->fleetValue[teamI] = 0;
#ifdef NETPLAY
MeleeTeam_init (&result->confirmedTeams[teamI]);
MeleeSetup_initSentTeam (result, teamI);
#endif /* NETPLAY */
}
return result;
@@ -221,6 +243,17 @@ MeleeSetup_delete (MeleeSetup *setup)
HFree (setup);
}
#ifdef NETPLAY
void
MeleeSetup_resetSentTeams (MeleeSetup *setup)
{
size_t teamI;
for (teamI = 0; teamI < NUM_SIDES; teamI++)
MeleeSetup_initSentTeam (setup, teamI);
}
#endif /* NETPLAY */
// Returns true iff the state has actually changed.
bool
MeleeSetup_setShip (MeleeSetup *setup, size_t teamNr, FleetShipIndex slotNr,
@@ -259,10 +292,10 @@ MeleeSetup_getFleet (const MeleeSetup *setup, size_t teamNr)
// Returns true iff the state has actually changed.
bool
MeleeSetup_setTeamName (MeleeSetup *setup, size_t teamNr,
const UNICODE *name)
const char *name)
{
MeleeTeam *team = &setup->teams[teamNr];
const UNICODE *oldName = MeleeTeam_getTeamName (team);
const char *oldName = MeleeTeam_getTeamName (team);
if (strcmp (oldName, name) == 0)
return false;
@@ -271,6 +304,8 @@ MeleeSetup_setTeamName (MeleeSetup *setup, size_t teamNr,
return true;
}
// NB. This function returns a pointer to a static buffer, which is
// overwritten by calls to MeleeSetup_setTeamName().
const char *
MeleeSetup_getTeamName (const MeleeSetup *setup, size_t teamNr)
{
@@ -301,24 +336,31 @@ MeleeSetup_serializeTeam (const MeleeSetup *setup, size_t teamNr,
#ifdef NETPLAY
MeleeShip
MeleeSetup_getConfirmedShip (const MeleeSetup *setup, size_t teamNr,
MeleeSetup_getSentShip (const MeleeSetup *setup, size_t teamNr,
FleetShipIndex slotNr)
{
return MeleeTeam_getShip (&setup->confirmedTeams[teamNr], slotNr);
return MeleeTeam_getShip (&setup->sentTeams[teamNr], slotNr);
}
// Returns NULL if there is no team name set. This is not the same
// as when an empty (zero-length) team name is set.
// NB. This function returns a pointer to a static buffer, which is
// overwritten by calls to MeleeSetup_setSentTeamName().
const char *
MeleeSetup_getConfirmedTeamName (const MeleeSetup *setup, size_t teamNr)
MeleeSetup_getSentTeamName (const MeleeSetup *setup, size_t teamNr)
{
return MeleeTeam_getTeamName (&setup->confirmedTeams[teamNr]);
if (!setup->haveSentTeamName[teamNr])
return NULL;
return MeleeTeam_getTeamName (&setup->sentTeams[teamNr]);
}
// Returns true iff the state has actually changed.
bool
MeleeSetup_setConfirmedShip (MeleeSetup *setup, size_t teamNr,
MeleeSetup_setSentShip (MeleeSetup *setup, size_t teamNr,
FleetShipIndex slotNr, MeleeShip ship)
{
MeleeTeam *team = &setup->confirmedTeams[teamNr];
MeleeTeam *team = &setup->sentTeams[teamNr];
MeleeShip oldShip = MeleeTeam_getShip (team, slotNr);
if (ship == oldShip)
@@ -329,28 +371,62 @@ MeleeSetup_setConfirmedShip (MeleeSetup *setup, size_t teamNr,
}
// Returns true iff the state has actually changed.
// 'name' can be NULL to indicate that no team name set. This is not the same
// as when an empty (zero-length) team name is set.
bool
MeleeSetup_setConfirmedTeamName (MeleeSetup *setup, size_t teamNr,
const UNICODE *name)
MeleeSetup_setSentTeamName (MeleeSetup *setup, size_t teamNr,
const char *name)
{
MeleeTeam *team = &setup->confirmedTeams[teamNr];
const UNICODE *oldName = MeleeTeam_getTeamName (team);
bool haveSentName = setup->haveSentTeamName[teamNr];
if (strcmp (oldName, name) == 0)
return false;
if (name == NULL)
{
if (!haveSentName)
{
// Had not sent a team name, and still haven't.
return false;
}
#ifdef DEBUG
{
// The actual team name should be irrelevant if haveSentTeamName
// is set to false. In a debug build, we set it to invalid, so
// that it is more likely that it will be noticed if it is ever
// used.
MeleeTeam *team = &setup->sentTeams[teamNr];
MeleeTeam_setName (team, "<INVALID>");
}
#endif
}
else
{
MeleeTeam *team;
if (haveSentName)
{
// Have sent a team name. Check whether it has actually changed.
const char *oldName = MeleeTeam_getTeamName (team);
if (strcmp (oldName, name) == 0)
return false; // Team name has not changed.
}
team = &setup->sentTeams[teamNr];
MeleeTeam_setName (team, name);
}
setup->haveSentTeamName[teamNr] = (name != NULL);
MeleeTeam_setName (team, name);
return true;
}
#if 0
bool
MeleeSetup_isTeamConfirmed (MeleeSetup *setup, size_t teamNr)
MeleeSetup_isTeamSent (MeleeSetup *setup, size_t teamNr)
{
MeleeTeam *localTeam = &setup->teams[teamNr];
MeleeTeam *confirmedTeam = &setup->confirmedTeams[teamNr];
MeleeTeam *sentTeam = &setup->sentTeams[teamNr];
return MeleeTeam_isEqual (localTeam, confirmedTeam);
return MeleeTeam_isEqual (localTeam, sentTeam);
}
#endif
+23 -38
View File
@@ -36,47 +36,29 @@ typedef COUNT FleetShipIndex;
struct MeleeTeam
{
MeleeShip ships[MELEE_FLEET_SIZE];
UNICODE name[MAX_TEAM_CHARS + 1 + 24];
char name[MAX_TEAM_CHARS + 1 + 24];
/* The +1 is for the terminating \0; the +24 is in case some
* default name in starcon.txt is unknowingly mangled. */
// XXX: SvdB: Why would it be mangled? Why don't we just reject
// it if it is? Is this so that we have some space
// for multibyte UTF-8 chars?
};
#endif /* MELEETEAM_INTERNAL */
#ifdef MELEESETUP_INTERNAL
// When Netplay is enabled, we keep two copies of the teams: the team as we
// consider it to be locally, and last confirmed team.
// There are no separate change and confirmation messages; a confirmation
// message is a message reporting a change to the value which was specified
// by the remote side.
// When a local change is made, the current team is updated, and a message
// is sent to the other side.
// When we receive a message of a remote update:
// - if the current value is the same as the received value, we change
// the confirmed value to the current/received value
// - if the current value is different from the received value, and
// the current value is the same as the confirmed value, we change both
// the current value and the confirmed value to the received value,
// and sent a message to the remote side of our modification.
// - if the current value is different from the received value, and
// the current value is not the same as the confirmed value, our
// action depends on who "owns" the value:
// - if the change is to the remote fleet, we change the current and
// confirmed value to the received value, and send a message to the
// remote side of our modification (as above)
// - if the change is to the local fleet, we take no action.
// (In this situation, a local change has been made, and a message of
// this has already been sent to the other side, and a confirmation
// from the other side will arrive eventually.)
// XXX: put this in docs/netplay/protocols.
// XXX: this not only works for teams, but also for other properties.
struct MeleeSetup
{
MeleeTeam teams[NUM_SIDES];
COUNT fleetValue[NUM_SIDES];
#ifdef NETPLAY
MeleeTeam confirmedTeams[NUM_SIDES];
// The least team which both sides agreed upon.
MeleeTeam sentTeams[NUM_SIDES];
// The last sent (parts of) teams.
// Used in the Update protocol. See doc/devel/netplay/protocol
// XXX: this may actually be deallocated when the battle starts.
bool haveSentTeamName[NUM_SIDES];
// Whether we have sent a team name this 'turn'.
// Used in the Update protocol. See doc/devel/netplay/protocol
// (also for the term 'turn').
#endif
};
@@ -88,6 +70,9 @@ void MeleeTeam_init (MeleeTeam *team);
void MeleeTeam_uninit (MeleeTeam *team);
MeleeTeam *MeleeTeam_new (void);
void MeleeTeam_delete (MeleeTeam *team);
#ifdef NETPLAY
void MeleeSetup_resetSentTeams (MeleeSetup *setup);
#endif /* NETPLAY */
int MeleeTeam_serialize (const MeleeTeam *team, uio_Stream *stream);
int MeleeTeam_deserialize (MeleeTeam *team, uio_Stream *stream);
COUNT MeleeTeam_getValue (const MeleeTeam *team);
@@ -96,23 +81,23 @@ void MeleeTeam_setShip (MeleeTeam *team, FleetShipIndex slotNr,
MeleeShip ship);
const MeleeShip *MeleeTeam_getFleet (const MeleeTeam *team);
const char *MeleeTeam_getTeamName (const MeleeTeam *team);
void MeleeTeam_setName (MeleeTeam *team, const UNICODE *name);
void MeleeTeam_setName (MeleeTeam *team, const char *name);
void MeleeTeam_copy (MeleeTeam *copy, const MeleeTeam *original);
#if 0
bool MeleeTeam_isEqual (const MeleeTeam *team1, const MeleeTeam *team2);
#endif
#ifdef NETPLAY
MeleeShip MeleeSetup_getConfirmedShip (const MeleeSetup *setup, size_t teamNr,
MeleeShip MeleeSetup_getSentShip (const MeleeSetup *setup, size_t teamNr,
FleetShipIndex slotNr);
const char *MeleeSetup_getConfirmedTeamName (const MeleeSetup *setup,
const char *MeleeSetup_getSentTeamName (const MeleeSetup *setup,
size_t teamNr);
bool MeleeSetup_setConfirmedShip (MeleeSetup *setup, size_t teamNr,
bool MeleeSetup_setSentShip (MeleeSetup *setup, size_t teamNr,
FleetShipIndex slotNr, MeleeShip ship);
bool MeleeSetup_setConfirmedTeamName (MeleeSetup *setup, size_t teamNr,
const UNICODE *name);
bool MeleeSetup_setSentTeamName (MeleeSetup *setup, size_t teamNr,
const char *name);
#if 0
bool MeleeSetup_isTeamConfirmed (MeleeSetup *setup, size_t teamNr);
bool MeleeSetup_isTeamSent (MeleeSetup *setup, size_t teamNr);
#endif
#endif /* NETPLAY */
@@ -127,7 +112,7 @@ bool MeleeSetup_setFleet (MeleeSetup *setup, size_t teamNr,
const MeleeShip *fleet);
const MeleeShip *MeleeSetup_getFleet (const MeleeSetup *setup, size_t teamNr);
bool MeleeSetup_setTeamName (MeleeSetup *setup, size_t teamNr,
const UNICODE *name);
const char *name);
const char *MeleeSetup_getTeamName (const MeleeSetup *setup,
size_t teamNr);
COUNT MeleeSetup_getFleetValue (const MeleeSetup *setup, size_t teamNr);
@@ -142,7 +127,7 @@ void MeleeState_setShip (MELEE_STATE *pMS, size_t teamNr,
void MeleeState_setFleet (MELEE_STATE *pMS, size_t teamNr,
const MeleeShip *fleet);
void MeleeState_setTeamName (MELEE_STATE *pMS, size_t teamNr,
const UNICODE *name);
const char *name);
void MeleeState_setTeam (MELEE_STATE *pMS, size_t teamNr,
const MeleeTeam *team);
+3
View File
@@ -30,7 +30,10 @@ typedef enum MeleeShip {
MELEE_YEHAT,
MELEE_ZOQFOTPIK,
MELEE_UNSET = ((BYTE) ~0) - 1,
// Used with the Update protocol, to register in the sentTeam
MELEE_NONE = (BYTE) ~0
// Empty fleet position.
} MeleeShip;
#define NUM_MELEE_SHIPS (MELEE_ZOQFOTPIK + 1)
@@ -181,8 +181,6 @@ NetConnection_connectedServerCallback(ListenState *listenState,
// Ignore errors; it's not a big deal. In debug mode, a message
// will already have been printed from the function itself.
conn->stateFlags.myTurn = true;
// The "server" may speak first.
conn->stateFlags.discriminant = true;
NetConnection_connected(conn);
@@ -210,8 +208,6 @@ NetConnection_connectedClientCallback(ConnectState *connectState,
// Ignore errors; it's not a big deal. In debug mode, a message
// will already have been printed from the function itself.
conn->stateFlags.myTurn = false;
// The "server" may speak first.
conn->stateFlags.discriminant = false;
NetConnection_connected(conn);
@@ -129,9 +129,6 @@ NetConnection_open(int player, const NetplayPeerOptions *options,
conn->stateData = NULL;
conn->stateFlags.connected = false;
conn->stateFlags.disconnected = false;
conn->stateFlags.myTurn = false;
conn->stateFlags.endingTurn = false;
conn->stateFlags.pendingTurnChange = false;
conn->stateFlags.discriminant = false;
conn->stateFlags.handshake.localOk = false;
conn->stateFlags.handshake.remoteOk = false;
@@ -350,11 +347,6 @@ NetConnection_isConnected(const NetConnection *conn) {
return conn->stateFlags.connected;
}
bool
NetConnection_isMyTurn(const NetConnection *conn) {
return conn->stateFlags.myTurn;
}
int
NetConnection_getPlayerNr(const NetConnection *conn) {
return conn->player;
+2 -12
View File
@@ -104,20 +104,11 @@ typedef struct {
/* This NetConnection has been disconnected. This implies
* !connected. It is only set if the NetConnection was once
* connected, but is no longer. */
bool myTurn;
/* This party is the only one who may send specific packets
* at the moment. */
bool endingTurn;
/* Request to change the turn from/to the other party. */
bool pendingTurnChange;
/* It is our turn and the other party wants our turn,
* but we're not ready to give it up just yet; we will first
* send our pending packets. */
bool discriminant;
/* If it is true here, it is false on the remote side
* of the same connection. It may be used to break ties.
* Unlike myTurn, this one is guaranteed not to change
* during a connection. Undefined while not connected. */
* It is guaranteed not to change during a connection. Undefined
* while not connected. */
HandShakeFlags handshake;
ReadyFlags ready;
ResetFlags reset;
@@ -204,7 +195,6 @@ bool NetConnection_isConnected(const NetConnection *conn);
void NetConnection_doErrorCallback(NetConnection *nd, int err);
bool NetConnection_isMyTurn(const NetConnection *conn);
void NetConnection_setStateData(NetConnection *conn,
NetConnectionStateData *stateData);
NetConnectionStateData *NetConnection_getStateData(const NetConnection *conn);
+7 -34
View File
@@ -84,6 +84,9 @@ NetMelee_connectCallback(NetConnection *conn) {
NetConnection_setStateData(conn, (void *) battleStateData);
NetConnection_setExtra(conn, NULL);
// We have sent no teams yet. Initialize the state accordingly.
MeleeSetup_resetSentTeams (meleeState->meleeSetup);
sendInit(conn);
Netplay_localReady (conn, NetMelee_enterState_inSetup, NULL, false);
}
@@ -119,43 +122,13 @@ NetMelee_enterState_inSetup(NetConnection *conn, void *arg) {
connectedFeedback(conn);
Netplay_NotifyAll_setFleet(meleeState, player);
Netplay_NotifyAll_setTeamName(meleeState, player);
// Send our team to the remote side.
// XXX This only works with 2 players atm.
assert (NUM_PLAYERS == 2);
Melee_bootstrapSyncTeam (meleeState, player);
flushPacketQueues();
(void) arg;
}
// Callback function for when both sides have confirmed that the battle
// has ended.
void
NetMelee_reenterState_inSetup(NetConnection *conn) {
BattleStateData *battleStateData;
struct melee_state *meleeState;
NetConnection_setState(conn, NetState_inSetup);
battleStateData = (BattleStateData *) NetConnection_getStateData(conn);
meleeState = battleStateData->meleeState;
// The player who entered the menu first should send his changes over
// to the other side when the other player enters setup too.
// As myTurn is set when a change is made, and will never be unset
// until the other side makes a change, it can be used to determine
// which side was first. In the case there were no changes made, myTurn
// may be the second player, but in this case it doesn't matter
// who sends what to whom.
if (NetConnection_isMyTurn(conn))
{
size_t side;
for (side = 0; side < NUM_SIDES; side++)
{
Netplay_NotifyAll_setFleet(meleeState, side);
Netplay_NotifyAll_setTeamName(meleeState, side);
}
flushPacketQueues();
}
}
+1 -2
View File
@@ -62,8 +62,7 @@ readyFlagsMeaningful(NetState state) {
state == NetState_interBattle ||
state == NetState_inBattle ||
state == NetState_endingBattle ||
state == NetState_endingBattle2 ||
state == NetState_endMelee;
state == NetState_endingBattle2;
}
+5 -5
View File
@@ -25,15 +25,15 @@
#define NETPLAY_FULL 2
#define NETPLAY_PROTOCOL_VERSION_MAJOR 0
#define NETPLAY_PROTOCOL_VERSION_MINOR 3
#define NETPLAY_PROTOCOL_VERSION_MINOR 4
#define NETPLAY_MIN_UQM_VERSION_MAJOR 0
#define NETPLAY_MIN_UQM_VERSION_MINOR 5
#define NETPLAY_MIN_UQM_VERSION_PATCH 4
#define NETPLAY_MIN_UQM_VERSION_MINOR 6
#define NETPLAY_MIN_UQM_VERSION_PATCH 9
#define NETPLAY_DEBUG
#undef NETPLAY_DEBUG
/* Extra debugging for netplay */
#define NETPLAY_DEBUG_FILE
#undef NETPLAY_DEBUG_FILE
/* Dump extra debugging information to file.
* Implies NETPLAY_DEBUG.*/
#define NETPLAY_STATISTICS
+1
View File
@@ -21,6 +21,7 @@
#include "netplay.h"
#include "port.h"
#include "netsend.h"
#include "netconnection.h"
#include "packet.h"
#include "libs/log.h"
@@ -38,7 +38,6 @@ NetStateData netStateData[] = {
DEFINE_NETSTATEDATA(inBattle),
DEFINE_NETSTATEDATA(endingBattle),
DEFINE_NETSTATEDATA(endingBattle2),
DEFINE_NETSTATEDATA(endMelee),
};
void
@@ -36,7 +36,6 @@ typedef enum {
NetState_inBattle, /* Battle has started */
NetState_endingBattle, /* Both sides are prepared to end */
NetState_endingBattle2, /* Waiting for the final synchronisation */
NetState_endMelee, /* Melee ended; remote is not yet in setup */
} NetState;
#include "types.h"
+19 -29
View File
@@ -29,33 +29,31 @@
#include <string.h>
#define DEFINE_PACKETDATA(name, inTurn) \
#define DEFINE_PACKETDATA(name) \
{ \
/* .len = */ sizeof (Packet_##name), \
/* .handler = */ (PacketHandler) PacketHandler_##name, \
/* .name = */ #name, \
/* .inTurn = */ (inTurn) \
}
PacketTypeData packetTypeData[PACKET_NUM] = {
DEFINE_PACKETDATA(Init, false),
DEFINE_PACKETDATA(Ping, false),
DEFINE_PACKETDATA(Ack, false),
DEFINE_PACKETDATA(EndTurn, false),
DEFINE_PACKETDATA(Ready, false),
DEFINE_PACKETDATA(Fleet, true),
DEFINE_PACKETDATA(TeamName, true),
DEFINE_PACKETDATA(Handshake0, false),
DEFINE_PACKETDATA(Handshake1, false),
DEFINE_PACKETDATA(HandshakeCancel, false),
DEFINE_PACKETDATA(HandshakeCancelAck, false),
DEFINE_PACKETDATA(SeedRandom, false),
DEFINE_PACKETDATA(InputDelay, false),
DEFINE_PACKETDATA(SelectShip, false),
DEFINE_PACKETDATA(BattleInput, false),
DEFINE_PACKETDATA(FrameCount, false),
DEFINE_PACKETDATA(Checksum, false),
DEFINE_PACKETDATA(Abort, false),
DEFINE_PACKETDATA(Reset, false),
DEFINE_PACKETDATA(Init),
DEFINE_PACKETDATA(Ping),
DEFINE_PACKETDATA(Ack),
DEFINE_PACKETDATA(Ready),
DEFINE_PACKETDATA(Fleet),
DEFINE_PACKETDATA(TeamName),
DEFINE_PACKETDATA(Handshake0),
DEFINE_PACKETDATA(Handshake1),
DEFINE_PACKETDATA(HandshakeCancel),
DEFINE_PACKETDATA(HandshakeCancelAck),
DEFINE_PACKETDATA(SeedRandom),
DEFINE_PACKETDATA(InputDelay),
DEFINE_PACKETDATA(SelectShip),
DEFINE_PACKETDATA(BattleInput),
DEFINE_PACKETDATA(FrameCount),
DEFINE_PACKETDATA(Checksum),
DEFINE_PACKETDATA(Abort),
DEFINE_PACKETDATA(Reset),
};
static inline void *
@@ -113,14 +111,6 @@ Packet_Ack_create(uint32 id) {
return packet;
}
Packet_EndTurn *
Packet_EndTurn_create(void) {
Packet_EndTurn *packet =
(Packet_EndTurn *) Packet_create(PACKET_ENDTURN, 0);
return packet;
}
Packet_Ready *
Packet_Ready_create(void) {
Packet_Ready *packet = (Packet_Ready *) Packet_create(PACKET_READY, 0);
-9
View File
@@ -25,7 +25,6 @@ typedef enum PacketType {
PACKET_INIT,
PACKET_PING,
PACKET_ACK,
PACKET_ENDTURN,
PACKET_READY,
PACKET_FLEET,
PACKET_TEAMNAME,
@@ -79,7 +78,6 @@ typedef struct {
size_t len; /* Minimal length of a packet of this type */
PacketHandler handler;
const char *name;
bool inTurn; /* Can only be sent if it's this party's turn. */
} PacketTypeData;
extern PacketTypeData packetTypeData[];
@@ -142,12 +140,6 @@ typedef struct {
uint32 id;
} Packet_Ack;
// Used to ask or confirm a turn change.
typedef struct {
PacketHeader header;
// No contents.
} Packet_EndTurn;
// Used to signal that a party is ready to continue.
typedef struct {
PacketHeader header;
@@ -262,7 +254,6 @@ void Packet_delete(Packet *packet);
Packet_Init *Packet_Init_create(void);
Packet_Ping *Packet_Ping_create(uint32 id);
Packet_Ack *Packet_Ack_create(uint32 id);
Packet_EndTurn *Packet_EndTurn_create(void);
Packet_Ready *Packet_Ready_create(void);
Packet_Handshake0 *Packet_Handshake0_create(void);
Packet_Handshake1 *Packet_Handshake1_create(void);
@@ -142,41 +142,6 @@ PacketHandler_Ack(NetConnection *conn, const Packet_Ack *packet) {
return 0;
}
int
PacketHandler_EndTurn(NetConnection *conn, const Packet_EndTurn *packet) {
if (!testNetState(conn->state > NetState_init &&
!conn->stateFlags.pendingTurnChange, PACKET_ENDTURN))
return -1; // errno is set
if (conn->stateFlags.endingTurn) {
// This was the confirmation we were waiting for.
// NB. A remote request while we had sent a request serves as
// a confirmation.
conn->stateFlags.myTurn = !conn->stateFlags.myTurn;
conn->stateFlags.endingTurn = false;
} else {
// The other party wants to change whose turn it is.
// If it would become the other party's turn, we wait until
// the queue is flushed to actually carry out the turn change,
// and send the confirmation. I we wouldn't do that, and we still
// had some data to send in our own turn, we would end up asking
// for our turn back, and the turn would keep changing without
// any progress being made.
if (conn->stateFlags.myTurn) {
// Schedule the turn change until after the next queue flush.
conn->stateFlags.pendingTurnChange = true;
} else {
conn->stateFlags.myTurn = true;
sendEndTurn(conn);
}
}
(void) packet;
// Its contents is not interesting.
return 0;
}
// Convert the side indication relative to a remote party to
// a local player number.
static inline int
@@ -189,17 +154,6 @@ localSide(NetConnection *conn, NetplaySide side) {
return 1 - conn->player;
}
static bool
checkYourTurn(NetConnection *conn, PacketType type) {
if (conn->stateFlags.myTurn) {
log_add(log_Warning, "Packet of type '%s' received in an "
"inappropriate turn.", packetTypeData[type].name);
errno = EBADMSG;
return false;
}
return true;
}
int
PacketHandler_Ready(NetConnection *conn, const Packet_Ready *packet) {
if (conn->stateFlags.reset.localReset)
@@ -239,11 +193,6 @@ PacketHandler_Fleet(NetConnection *conn, const Packet_Fleet *packet) {
if (!testNetState(conn->state == NetState_inSetup, PACKET_FLEET))
return -1; // errno is set
if (!checkYourTurn(conn, PACKET_FLEET)) {
// errno is set
return -1;
}
player = localSide(conn, (NetplaySide) packet->side);
len = packetLength((const Packet *) packet);
@@ -304,14 +253,9 @@ PacketHandler_TeamName(NetConnection *conn, const Packet_TeamName *packet) {
return -1;
}
if (!testNetState(conn->state == NetState_inSetup, PACKET_TEAMNAME))
if (!testNetState(conn->state == NetState_inSetup, PACKET_FLEET))
return -1; // errno is set
if (!checkYourTurn(conn, PACKET_TEAMNAME)) {
// errno is set
return -1;
}
battleStateData = (BattleStateData *) NetConnection_getStateData(conn);
if (conn->stateFlags.handshake.localOk) {
@@ -503,8 +447,7 @@ PacketHandler_InputDelay(NetConnection *conn,
return -1;
}
if (!testNetState(conn->state == NetState_preBattle,
PACKET_INPUTDELAY))
if (!testNetState(conn->state == NetState_preBattle, PACKET_INPUTDELAY))
return -1; // errno is set
battleStateData = (BattleStateData *) NetConnection_getStateData(conn);
@@ -28,7 +28,6 @@
DECLARE_PACKETHANDLER(Init);
DECLARE_PACKETHANDLER(Ping);
DECLARE_PACKETHANDLER(Ack);
DECLARE_PACKETHANDLER(EndTurn);
DECLARE_PACKETHANDLER(Ready);
DECLARE_PACKETHANDLER(Fleet);
DECLARE_PACKETHANDLER(TeamName);
+3 -62
View File
@@ -47,9 +47,6 @@ PacketQueue_init(PacketQueue *queue) {
queue->size = 0;
queue->first = NULL;
queue->end = &queue->first;
queue->firstUrgent = NULL;
queue->endUrgent = &queue->first;
}
static void
@@ -64,31 +61,23 @@ PacketQueue_deleteLinks(PacketQueueLink *link) {
void
PacketQueue_uninit(PacketQueue *queue) {
PacketQueue_deleteLinks(queue->firstUrgent);
PacketQueue_deleteLinks(queue->first);
}
void
queuePacket(NetConnection *conn, Packet *packet, bool urgent) {
queuePacket(NetConnection *conn, Packet *packet) {
PacketQueue *queue;
PacketQueueLink *link;
assert(NetConnection_isConnected(conn));
assert(!urgent || !packetTypeData[packetType(packet)].inTurn);
// Urgent packets should never stall the connection.
queue = &conn->queue;
link = PacketQueueLink_alloc();
link->packet = packet;
link->next = NULL;
if (urgent) {
*queue->endUrgent = link;
queue->endUrgent = &link->next;
} else {
*queue->end = link;
queue->end = &link->next;
}
*queue->end = link;
queue->end = &link->next;
queue->size++;
// XXX: perhaps check that this queue isn't getting too large?
@@ -124,29 +113,6 @@ flushPacketQueueLinks(NetConnection *conn, PacketQueueLink **first) {
PacketQueue *queue = &conn->queue;
for (link = *first; link != NULL; link = next) {
if (packetTypeData[packetType(link->packet)].inTurn &&
(!conn->stateFlags.myTurn || conn->stateFlags.endingTurn)) {
// This packet requires it to be 'our turn', and it isn't,
// or we've already told the other party we wanted to end our
// turn.
// This should never happen in the urgent queue.
assert(first != &queue->firstUrgent);
if (!conn->stateFlags.myTurn && !conn->stateFlags.endingTurn) {
conn->stateFlags.endingTurn = true;
if (sendEndTurnDirect(conn) == -1) {
// errno is set
*first = link;
return -1;
}
}
*first = link;
errno = EAGAIN;
// We need to wait for the reply to the turn change.
return -1;
}
if (sendPacket(conn, link->packet) == -1) {
// Errno is set.
*first = link;
@@ -170,14 +136,6 @@ flushPacketQueue(NetConnection *conn) {
assert(NetConnection_isConnected(conn));
flushResult = flushPacketQueueLinks(conn, &queue->firstUrgent);
if (queue->firstUrgent == NULL)
queue->endUrgent = &queue->firstUrgent;
if (flushResult == -1) {
// errno is set
return -1;
}
flushResult = flushPacketQueueLinks(conn, &queue->first);
if (queue->first == NULL)
queue->end = &queue->first;
@@ -186,23 +144,6 @@ flushPacketQueue(NetConnection *conn) {
return -1;
}
// If a turn change had been requested by the other side while it was
// our turn, we first sent everything we still had to send in our turn.
// Now that is done, it is the time to actually give up the turn.
if (conn->stateFlags.pendingTurnChange) {
assert(conn->stateFlags.myTurn);
conn->stateFlags.myTurn = false;
conn->stateFlags.pendingTurnChange = false;
// Send the confirmation to the other side:
if (sendEndTurnDirect(conn) == -1) {
// errno is set
return -1;
}
}
return 0;
}
+2 -19
View File
@@ -36,31 +36,14 @@ struct PacketQueue {
size_t size;
PacketQueueLink *first;
PacketQueueLink **end;
PacketQueueLink *firstUrgent;
PacketQueueLink **endUrgent;
// first points to the first entry in the queue
// end points to the location where the next non-urgent message should
// be inserted.
// 'firstUrgent' and 'endUrgent' are analogous to 'first' and 'end'.
// Urgent packets should only be used for packets that may not
// be delayed while we wait for some remote confirmation.
// As such, these messages themselves should not require a state change
// which needs to be remotely confirmed.
// For example, the endTurn message can be sent when we want to change
// which party is allowed to transmit specific packets. That message
// should not be delayed by messages which require that *we* are that
// party, as without the endTurn message, it will never become our turn.
// Also, ping and ack packets should give some indication of the round
// trip time, which they can only do if they aren't delayed by other
// packets.
// end points to the location where the next message should be inserted.
};
void PacketQueue_init(PacketQueue *queue);
void PacketQueue_uninit(PacketQueue *queue);
void queuePacket(NetConnection *conn, Packet *packet, bool urgent);
void queuePacket(NetConnection *conn, Packet *packet);
int flushPacketQueue(NetConnection *conn);
+19 -37
View File
@@ -29,7 +29,7 @@ sendInit(NetConnection *conn) {
Packet_Init *packet;
packet = Packet_Init_create();
queuePacket(conn, (Packet *) packet, false);
queuePacket(conn, (Packet *) packet);
}
void
@@ -37,7 +37,7 @@ sendPing(NetConnection *conn, uint32 id) {
Packet_Ping *packet;
packet = Packet_Ping_create(id);
queuePacket(conn, (Packet *) packet, true);
queuePacket(conn, (Packet *) packet);
}
void
@@ -45,15 +45,7 @@ sendAck(NetConnection *conn, uint32 id) {
Packet_Ack *packet;
packet = Packet_Ack_create(id);
queuePacket(conn, (Packet *) packet, true);
}
void
sendEndTurn(NetConnection *conn) {
Packet_EndTurn *packet;
packet = Packet_EndTurn_create();
queuePacket(conn, (Packet *) packet, true);
queuePacket(conn, (Packet *) packet);
}
void
@@ -61,17 +53,7 @@ sendReady(NetConnection *conn) {
Packet_Ready *packet;
packet = Packet_Ready_create();
queuePacket(conn, (Packet *) packet, false);
}
// Bypass the packet queue.
// Should only be called from the packet queue functions themselves.
int
sendEndTurnDirect(NetConnection *conn) {
Packet_EndTurn *packet;
packet = Packet_EndTurn_create();
return sendPacket(conn, (Packet *) packet);
queuePacket(conn, (Packet *) packet);
}
void
@@ -79,7 +61,7 @@ sendHandshake0(NetConnection *conn) {
Packet_Handshake0 *packet;
packet = Packet_Handshake0_create();
queuePacket(conn, (Packet *) packet, false);
queuePacket(conn, (Packet *) packet);
}
void
@@ -87,7 +69,7 @@ sendHandshake1(NetConnection *conn) {
Packet_Handshake1 *packet;
packet = Packet_Handshake1_create();
queuePacket(conn, (Packet *) packet, false);
queuePacket(conn, (Packet *) packet);
}
void
@@ -95,7 +77,7 @@ sendHandshakeCancel(NetConnection *conn) {
Packet_HandshakeCancel *packet;
packet = Packet_HandshakeCancel_create();
queuePacket(conn, (Packet *) packet, false);
queuePacket(conn, (Packet *) packet);
}
void
@@ -103,7 +85,7 @@ sendHandshakeCancelAck(NetConnection *conn) {
Packet_HandshakeCancelAck *packet;
packet = Packet_HandshakeCancelAck_create();
queuePacket(conn, (Packet *) packet, false);
queuePacket(conn, (Packet *) packet);
}
void
@@ -112,7 +94,7 @@ sendTeamName(NetConnection *conn, NetplaySide side, const char *name,
Packet_TeamName *packet;
packet = Packet_TeamName_create(side, name, len);
queuePacket(conn, (Packet *) packet, false);
queuePacket(conn, (Packet *) packet);
}
void
@@ -128,7 +110,7 @@ sendFleet(NetConnection *conn, NetplaySide side, const MeleeShip *ships,
packet->ships[i].ship = (uint8) ships[i];
}
queuePacket(conn, (Packet *) packet, false);
queuePacket(conn, (Packet *) packet);
}
void
@@ -141,7 +123,7 @@ sendFleetShip(NetConnection *conn, NetplaySide side,
packet->ships[0].index = (uint8) shipIndex;
packet->ships[0].ship = (uint8) ship;
queuePacket(conn, (Packet *) packet, false);
queuePacket(conn, (Packet *) packet);
}
void
@@ -149,7 +131,7 @@ sendSeedRandom(NetConnection *conn, uint32 seed) {
Packet_SeedRandom *packet;
packet = Packet_SeedRandom_create(seed);
queuePacket(conn, (Packet *) packet, false);
queuePacket(conn, (Packet *) packet);
}
void
@@ -157,7 +139,7 @@ sendInputDelay(NetConnection *conn, uint32 delay) {
Packet_InputDelay *packet;
packet = Packet_InputDelay_create(delay);
queuePacket(conn, (Packet *) packet, false);
queuePacket(conn, (Packet *) packet);
}
void
@@ -165,7 +147,7 @@ sendSelectShip(NetConnection *conn, FleetShipIndex index) {
Packet_SelectShip *packet;
packet = Packet_SelectShip_create((uint16) index);
queuePacket(conn, (Packet *) packet, false);
queuePacket(conn, (Packet *) packet);
}
void
@@ -173,7 +155,7 @@ sendBattleInput(NetConnection *conn, BATTLE_INPUT_STATE input) {
Packet_BattleInput *packet;
packet = Packet_BattleInput_create((uint8) input);
queuePacket(conn, (Packet *) packet, false);
queuePacket(conn, (Packet *) packet);
}
void
@@ -181,7 +163,7 @@ sendFrameCount(NetConnection *conn, BattleFrameCounter frameCount) {
Packet_FrameCount *packet;
packet = Packet_FrameCount_create((uint32) frameCount);
queuePacket(conn, (Packet *) packet, false);
queuePacket(conn, (Packet *) packet);
}
#ifdef NETPLAY_CHECKSUM
@@ -191,7 +173,7 @@ sendChecksum(NetConnection *conn, BattleFrameCounter frameNr,
Packet_Checksum *packet;
packet = Packet_Checksum_create((uint32) frameNr, (uint32) checksum);
queuePacket(conn, (Packet *) packet, false);
queuePacket(conn, (Packet *) packet);
}
#endif
@@ -200,7 +182,7 @@ sendAbort(NetConnection *conn, NetplayAbortReason reason) {
Packet_Abort *packet;
packet = Packet_Abort_create((uint16) reason);
queuePacket(conn, (Packet *) packet, false);
queuePacket(conn, (Packet *) packet);
}
void
@@ -208,7 +190,7 @@ sendReset(NetConnection *conn, NetplayResetReason reason) {
Packet_Reset *packet;
packet = Packet_Reset_create((uint16) reason);
queuePacket(conn, (Packet *) packet, false);
queuePacket(conn, (Packet *) packet);
}
@@ -34,9 +34,7 @@
void sendInit(NetConnection *conn);
void sendPing(NetConnection *conn, uint32 id);
void sendAck(NetConnection *conn, uint32 id);
void sendEndTurn(NetConnection *conn);
void sendReady(NetConnection *conn);
int sendEndTurnDirect(NetConnection *conn);
void sendHandshake0(NetConnection *conn);
void sendHandshake1(NetConnection *conn);
void sendHandshakeCancel(NetConnection *conn);
@@ -82,7 +82,6 @@ Netplay_connectionReset(NetConnection *conn, NetplayResetReason reason,
case NetState_inBattle:
case NetState_endingBattle:
case NetState_endingBattle2:
case NetState_endMelee:
resetFeedback(conn, reason, byRemote);
break;
}
+7 -15
View File
@@ -384,15 +384,6 @@ aborted:
return FALSE;
}
#ifdef NETPLAY
static void
endMeleeCallback (NetConnection *conn, void *arg)
{
NetMelee_reenterState_inSetup (conn);
(void) arg;
}
#endif
static COUNT
GetRaceQueueValue (const QUEUE *queue) {
COUNT result;
@@ -661,9 +652,14 @@ MeleeGameOver (void)
// Show the battle result.
for (playerI = 0; playerI < NUM_PLAYERS; playerI++)
DrawPickMeleeFrame (playerI);
UnlockMutex (GraphicsLock);
#ifdef NETPLAY
negotiateReadyConnections(true, NetState_inSetup);
#endif
TimeOut = GetTimeCounter () + (ONE_SECOND * 4);
UnlockMutex (GraphicsLock);
PressState = PulsedInputState.menu[KEY_MENU_SELECT] ||
PulsedInputState.menu[KEY_MENU_CANCEL];
@@ -683,11 +679,6 @@ MeleeGameOver (void)
&& (!(PlayerControl[0] & PlayerControl[1] & PSYTRON_CONTROL)
|| GetTimeCounter () < TimeOut)));
#ifdef NETPLAY
setStateConnections (NetState_endMelee);
localReadyConnections (endMeleeCallback, NULL, true);
#endif
LockMutex (GraphicsLock);
}
@@ -898,6 +889,7 @@ GetInitialMeleeStarShips (HSTARSHIP *result)
return GetMeleeStarShips (playerMask, result);
}
// Get the next ship to use in SuperMelee.
BOOLEAN
GetNextMeleeStarShip (COUNT which_player, HSTARSHIP *result)
{
+3 -3
View File
@@ -121,7 +121,7 @@ readyToEndCallback (NetConnection *conn, void *arg)
* 3. After a player has both sent and received a frame count, the
* simulation continues for each party, until the maximum of both
* frame counts has been achieved.
* 4. The Ready protocol is used to let each side signal that the it has
* 4. The Ready protocol is used to let each side signal that it has
* reached the target frame count.
* 5. The battle ends.
*/
@@ -132,7 +132,7 @@ readyForBattleEndPlayer (NetConnection *conn)
battleStateData = (BattleStateData *) NetConnection_getStateData(conn);
if (NetConnection_getState (conn) == NetState_interBattle ||
NetConnection_getState (conn) == NetState_endMelee)
NetConnection_getState (conn) == NetState_inSetup)
{
// This connection is already ready. The entire synchronisation
// protocol has already been done for this connection.
@@ -161,7 +161,7 @@ readyForBattleEndPlayer (NetConnection *conn)
// Keep the simulation going as long as the target frame count
// hasn't been reached yet. Note that if the connection state is
// NetState_endingBattle, that we haven't yet received the
// NetState_endingBattle, then we haven't yet received the
// remote frame count, so the target frame count may still rise.
if (battleFrameCount < battleStateData->endFrameCount)
return false;
+2 -2
View File
@@ -21,8 +21,8 @@
#define UQM_MAJOR_VERSION_S "0"
#define UQM_MINOR_VERSION 6
#define UQM_MINOR_VERSION_S "6"
#define UQM_PATCH_VERSION 8
#define UQM_PATCH_VERSION_S "8"
#define UQM_PATCH_VERSION 9
#define UQM_PATCH_VERSION_S "9"
#define UQM_EXTRA_VERSION ""
/* The final version is interpreted as:
* printf ("%d.%d.%d%s", UQM_MAJOR_VERSION, UQM_MINOR_VERSION,