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:
+14
-5
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user