forked from 0ad/0ad
# Some initial work on networking, fixing session setup, game startup, and command queueing.
- Fixed outdated / buggy networking code in the GUI scripts. - Finished the API to CNetClient so that it's possible to start a CGame from it. - Some enhancements for debugging networking: Enabled updates while the game is minimized/out-of-focus if it's in a network session. Also reduced the turn length to something slightly more manageable but still unplayable (1 sec versus 3 sec). - Fixed a bug where IssueCommand used to access the order it creates after queueing it, which is bad if the order gets deleted while being queued (e.g. in CNetClient). This was SVN commit r5139.
This commit is contained in:
parent
db189468a9
commit
92578ae553
@ -911,20 +911,7 @@ A large landmass with rivers, forests and coastal fishing grounds.
|
||||
tooltip="Click this button to start a new game with the current settings."
|
||||
>Start!
|
||||
<action on="Press"><![CDATA[
|
||||
var losSetting = getGUIObjectByName("pgSessionSetupLosSetting").selected;
|
||||
var fowEnabled = getGUIObjectByName("pgSessionSetupFoW").checked;
|
||||
if(getGUIObjectByName("pgSessionSetupScreenshotMode").checked)
|
||||
{
|
||||
losSetting = 2;
|
||||
fowEnabled = false;
|
||||
}
|
||||
startMap (
|
||||
getCurrItemValue("pgSessionSetupMapName"),
|
||||
losSetting,
|
||||
fowEnabled,
|
||||
getCurrItemValue("pgSessionSetupGameMode"),
|
||||
getGUIObjectByName("pgSessionSetupScreenshotMode").checked,
|
||||
"pgSessionSetup");
|
||||
launchGame();
|
||||
]]></action>
|
||||
</object>
|
||||
|
||||
|
@ -5,11 +5,20 @@
|
||||
|
||||
// ====================================================================
|
||||
|
||||
function startMap (mapName, losSetting, fogOfWar, gameMode, screenshotMode, openWindow)
|
||||
function launchGame ()
|
||||
{
|
||||
// Starts the map, closing the current window.
|
||||
// mapName: .pmp to load.
|
||||
// openWindow: Window group (usually parent string) of control that called the function. It'll be hidden.
|
||||
// Starts the map, closing the session setup window.
|
||||
|
||||
var mapName = getCurrItemValue("pgSessionSetupMapName");
|
||||
var gameMode = getCurrItemValue("pgSessionSetupGameMode");
|
||||
var screenshotMode = getGUIObjectByName("pgSessionSetupScreenshotMode").checked;
|
||||
var losSetting = getGUIObjectByName("pgSessionSetupLosSetting").selected;
|
||||
var fogOfWar = getGUIObjectByName("pgSessionSetupFoW").checked;
|
||||
if(screenshotMode)
|
||||
{
|
||||
losSetting = 2;
|
||||
fogOfWar = false;
|
||||
}
|
||||
|
||||
// Check whether we have a correct file extension, to avoid crashes
|
||||
var extension = mapName.substring (mapName.length, mapName.length-4);
|
||||
@ -27,11 +36,13 @@ function startMap (mapName, losSetting, fogOfWar, gameMode, screenshotMode, open
|
||||
g_GameAttributes.screenshotMode = screenshotMode;
|
||||
|
||||
// Close setup window
|
||||
closeMainMenuSubWindow (openWindow);
|
||||
closeMainMenuSubWindow ("pgSessionSetup");
|
||||
|
||||
// Display loading screen.
|
||||
startLoadingScreen();
|
||||
|
||||
console.write( "running startGame()" );
|
||||
|
||||
// Begin game session.
|
||||
if (! startGame())
|
||||
{
|
||||
@ -44,6 +55,8 @@ function startMap (mapName, losSetting, fogOfWar, gameMode, screenshotMode, open
|
||||
btCode = new Array("");
|
||||
messageBox(400, 200, "The game could not be started with the given parameters. You probably have entered an invalid map name.", "Error", 0, btCaptions, btCode);
|
||||
}
|
||||
|
||||
console.write( "done running startGame()" );
|
||||
|
||||
// Set starting UI layout.
|
||||
GUIType=rb;
|
||||
|
@ -74,26 +74,17 @@ function initMPClient (mpParentWindow, ipAddress, profileName)
|
||||
// Player Name
|
||||
client.playerName = profileName;
|
||||
|
||||
var success = client.beginConnect (ipAddress);
|
||||
if (!success)
|
||||
{
|
||||
messageBox(400, 200, "Failed to connect to server. Please check the network connection.",
|
||||
"Client Failure", 2, new Array(), new Array());
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
console.write ("Client successfully started to connect to " + ipAddress + ".");
|
||||
}
|
||||
|
||||
client.onClientConnect = function (event)
|
||||
{
|
||||
// Set player slot to new player's name.
|
||||
pushItem ("pgSessionSetupP" + (event.id), event.name);
|
||||
console.write("onClientConnect: name is " + event.name + ", id is " + event.id);
|
||||
if( event.id != 1 )
|
||||
pushItem ("pgSessionSetupP" + (event.id), event.name);
|
||||
}
|
||||
|
||||
client.onConnectComplete = function (event)
|
||||
{
|
||||
console.write("onConnectComplete: " + event.message);
|
||||
if (event.success)
|
||||
{
|
||||
// Switch to Session Setup screen.
|
||||
@ -118,29 +109,34 @@ function initMPClient (mpParentWindow, ipAddress, profileName)
|
||||
|
||||
client.onDisconnect = function (event)
|
||||
{
|
||||
console.write("onDisconnect: " + event.message);
|
||||
messageBox (400, 200, event.message,
|
||||
"Host Disconnected", 2, new Array(), new Array());
|
||||
}
|
||||
|
||||
client.onClientDisconnect = function (event)
|
||||
{
|
||||
console.write("onClientDisconnect: " + event.message);
|
||||
messageBox (400, 200, event.session,
|
||||
"Client " + event.name + "(" + event.id + ") Disconnected", 2, new Array(), new Array());
|
||||
}
|
||||
|
||||
client.onConnect = function (event)
|
||||
{
|
||||
messageBox (400, 200, event.session,
|
||||
"Client " + event.name + "(" + event.id + ") Connected", 2, new Array(), new Array());
|
||||
}
|
||||
|
||||
client.onStartGame = function (event)
|
||||
{
|
||||
// The server has called Start Game!, so we better switch to the session GUI and stuff like that.
|
||||
startMap (
|
||||
getCurrItemValue ("pgSessionSetupMapName"),
|
||||
getGUIObjectByName("pgSessionSetupLosSetting").selected,
|
||||
"pgSessionSetup");
|
||||
launchGame();
|
||||
}
|
||||
|
||||
var success = client.beginConnect (ipAddress);
|
||||
if (!success)
|
||||
{
|
||||
messageBox(400, 200, "Failed to connect to server. Please check the network connection.",
|
||||
"Client Failure", 2, new Array(), new Array());
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
console.write ("Client successfully started to connect to " + ipAddress + ".");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -42,7 +42,7 @@ function openSessionSetup (sessionReturnWindow)
|
||||
// Open the slot.
|
||||
g_GameAttributes.slots[slotNumber-1].assignOpen();
|
||||
|
||||
console.write ("Opened slot " + this.name);
|
||||
//console.write ("Opened slot " + this.name);
|
||||
break;
|
||||
case "Closed":
|
||||
// If "Closed" selected,
|
||||
@ -61,7 +61,7 @@ function openSessionSetup (sessionReturnWindow)
|
||||
// Close the slot.
|
||||
g_GameAttributes.slots[slotNumber-1].assignClosed();
|
||||
|
||||
console.write ("Closed slot " + this.name);
|
||||
//console.write ("Closed slot " + this.name);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
@ -32,6 +32,8 @@ that of Atlas depending on commandline parameters.
|
||||
#include "ps/Hotkey.h"
|
||||
#include "ps/Globals.h"
|
||||
#include "ps/Interact.h"
|
||||
#include "network/Client.h"
|
||||
#include "network/Server.h"
|
||||
#include "network/SessionManager.h"
|
||||
#include "graphics/Camera.h"
|
||||
#include "graphics/GameView.h"
|
||||
@ -175,31 +177,19 @@ static void Frame()
|
||||
debug_assert(TimeSinceLastFrame >= 0.0f);
|
||||
|
||||
// decide if update/render is necessary
|
||||
bool need_render, need_update;
|
||||
if( g_app_minimized )
|
||||
{
|
||||
// TODO: eventually update ought to be re-enabled so the server host
|
||||
// can Alt+Tab out without the match hanging. however, game updates
|
||||
// are currently really slow and disabling them makes debugging nicer.
|
||||
need_update = false;
|
||||
need_render = false;
|
||||
bool need_render = !g_app_minimized;
|
||||
bool need_update = true;
|
||||
|
||||
// inactive; relinquish CPU for a little while
|
||||
// If we are not running a multiplayer game, disable updates when the game is
|
||||
// minimized or out of focus and relinquish the CPU a bit, in order to make
|
||||
// debugging easier.
|
||||
if( !g_NetClient && !g_NetServer && !g_app_has_focus )
|
||||
{
|
||||
need_update = false;
|
||||
// don't use SDL_WaitEvent: don't want the main loop to freeze until app focus is restored
|
||||
SDL_Delay(10);
|
||||
}
|
||||
else if( !g_app_has_focus )
|
||||
{
|
||||
need_update = false; // see above
|
||||
need_render = true;
|
||||
|
||||
SDL_Delay(5); // see above
|
||||
}
|
||||
else // active
|
||||
{
|
||||
need_update = true;
|
||||
need_render = true;
|
||||
}
|
||||
// TODO: throttling: limit update and render frequency to the minimum.
|
||||
// this is mostly relevant for "inactive" state, so that other windows
|
||||
// get enough CPU time, but it's always nice for power+thermal management.
|
||||
|
@ -252,7 +252,7 @@ bool CNetClient::PreGameHandler(CNetMessage *pMsg, CNetSession *pSession)
|
||||
{
|
||||
case NMT_StartGame:
|
||||
{
|
||||
pClient->StartGame();
|
||||
pClient->OnStartGameMessage();
|
||||
HANDLED(pMsg);
|
||||
}
|
||||
case NMT_ClientConnect:
|
||||
@ -425,16 +425,29 @@ void CNetClient::OnClientDisconnect(int sessionID)
|
||||
m_ServerSessions.erase(it);
|
||||
}
|
||||
|
||||
void CNetClient::StartGame()
|
||||
void CNetClient::OnStartGameMessage()
|
||||
{
|
||||
m_pMessageHandler=InGameHandler;
|
||||
m_pGame->StartGame(m_pGameAttributes);
|
||||
|
||||
if (m_OnStartGame.Defined())
|
||||
debug_assert( m_OnStartGame.Defined() );
|
||||
CStartGameEvent evt;
|
||||
m_OnStartGame.DispatchEvent(GetScript(), &evt);
|
||||
}
|
||||
|
||||
int CNetClient::StartGame()
|
||||
{
|
||||
if (m_pGame->StartGame(m_pGameAttributes) != PSRETURN_OK)
|
||||
{
|
||||
CStartGameEvent evt;
|
||||
m_OnStartGame.DispatchEvent(GetScript(), &evt);
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
CPlayer* CNetClient::GetLocalPlayer()
|
||||
{
|
||||
return m_pLocalPlayerSlot->GetPlayer();
|
||||
}
|
||||
|
||||
void CNetClient::NewTurn()
|
||||
|
@ -50,6 +50,7 @@ class CNetClient: public CNetSession, protected CTurnManager, public CJSObject<C
|
||||
|
||||
void OnClientConnect(int sessionID, const CStrW& name);
|
||||
void OnClientDisconnect(int sessionID);
|
||||
void OnStartGameMessage();
|
||||
|
||||
// JS Interface Functions
|
||||
bool JSI_BeginConnect(JSContext *cx, uintN argc, jsval *argv);
|
||||
@ -59,12 +60,16 @@ protected:
|
||||
virtual void NewTurn();
|
||||
virtual void QueueLocalCommand(CNetMessage *pMsg);
|
||||
|
||||
void StartGame();
|
||||
|
||||
public:
|
||||
CNetClient(CGame *pGame, CGameAttributes *pGameAttribs);
|
||||
virtual ~CNetClient();
|
||||
|
||||
// Launch a game through this client
|
||||
int StartGame();
|
||||
|
||||
// Get a pointer to our player
|
||||
CPlayer* GetLocalPlayer();
|
||||
|
||||
static MessageHandler ConnectHandler;
|
||||
|
||||
static MessageHandler BaseHandler; // Common to all connected states
|
||||
|
@ -234,7 +234,7 @@ void CMessageSocket::StartReadHeader()
|
||||
m_pRdBuffer=(u8 *)malloc(m_RdBufferSize);
|
||||
}
|
||||
m_ReadingData=false;
|
||||
//printf("CMessageSocket::StartReadHeader(): Trying to read %u\n", HEADER_LENGTH);
|
||||
printf("CMessageSocket::StartReadHeader(): Trying to read %u\n", HEADER_LENGTH);
|
||||
PS_RESULT res=Read(m_pRdBuffer, HEADER_LENGTH);
|
||||
if (res != PS_OK)
|
||||
{
|
||||
@ -260,7 +260,7 @@ void CMessageSocket::StartReadMessage()
|
||||
m_pRdBuffer=(u8 *)malloc(m_RdBufferSize);
|
||||
}
|
||||
m_ReadingData=true;
|
||||
//printf("CMessageSocket::StartReadMessage(): Got type %d, trying to read %u\n", hdr.m_MsgType, hdr.m_MsgLength);
|
||||
printf("CMessageSocket::StartReadMessage(): Got type %d, trying to read %u\n", hdr.m_MsgType, hdr.m_MsgLength);
|
||||
|
||||
if (hdr.m_MsgLength == 0)
|
||||
{
|
||||
|
@ -65,9 +65,10 @@ CNetServer::CNetServer(CGame *pGame, CGameAttributes *pGameAttribs):
|
||||
m_pGameAttributes->SetPlayerSlotAssignmentCallback(PlayerSlotAssignmentCallback, this);
|
||||
|
||||
m_pGame->GetSimulation()->SetTurnManager(this);
|
||||
// Set an incredibly long turn length - less command batch spam that way
|
||||
|
||||
// Set an incredibly long turn length for debugging - less command batch spam that way
|
||||
for (int i=0;i<3;i++)
|
||||
CTurnManager::SetTurnLength(i, 3000);
|
||||
CTurnManager::SetTurnLength(i, 1000);
|
||||
|
||||
g_ScriptingHost.SetGlobal("g_NetServer", OBJECT_TO_JSVAL(GetScript()));
|
||||
}
|
||||
@ -348,7 +349,9 @@ int CNetServer::StartGame()
|
||||
Broadcast(new CStartGame());
|
||||
|
||||
if (m_pGame->StartGame(m_pGameAttributes) != PSRETURN_OK)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
CTurnManager::Initialize(m_pGameAttributes->GetSlotCount());
|
||||
|
@ -277,7 +277,7 @@ PS_RESULT CSocketBase::Initialize(ESocketProtocol proto)
|
||||
g_SocketSetInternal.m_NumSockets++;
|
||||
GLOBAL_UNLOCK();
|
||||
|
||||
SetNonBlocking(true);
|
||||
SetNonBlocking(m_NonBlocking);
|
||||
|
||||
return PS_OK;
|
||||
}
|
||||
|
@ -180,7 +180,7 @@ PSRETURN CGame::StartGame(CGameAttributes *pAttribs)
|
||||
if (g_NetClient)
|
||||
{
|
||||
// TODO
|
||||
//m_pLocalPlayer=g_NetClient->GetLocalPlayer();
|
||||
m_pLocalPlayer = g_NetClient->GetLocalPlayer();
|
||||
debug_assert(m_pLocalPlayer && "Darn it! We weren't assigned to a slot!");
|
||||
}
|
||||
else
|
||||
|
@ -237,17 +237,18 @@ JSBool IssueCommand( JSContext* cx, JSObject*, uint argc, jsval* argv, jsval* rv
|
||||
entities.push_back( (ToNative<CEntity>(argv[0])) ->me);
|
||||
else
|
||||
entities = *EntityCollection::RetrieveSet(cx, JSVAL_TO_OBJECT(argv[0]));
|
||||
|
||||
|
||||
std::map<int, CEntityList> entityStore;
|
||||
|
||||
bool isQueued = ToPrimitive<bool>(argv[1]);
|
||||
|
||||
|
||||
//Destroy old notifiers if we're explicitly being reassigned
|
||||
for ( size_t i=0; i < entities.size(); i++)
|
||||
{
|
||||
if ( entities[i]->entf_get(ENTF_DESTROY_NOTIFIERS))
|
||||
entities[i]->DestroyAllNotifiers();
|
||||
}
|
||||
|
||||
std::vector<CNetMessage*> messages;
|
||||
|
||||
//Generate messages for formations
|
||||
@ -281,9 +282,9 @@ JSBool IssueCommand( JSContext* cx, JSObject*, uint argc, jsval* argv, jsval* rv
|
||||
|
||||
for ( std::vector<CNetMessage*>::iterator it=messages.begin(); it != messages.end(); it++ )
|
||||
{
|
||||
//g_Console->InsertMessage(L"IssueCommand: %hs", (*it)->GetString().c_str());
|
||||
g_Game->GetSimulation()->QueueLocalCommand(*it);
|
||||
g_Console->InsertMessage(L"IssueCommand: %hs", (*it)->GetString().c_str());
|
||||
*rval = g_ScriptingHost.UCStringToValue((*it)->GetString());
|
||||
g_Game->GetSimulation()->QueueLocalCommand(*it);
|
||||
}
|
||||
|
||||
return JS_TRUE;
|
||||
@ -728,11 +729,14 @@ JSBool StartGame(JSContext* cx, JSObject*, uint argc, jsval* argv, jsval* rval)
|
||||
*rval = BOOLEAN_TO_JSVAL(JS_TRUE);
|
||||
|
||||
// Hosted MP Game
|
||||
if (g_NetServer)
|
||||
if (g_NetServer)
|
||||
{
|
||||
*rval = BOOLEAN_TO_JSVAL(g_NetServer->StartGame() == 0);
|
||||
// Joined MP Game: StartGame is invalid - do nothing
|
||||
}
|
||||
// Joined MP Game
|
||||
else if (g_NetClient)
|
||||
{
|
||||
*rval = BOOLEAN_TO_JSVAL(g_NetClient->StartGame() == 0);
|
||||
}
|
||||
// Start an SP Game Session
|
||||
else if (!g_Game)
|
||||
@ -750,6 +754,10 @@ JSBool StartGame(JSContext* cx, JSObject*, uint argc, jsval* argv, jsval* rval)
|
||||
return( JS_TRUE );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
*rval = BOOLEAN_TO_JSVAL(JS_FALSE);
|
||||
}
|
||||
|
||||
return( JS_TRUE );
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user