Beispiel #1
0
void CSimulation2::LoadPlayerSettings(bool newPlayers)
{
	JSContext* cx = GetScriptInterface().GetContext();
	JSAutoRequest rq(cx);
	JS::RootedValue global(cx, GetScriptInterface().GetGlobalObject());
	GetScriptInterface().CallFunctionVoid(global, "LoadPlayerSettings", m->m_MapSettings, newPlayers);
}
Beispiel #2
0
void CNetClient::CheckServerConnection()
{
	// Trigger local warnings if the connection to the server is bad.
	// At most once per second.
	std::time_t now = std::time(nullptr);
	if (now <= m_LastConnectionCheck)
		return;

	m_LastConnectionCheck = now;

	JSContext* cx = GetScriptInterface().GetContext();

	// Report if we are losing the connection to the server
	u32 lastReceived = m_Session->GetLastReceivedTime();
	if (lastReceived > NETWORK_WARNING_TIMEOUT)
	{
		JS::RootedValue msg(cx);
		GetScriptInterface().Eval("({ 'type':'netwarn', 'warntype': 'server-timeout' })", &msg);
		GetScriptInterface().SetProperty(msg, "lastReceivedTime", lastReceived);
		PushGuiMessage(msg);
		return;
	}

	// Report if we have a bad ping to the server
	u32 meanRTT = m_Session->GetMeanRTT();
	if (meanRTT > DEFAULT_TURN_LENGTH_MP)
	{
		JS::RootedValue msg(cx);
		GetScriptInterface().Eval("({ 'type':'netwarn', 'warntype': 'server-latency' })", &msg);
		GetScriptInterface().SetProperty(msg, "meanRTT", meanRTT);
		PushGuiMessage(msg);
	}
}
Beispiel #3
0
void CSimulation2::InitGame(JS::HandleValue data)
{
	JSContext* cx = GetScriptInterface().GetContext();
	JSAutoRequest rq(cx);
	JS::RootedValue global(cx, GetScriptInterface().GetGlobalObject());
	GetScriptInterface().CallFunctionVoid(global, "InitGame", data);
}
Beispiel #4
0
void CSimulation2::LoadMapSettings()
{
	// Initialize here instead of in Update()
	GetScriptInterface().CallFunctionVoid(GetScriptInterface().GetGlobalObject(), "LoadMapSettings", m->m_MapSettings);

	if (!m->m_StartupScript.empty())
		GetScriptInterface().LoadScript(L"map startup script", m->m_StartupScript);
}
Beispiel #5
0
void CNetClient::HandleDisconnect(u32 reason)
{
	JSContext* cx = GetScriptInterface().GetContext();
	JSAutoRequest rq(cx);

	JS::RootedValue msg(cx);
	GetScriptInterface().Eval("({'type':'netstatus','status':'disconnected'})", &msg);
	GetScriptInterface().SetProperty(msg, "reason", (int)reason, false);
	PushGuiMessage(msg);

	SAFE_DELETE(m_Session);

	// Update the state immediately to UNCONNECTED (don't bother with FSM transitions since
	// we'd need one for every single state, and we don't need to use per-state actions)
	SetCurrState(NCS_UNCONNECTED);
}
Beispiel #6
0
std::string CNetClient::TestReadGuiMessages()
{
	JSContext* cx = GetScriptInterface().GetContext();
	JSAutoRequest rq(cx);

	std::string r;
	JS::RootedValue msg(cx);
	while (true)
	{
		GuiPoll(&msg);
		if (msg.isUndefined())
			break;
		r += GetScriptInterface().ToString(&msg) + "\n";
	}
	return r;
}
Beispiel #7
0
void CSimulation2::LoadMapSettings()
{
	JSContext* cx = GetScriptInterface().GetContext();
	JSAutoRequest rq(cx);
	
	JS::RootedValue global(cx, GetScriptInterface().GetGlobalObject());
	
	// Initialize here instead of in Update()
	GetScriptInterface().CallFunctionVoid(global, "LoadMapSettings", m->m_MapSettings);

	if (!m->m_StartupScript.empty())
		GetScriptInterface().LoadScript(L"map startup script", m->m_StartupScript);

	// Load the trigger scripts after we have loaded the simulation and the map.
	m->LoadTriggerScripts(m->m_ComponentManager, m->m_MapSettings, &m->m_LoadedScripts);
}
Beispiel #8
0
void CNetClient::LoadFinished()
{
	JSContext* cx = GetScriptInterface().GetContext();
	JSAutoRequest rq(cx);

	if (!m_JoinSyncBuffer.empty())
	{
		// We're rejoining a game, and just finished loading the initial map,
		// so deserialize the saved game state now

		std::string state;
		DecompressZLib(m_JoinSyncBuffer, state, true);

		std::stringstream stream(state);

		u32 turn;
		stream.read((char*)&turn, sizeof(turn));
		turn = to_le32(turn);

		LOGMESSAGE("Rejoining client deserializing state at turn %u\n", turn);

		bool ok = m_Game->GetSimulation2()->DeserializeState(stream);
		ENSURE(ok);

		m_ClientTurnManager->ResetState(turn, turn);

		JS::RootedValue msg(cx);
		GetScriptInterface().Eval("({'type':'netstatus','status':'join_syncing'})", &msg);
		PushGuiMessage(msg);
	}
	else
	{
		// Connecting at the start of a game, so we'll wait for other players to finish loading
		JS::RootedValue msg(cx);
		GetScriptInterface().Eval("({'type':'netstatus','status':'waiting_for_players'})", &msg);
		PushGuiMessage(msg);
	}

	CLoadedGameMessage loaded;
	loaded.m_CurrentTurn = m_ClientTurnManager->GetCurrentTurn();
	SendMessage(&loaded);
}
Beispiel #9
0
void CNetServerWorker::UpdateGameAttributes(JS::MutableHandleValue attrs)
{
	m_GameAttributes.set(m_ScriptInterface->GetJSRuntime(), attrs);

	if (!m_Host)
		return;

	CGameSetupMessage gameSetupMessage(GetScriptInterface());
	gameSetupMessage.m_Data.set(m_GameAttributes.get());
	Broadcast(&gameSetupMessage);
}
Beispiel #10
0
std::string CSimulation2::GetAIData()
{
	ScriptInterface& scriptInterface = GetScriptInterface();
	std::vector<CScriptValRooted> aiData = ICmpAIManager::GetAIs(scriptInterface);
	
	// Build single JSON string with array of AI data
	CScriptValRooted ais;
	if (!scriptInterface.Eval("({})", ais) || !scriptInterface.SetProperty(ais.get(), "AIData", aiData))
		return std::string();
	
	return scriptInterface.StringifyJSON(ais.get());
}
Beispiel #11
0
void CNetServerWorker::OnUserJoin(CNetServerSession* session)
{
	AddPlayer(session->GetGUID(), session->GetUserName());

	CGameSetupMessage gameSetupMessage(GetScriptInterface());
	gameSetupMessage.m_Data = m_GameAttributes.get();
	session->SendMessage(&gameSetupMessage);

	CPlayerAssignmentMessage assignMessage;
	ConstructPlayerAssignmentMessage(assignMessage);
	session->SendMessage(&assignMessage);
}
Beispiel #12
0
std::string CSimulation2::GetAIData()
{
	ScriptInterface& scriptInterface = GetScriptInterface();
	JSContext* cx = scriptInterface.GetContext();
	JSAutoRequest rq(cx);
	JS::RootedValue aiData(cx, ICmpAIManager::GetAIs(scriptInterface));
	
	// Build single JSON string with array of AI data
	JS::RootedValue ais(cx);
	if (!scriptInterface.Eval("({})", &ais) || !scriptInterface.SetProperty(ais, "AIData", aiData))
		return std::string();
	
	return scriptInterface.StringifyJSON(&ais);
}
Beispiel #13
0
void CNetClient::PostPlayerAssignmentsToScript()
{
	JSContext* cx = GetScriptInterface().GetContext();
	JSAutoRequest rq(cx);

	JS::RootedValue msg(cx);
	GetScriptInterface().Eval("({'type':'players', 'hosts':{}})", &msg);

	JS::RootedValue hosts(cx);
	GetScriptInterface().GetProperty(msg, "hosts", &hosts);

	for (PlayerAssignmentMap::iterator it = m_PlayerAssignments.begin(); it != m_PlayerAssignments.end(); ++it)
	{
		JS::RootedValue host(cx);
		GetScriptInterface().Eval("({})", &host);
		GetScriptInterface().SetProperty(host, "name", std::wstring(it->second.m_Name), false);
		GetScriptInterface().SetProperty(host, "player", it->second.m_PlayerID, false);
		GetScriptInterface().SetProperty(host, "status", it->second.m_Status, false);
		GetScriptInterface().SetProperty(hosts, it->first.c_str(), host, false);
	}

	PushGuiMessage(msg);
}
Beispiel #14
0
CNetClient::CNetClient(CGame* game) :
	m_Session(NULL),
	m_UserName(L"anonymous"),
	m_GUID(ps_generate_guid()), m_HostID((u32)-1), m_ClientTurnManager(NULL), m_Game(game),
	m_GameAttributes(game->GetSimulation2()->GetScriptInterface().GetContext()),
	m_LastConnectionCheck(0)
{
	m_Game->SetTurnManager(NULL); // delete the old local turn manager so we don't accidentally use it

	void* context = this;

	JS_AddExtraGCRootsTracer(GetScriptInterface().GetJSRuntime(), CNetClient::Trace, this);

	// Set up transitions for session
	AddTransition(NCS_UNCONNECTED, (uint)NMT_CONNECT_COMPLETE, NCS_CONNECT, (void*)&OnConnect, context);

	AddTransition(NCS_CONNECT, (uint)NMT_SERVER_HANDSHAKE, NCS_HANDSHAKE, (void*)&OnHandshake, context);

	AddTransition(NCS_HANDSHAKE, (uint)NMT_SERVER_HANDSHAKE_RESPONSE, NCS_AUTHENTICATE, (void*)&OnHandshakeResponse, context);

	AddTransition(NCS_AUTHENTICATE, (uint)NMT_AUTHENTICATE_RESULT, NCS_INITIAL_GAMESETUP, (void*)&OnAuthenticate, context);

	AddTransition(NCS_INITIAL_GAMESETUP, (uint)NMT_GAME_SETUP, NCS_PREGAME, (void*)&OnGameSetup, context);

	AddTransition(NCS_PREGAME, (uint)NMT_CHAT, NCS_PREGAME, (void*)&OnChat, context);
	AddTransition(NCS_PREGAME, (uint)NMT_READY, NCS_PREGAME, (void*)&OnReady, context);
	AddTransition(NCS_PREGAME, (uint)NMT_GAME_SETUP, NCS_PREGAME, (void*)&OnGameSetup, context);
	AddTransition(NCS_PREGAME, (uint)NMT_PLAYER_ASSIGNMENT, NCS_PREGAME, (void*)&OnPlayerAssignment, context);
	AddTransition(NCS_PREGAME, (uint)NMT_KICKED, NCS_PREGAME, (void*)&OnKicked, context);
	AddTransition(NCS_PREGAME, (uint)NMT_CLIENT_TIMEOUT, NCS_PREGAME, (void*)&OnClientTimeout, context);
	AddTransition(NCS_PREGAME, (uint)NMT_CLIENT_PERFORMANCE, NCS_PREGAME, (void*)&OnClientPerformance, context);
	AddTransition(NCS_PREGAME, (uint)NMT_GAME_START, NCS_LOADING, (void*)&OnGameStart, context);
	AddTransition(NCS_PREGAME, (uint)NMT_JOIN_SYNC_START, NCS_JOIN_SYNCING, (void*)&OnJoinSyncStart, context);

	AddTransition(NCS_JOIN_SYNCING, (uint)NMT_CHAT, NCS_JOIN_SYNCING, (void*)&OnChat, context);
	AddTransition(NCS_JOIN_SYNCING, (uint)NMT_GAME_SETUP, NCS_JOIN_SYNCING, (void*)&OnGameSetup, context);
	AddTransition(NCS_JOIN_SYNCING, (uint)NMT_PLAYER_ASSIGNMENT, NCS_JOIN_SYNCING, (void*)&OnPlayerAssignment, context);
	AddTransition(NCS_JOIN_SYNCING, (uint)NMT_CLIENT_TIMEOUT, NCS_JOIN_SYNCING, (void*)&OnClientTimeout, context);
	AddTransition(NCS_JOIN_SYNCING, (uint)NMT_CLIENT_PERFORMANCE, NCS_JOIN_SYNCING, (void*)&OnClientPerformance, context);
	AddTransition(NCS_JOIN_SYNCING, (uint)NMT_GAME_START, NCS_JOIN_SYNCING, (void*)&OnGameStart, context);
	AddTransition(NCS_JOIN_SYNCING, (uint)NMT_SIMULATION_COMMAND, NCS_JOIN_SYNCING, (void*)&OnInGame, context);
	AddTransition(NCS_JOIN_SYNCING, (uint)NMT_END_COMMAND_BATCH, NCS_JOIN_SYNCING, (void*)&OnJoinSyncEndCommandBatch, context);
	AddTransition(NCS_JOIN_SYNCING, (uint)NMT_LOADED_GAME, NCS_INGAME, (void*)&OnLoadedGame, context);

	AddTransition(NCS_LOADING, (uint)NMT_CHAT, NCS_LOADING, (void*)&OnChat, context);
	AddTransition(NCS_LOADING, (uint)NMT_GAME_SETUP, NCS_LOADING, (void*)&OnGameSetup, context);
	AddTransition(NCS_LOADING, (uint)NMT_PLAYER_ASSIGNMENT, NCS_LOADING, (void*)&OnPlayerAssignment, context);
	AddTransition(NCS_LOADING, (uint)NMT_CLIENT_TIMEOUT, NCS_LOADING, (void*)&OnClientTimeout, context);
	AddTransition(NCS_LOADING, (uint)NMT_CLIENT_PERFORMANCE, NCS_LOADING, (void*)&OnClientPerformance, context);
	AddTransition(NCS_LOADING, (uint)NMT_LOADED_GAME, NCS_INGAME, (void*)&OnLoadedGame, context);

	AddTransition(NCS_INGAME, (uint)NMT_REJOINED, NCS_INGAME, (void*)&OnRejoined, context);
	AddTransition(NCS_INGAME, (uint)NMT_KICKED, NCS_INGAME, (void*)&OnKicked, context);
	AddTransition(NCS_INGAME, (uint)NMT_CLIENT_TIMEOUT, NCS_INGAME, (void*)&OnClientTimeout, context);
	AddTransition(NCS_INGAME, (uint)NMT_CLIENT_PERFORMANCE, NCS_INGAME, (void*)&OnClientPerformance, context);
	AddTransition(NCS_INGAME, (uint)NMT_CHAT, NCS_INGAME, (void*)&OnChat, context);
	AddTransition(NCS_INGAME, (uint)NMT_GAME_SETUP, NCS_INGAME, (void*)&OnGameSetup, context);
	AddTransition(NCS_INGAME, (uint)NMT_PLAYER_ASSIGNMENT, NCS_INGAME, (void*)&OnPlayerAssignment, context);
	AddTransition(NCS_INGAME, (uint)NMT_SIMULATION_COMMAND, NCS_INGAME, (void*)&OnInGame, context);
	AddTransition(NCS_INGAME, (uint)NMT_SYNC_ERROR, NCS_INGAME, (void*)&OnInGame, context);
	AddTransition(NCS_INGAME, (uint)NMT_END_COMMAND_BATCH, NCS_INGAME, (void*)&OnInGame, context);

	// Set first state
	SetFirstState(NCS_UNCONNECTED);
}
Beispiel #15
0
void CSimulation2::LoadPlayerSettings(bool newPlayers)
{
	GetScriptInterface().CallFunctionVoid(GetScriptInterface().GetGlobalObject(), "LoadPlayerSettings", m->m_MapSettings, newPlayers);
}
Beispiel #16
0
void CSimulation2::InitGame(const CScriptVal& data)
{
	GetScriptInterface().CallFunctionVoid(GetScriptInterface().GetGlobalObject(), "InitGame", data);
}
Beispiel #17
0
void CSimulation2::ReplaceSkirmishGlobals()
{
	GetScriptInterface().CallFunctionVoid(GetScriptInterface().GetGlobalObject(), "ReplaceSkirmishGlobals");
}
Beispiel #18
0
bool CNetServerWorker::RunStep()
{
	// Check for messages from the game thread.
	// (Do as little work as possible while the mutex is held open,
	// to avoid performance problems and deadlocks.)
	
	m_ScriptInterface->GetRuntime()->MaybeIncrementalGC(0.5f);
	
	JSContext* cx = m_ScriptInterface->GetContext();
	JSAutoRequest rq(cx);

	std::vector<std::pair<int, CStr> > newAssignPlayer;
	std::vector<bool> newStartGame;
	std::vector<std::pair<CStr, int> > newPlayerReady;
	std::vector<bool> newPlayerResetReady;
	std::vector<std::string> newGameAttributes;
	std::vector<u32> newTurnLength;

	{
		CScopeLock lock(m_WorkerMutex);

		if (m_Shutdown)
			return false;

		newStartGame.swap(m_StartGameQueue);
		newPlayerReady.swap(m_PlayerReadyQueue);
		newPlayerResetReady.swap(m_PlayerResetReadyQueue);
		newAssignPlayer.swap(m_AssignPlayerQueue);
		newGameAttributes.swap(m_GameAttributesQueue);
		newTurnLength.swap(m_TurnLengthQueue);
	}

	for (size_t i = 0; i < newAssignPlayer.size(); ++i)
		AssignPlayer(newAssignPlayer[i].first, newAssignPlayer[i].second);

	for (size_t i = 0; i < newPlayerReady.size(); ++i)
		SetPlayerReady(newPlayerReady[i].first, newPlayerReady[i].second);

	if (!newPlayerResetReady.empty())
		ClearAllPlayerReady();

	if (!newGameAttributes.empty())
	{
		JS::RootedValue gameAttributesVal(cx);
		GetScriptInterface().ParseJSON(newGameAttributes.back(), &gameAttributesVal);
		UpdateGameAttributes(&gameAttributesVal);
	}

	if (!newTurnLength.empty())
		SetTurnLength(newTurnLength.back());

	// Do StartGame last, so we have the most up-to-date game attributes when we start
	if (!newStartGame.empty())
		StartGame();

	// Perform file transfers
	for (size_t i = 0; i < m_Sessions.size(); ++i)
		m_Sessions[i]->GetFileTransferer().Poll();

	// Process network events:

	ENetEvent event;
	int status = enet_host_service(m_Host, &event, HOST_SERVICE_TIMEOUT);
	if (status < 0)
	{
		LOGERROR("CNetServerWorker: enet_host_service failed (%d)", status);
		// TODO: notify game that the server has shut down
		return false;
	}

	if (status == 0)
	{
		// Reached timeout with no events - try again
		return true;
	}

	// Process the event:

	switch (event.type)
	{
	case ENET_EVENT_TYPE_CONNECT:
	{
		// Report the client address
		char hostname[256] = "(error)";
		enet_address_get_host_ip(&event.peer->address, hostname, ARRAY_SIZE(hostname));
		LOGMESSAGE("Net server: Received connection from %s:%u", hostname, (unsigned int)event.peer->address.port);

		// Set up a session object for this peer

		CNetServerSession* session = new CNetServerSession(*this, event.peer);

		m_Sessions.push_back(session);

		SetupSession(session);

		ENSURE(event.peer->data == NULL);
		event.peer->data = session;

		HandleConnect(session);

		break;
	}

	case ENET_EVENT_TYPE_DISCONNECT:
	{
		// If there is an active session with this peer, then reset and delete it

		CNetServerSession* session = static_cast<CNetServerSession*>(event.peer->data);
		if (session)
		{
			LOGMESSAGE("Net server: Disconnected %s", DebugName(session).c_str());

			// Remove the session first, so we won't send player-update messages to it
			// when updating the FSM
			m_Sessions.erase(remove(m_Sessions.begin(), m_Sessions.end(), session), m_Sessions.end());

			session->Update((uint)NMT_CONNECTION_LOST, NULL);

			delete session;
			event.peer->data = NULL;
		}

		break;
	}

	case ENET_EVENT_TYPE_RECEIVE:
	{
		// If there is an active session with this peer, then process the message

		CNetServerSession* session = static_cast<CNetServerSession*>(event.peer->data);
		if (session)
		{
			// Create message from raw data
			CNetMessage* msg = CNetMessageFactory::CreateMessage(event.packet->data, event.packet->dataLength, GetScriptInterface());
			if (msg)
			{
				LOGMESSAGE("Net server: Received message %s of size %lu from %s", msg->ToString().c_str(), (unsigned long)msg->GetSerializedLength(), DebugName(session).c_str());

				HandleMessageReceive(msg, session);

				delete msg;
			}
		}

		// Done using the packet
		enet_packet_destroy(event.packet);

		break;
	}

	case ENET_EVENT_TYPE_NONE:
		break;
	}

	return true;
}
Beispiel #19
0
CNetClient::~CNetClient()
{
	DestroyConnection();
	JS_RemoveExtraGCRootsTracer(GetScriptInterface().GetJSRuntime(), CNetClient::Trace, this);
}
Beispiel #20
0
void CSimulation2::InitGame(const CScriptVal& data)
{
	CScriptVal ret; // ignored
	GetScriptInterface().CallFunction(GetScriptInterface().GetGlobalObject(), "InitGame", data, ret);
}