Optionally allow observers to rejoin a game when they weren't here during the game setup.

Patch by elexis, fixes #3242.

This was SVN commit r16945.
This commit is contained in:
Nicolas Auvray 2015-08-28 20:20:10 +00:00
parent 8e70140ec2
commit e56dddbefb
6 changed files with 73 additions and 18 deletions

View File

@ -6,8 +6,9 @@ function getDisconnectReason(id)
case 0: return translate("Unknown reason");
case 1: return translate("Unexpected shutdown");
case 2: return translate("Incorrect network protocol version");
case 3: return translate("Game has already started");
default: return sprintf(translate("\\[Invalid value %(id)s]"), { id: id });
case 3: return translate("Game is loading, please try later");
case 4: return translate("Game has already started, no observers allowed");
default: return sprintf(translate("\\[Invalid value %(id)s]"), { "id": id });
}
}

View File

@ -154,6 +154,20 @@ function initMain()
mapFilters.list_data = getFilterIds();
g_GameAttributes.mapFilter = "default";
// For singleplayer reduce the size of more options dialog by three options (cheats, rated game, observer late join = 90px)
if (!g_IsNetworked)
{
Engine.GetGUIObjectByName("moreOptions").size = "50%-200 50%-195 50%+200 50%+160";
Engine.GetGUIObjectByName("hideMoreOptions").size = "50%-70 310 50%+70 336";
}
// For non-lobby multiplayergames reduce the size of the dialog by one option (rated game, 30px)
else if (g_IsNetworked && !Engine.HasXmppClient())
{
Engine.GetGUIObjectByName("moreOptions").size = "50%-200 50%-195 50%+200 50%+220";
Engine.GetGUIObjectByName("hideMoreOptions").size = "50%-70 370 50%+70 396";
Engine.GetGUIObjectByName("optionObserverLateJoin").size = "14 338 94% 366";
}
// Setup controls for host only
if (g_IsController)
{
@ -255,6 +269,11 @@ function initMain()
updateGameAttributes();
};
Engine.GetGUIObjectByName("observerLateJoin").onPress = function() {
g_GameAttributes.settings.ObserverLateJoin = this.checked;
updateGameAttributes();
};
Engine.GetGUIObjectByName("disableTreasures").onPress = function() {
g_GameAttributes.settings.DisableTreasures = this.checked;
updateGameAttributes();
@ -316,6 +335,7 @@ function initMain()
{
Engine.GetGUIObjectByName("optionCheats").hidden = false;
Engine.GetGUIObjectByName("enableCheats").checked = false;
Engine.GetGUIObjectByName("optionObserverLateJoin").hidden = false;
g_GameAttributes.settings.CheatsEnabled = false;
// Setup ranked option if we are connected to the lobby.
if (Engine.HasXmppClient())
@ -331,6 +351,9 @@ function initMain()
{
Engine.GetGUIObjectByName("enableCheatsText").hidden = true;
Engine.GetGUIObjectByName("enableCheats").hidden = false;
Engine.GetGUIObjectByName("observerLateJoinText").hidden = true;
Engine.GetGUIObjectByName("observerLateJoin").hidden = false;
if (Engine.HasXmppClient())
{
Engine.GetGUIObjectByName("enableRatingText").hidden = true;
@ -1188,10 +1211,12 @@ function onGameAttributesChange()
var populationCap = Engine.GetGUIObjectByName("populationCap");
var startingResources = Engine.GetGUIObjectByName("startingResources");
var ceasefire = Engine.GetGUIObjectByName("ceasefire");
var observerLateJoin = Engine.GetGUIObjectByName("observerLateJoin");
var numPlayersText= Engine.GetGUIObjectByName("numPlayersText");
var mapSizeDesc = Engine.GetGUIObjectByName("mapSizeDesc");
var mapSizeText = Engine.GetGUIObjectByName("mapSizeText");
var observerLateJoinText = Engine.GetGUIObjectByName("observerLateJoinText");
var revealMapText = Engine.GetGUIObjectByName("revealMapText");
var exploreMapText = Engine.GetGUIObjectByName("exploreMapText");
var disableTreasuresText = Engine.GetGUIObjectByName("disableTreasuresText");
@ -1222,6 +1247,10 @@ function onGameAttributesChange()
}
else
enableRatingText.caption = "Unknown";
observerLateJoin.checked = g_GameAttributes.settings.ObserverLateJoin;
observerLateJoinText.caption = observerLateJoin.checked ? translate("Yes") : translate("No");
gameSpeedText.caption = g_GameSpeeds.names[speedIdx];
gameSpeedBox.selected = speedIdx;
populationCap.selected = (mapSettings.PopulationCap !== undefined && POPULATION_CAP_DATA.indexOf(mapSettings.PopulationCap) != -1 ? POPULATION_CAP_DATA.indexOf(mapSettings.PopulationCap) : POPULATION_CAP_DEFAULTIDX);

View File

@ -270,7 +270,7 @@
<!-- More Options -->
<object hidden="true" name="moreOptionsFade" type="image" z="60" sprite="ModernFade"/>
<object name="moreOptions" type="image" sprite="ModernDialog" size="50%-200 50%-195 50%+200 50%+220" z="70" hidden="true">
<object name="moreOptions" type="image" sprite="ModernDialog" size="50%-200 50%-195 50%+200 50%+250" z="70" hidden="true">
<object style="ModernLabelText" type="text" size="50%-128 -18 50%+128 14">
<translatableAttribute id="caption">More Options</translatableAttribute>
</object>
@ -385,12 +385,22 @@
</object>
</object>
<object name="optionObserverLateJoin" size="14 368 94% 396" hidden="true">
<object size="0 0 40% 28" type="text" hidden="false" style="ModernRightLabelText">
<translatableAttribute id="caption">Late Observer Joins:</translatableAttribute>
</object>
<object name="observerLateJoinText" size="40% 0 100% 28" type="text" style="ModernLeftLabelText"/>
<object name="observerLateJoin" size="40%+10 5 40%+30 100%-5" type="checkbox" style="ModernTickBox" hidden="true" tooltip_style="onscreenToolTip">
<translatableAttribute id="tooltip">Allow observers to join after the game started.</translatableAttribute>
</object>
</object>
<!-- Hide More Options Button -->
<object
name="hideMoreOptions"
type="button"
style="StoneButton"
size="50%-70 370 50%+70 396"
size="50%-70 400 50%+70 426"
tooltip_style="onscreenToolTip"
hotkey="cancel"
>

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2011 Wildfire Games.
/* Copyright (C) 2015 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -62,6 +62,7 @@ enum NetDisconnectReason
NDR_UNKNOWN = 0,
NDR_UNEXPECTED_SHUTDOWN,
NDR_INCORRECT_PROTOCOL_VERSION,
NDR_SERVER_LOADING,
NDR_SERVER_ALREADY_IN_GAME
};

View File

@ -28,7 +28,7 @@
#define PS_PROTOCOL_MAGIC 0x5073013f // 'P', 's', 0x01, '?'
#define PS_PROTOCOL_MAGIC_RESPONSE 0x50630121 // 'P', 'c', 0x01, '!'
#define PS_PROTOCOL_VERSION 0x01010006 // Arbitrary protocol
#define PS_PROTOCOL_VERSION 0x01010007 // Arbitrary protocol
#define PS_DEFAULT_PORT 0x5073 // 'P', 's'
// Defines the list of message types. The order of the list must not change.

View File

@ -789,26 +789,40 @@ bool CNetServerWorker::OnAuthenticate(void* context, CFsmEvent* event)
CNetServerSession* session = (CNetServerSession*)context;
CNetServerWorker& server = session->GetServer();
CAuthenticateMessage* message = (CAuthenticateMessage*)event->GetParamRef();
// Prohibit joins while the game is loading
if (server.m_State == SERVER_STATE_LOADING)
{
LOGMESSAGE("Refused connection while the game is loading");
session->Disconnect(NDR_SERVER_LOADING);
return true;
}
CAuthenticateMessage* message = (CAuthenticateMessage*)event->GetParamRef();
CStrW username = server.DeduplicatePlayerName(SanitisePlayerName(message->m_Name));
bool isRejoining = false;
// Optionally allow observers to join after the game has started
bool observerLateJoin = false;
ScriptInterface& scriptInterface = server.GetScriptInterface();
JSContext* cx = scriptInterface.GetContext();
JSAutoRequest rq(cx);
JS::RootedValue settings(cx);
scriptInterface.GetProperty(server.m_GameAttributes.get(), "settings", &settings);
if (scriptInterface.HasProperty(settings, "ObserverLateJoin"))
scriptInterface.GetProperty(settings, "ObserverLateJoin", observerLateJoin);
// If the game has already started, only allow rejoins
bool isRejoining = false;
if (server.m_State != SERVER_STATE_PREGAME)
{
// isRejoining = true; // uncomment this to test rejoining even if the player wasn't connected previously
// Search for an old disconnected player of the same name
// (TODO: if GUIDs were stable, we should use them instead)
for (PlayerAssignmentMap::iterator it = server.m_PlayerAssignments.begin(); it != server.m_PlayerAssignments.end(); ++it)
{
if (!it->second.m_Enabled && it->second.m_Name == username)
{
isRejoining = true;
break;
}
}
isRejoining =
observerLateJoin ||
std::find_if(
server.m_PlayerAssignments.begin(), server.m_PlayerAssignments.end(),
[&username] (const std::pair<CStr, PlayerAssignment>& pair)
{ return pair.second.m_Enabled && pair.second.m_Name == username; })
!= server.m_PlayerAssignments.end();
// Players who weren't already in the game are not allowed to join now that it's started
if (!isRejoining)