1
0
forked from 0ad/0ad

Fix #3386, patch by elexis.

This was SVN commit r16997.
This commit is contained in:
JoshuaJB 2015-09-10 05:30:18 +00:00
parent 00a51404c9
commit 8b437a0b1c
6 changed files with 66 additions and 50 deletions

View File

@ -48,7 +48,11 @@ function init(attribs)
Engine.LobbySetPlayerPresence("available"); Engine.LobbySetPlayerPresence("available");
Engine.SendGetGameList(); Engine.SendGetGameList();
Engine.SendGetBoardList(); Engine.SendGetBoardList();
// When rejoining the lobby after a game, we don't need to process presence changes
Engine.LobbyClearPresenceUpdates();
updatePlayerList(); updatePlayerList();
updateSubject(Engine.LobbyGetRoomSubject()); updateSubject(Engine.LobbyGetRoomSubject());
resetFilters(); resetFilters();
@ -233,7 +237,6 @@ function updatePlayerList()
playersBox.list = nickList; playersBox.list = nickList;
if (playersBox.selected >= playersBox.list.length) if (playersBox.selected >= playersBox.list.length)
playersBox.selected = -1; playersBox.selected = -1;
return [playerList, presenceList, nickList, ratingList];
} }
/** /**
@ -689,53 +692,18 @@ function onTick()
break; break;
case "muc": case "muc":
var nick = message.text; var nick = message.text;
var presence = Engine.LobbyGetPlayerPresence(nick);
var playersBox = Engine.GetGUIObjectByName("playersBox");
var playerList = playersBox.list_name;
var presenceList = playersBox.list_status;
var nickList = playersBox.list;
var ratingList = playersBox.list_rating;
var nickIndex = nickList.indexOf(nick);
switch(message.level) switch(message.level)
{ {
case "join": case "join":
var [name, status, rating] = formatPlayerListEntry(nick, presence, "-");
playerList.push(name);
presenceList.push(status);
nickList.push(nick);
ratingList.push(String(rating));
addChatMessage({ "text": "/special " + sprintf(translate("%(nick)s has joined."), { nick: nick }), "key": g_specialKey }); addChatMessage({ "text": "/special " + sprintf(translate("%(nick)s has joined."), { nick: nick }), "key": g_specialKey });
break; break;
case "leave": case "leave":
if (nickIndex == -1) // Left, but not present (TODO: warn about this?)
break;
playerList.splice(nickIndex, 1);
presenceList.splice(nickIndex, 1);
nickList.splice(nickIndex, 1);
ratingList.splice(nickIndex, 1);
addChatMessage({ "text": "/special " + sprintf(translate("%(nick)s has left."), { nick: nick }), "key": g_specialKey }); addChatMessage({ "text": "/special " + sprintf(translate("%(nick)s has left."), { nick: nick }), "key": g_specialKey });
break; break;
case "nick": case "nick":
if (nickIndex == -1) // Changed nick, but not present (shouldn't ever happen)
break;
if (!isValidNick(message.data))
{
addChatMessage({ "from": "system", "text": sprintf(translate("Invalid nickname: %(nick)s"), { nick: message.data })});
break;
}
var [name, status, rating] = formatPlayerListEntry(message.data, presence, stripColorCodes(ratingList[nickIndex])); // TODO: actually we don't want to change the presence here, so use what was used before
playerList[nickIndex] = name;
// presence stays the same
nickList[nickIndex] = message.data;
addChatMessage({ "text": "/special " + sprintf(translate("%(oldnick)s is now known as %(newnick)s."), { oldnick: nick, newnick: message.data }), "key": g_specialKey }); addChatMessage({ "text": "/special " + sprintf(translate("%(oldnick)s is now known as %(newnick)s."), { oldnick: nick, newnick: message.data }), "key": g_specialKey });
break; break;
case "presence": case "presence":
if (nickIndex == -1) // Changed presence, but not online (shouldn't ever happen)
break;
var [name, status, rating] = formatPlayerListEntry(nick, presence, stripColorCodes(ratingList[nickIndex]));
presenceList[nickIndex] = status;
playerList[nickIndex] = name;
ratingList[nickIndex] = rating;
break; break;
case "subject": case "subject":
updateSubject(message.text); updateSubject(message.text);
@ -744,13 +712,10 @@ function onTick()
warn(sprintf("Unknown message.level '%(msglvl)s'", { msglvl: message.level })); warn(sprintf("Unknown message.level '%(msglvl)s'", { msglvl: message.level }));
break; break;
} }
// Push new data to GUI // We might receive many join/leaves when returning to the lobby from a long game.
playersBox.list_name = playerList; // To improve performance, only update the playerlist GUI when the last update in the current stack is processed
playersBox.list_status = presenceList; if (Engine.LobbyGetMucMessageCount() == 0)
playersBox.list_rating = ratingList; updatePlayerList();
playersBox.list = nickList;
if (playersBox.selected >= playersBox.list.length)
playersBox.selected = -1;
break; break;
case "system": case "system":
switch (message.level) switch (message.level)

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2014 Wildfire Games. /* Copyright (C) 2015 Wildfire Games.
* This file is part of 0 A.D. * This file is part of 0 A.D.
* *
* 0 A.D. is free software: you can redistribute it and/or modify * 0 A.D. is free software: you can redistribute it and/or modify
@ -47,8 +47,9 @@ public:
virtual void GetPresence(const std::string& nickname, std::string& presence) = 0; virtual void GetPresence(const std::string& nickname, std::string& presence) = 0;
virtual void GetRole(const std::string& nickname, std::string& role) = 0; virtual void GetRole(const std::string& nickname, std::string& role) = 0;
virtual void GetSubject(std::string& subject) = 0; virtual void GetSubject(std::string& subject) = 0;
virtual void GUIGetPlayerList(ScriptInterface& scriptInterface, JS::MutableHandleValue ret) = 0; virtual void GUIGetPlayerList(ScriptInterface& scriptInterface, JS::MutableHandleValue ret) = 0;
virtual void ClearPresenceUpdates() = 0;
virtual int GetMucMessageCount() = 0;
virtual void GUIGetGameList(ScriptInterface& scriptInterface, JS::MutableHandleValue ret) = 0; virtual void GUIGetGameList(ScriptInterface& scriptInterface, JS::MutableHandleValue ret) = 0;
virtual void GUIGetBoardList(ScriptInterface& scriptInterface, JS::MutableHandleValue ret) = 0; virtual void GUIGetBoardList(ScriptInterface& scriptInterface, JS::MutableHandleValue ret) = 0;
virtual void GUIGetProfile(ScriptInterface& scriptInterface, JS::MutableHandleValue ret) = 0; virtual void GUIGetProfile(ScriptInterface& scriptInterface, JS::MutableHandleValue ret) = 0;

View File

@ -641,6 +641,33 @@ void XmppClient::PushGuiMessage(XmppClient::GUIMessage message)
m_GuiMessageQueue.push_back(std::move(message)); m_GuiMessageQueue.push_back(std::move(message));
} }
/**
* Clears all presence updates from the message queue.
* Used when rejoining the lobby, since we don't need to handle past presence changes.
*/
void XmppClient::ClearPresenceUpdates()
{
m_GuiMessageQueue.erase(
std::remove_if(m_GuiMessageQueue.begin(), m_GuiMessageQueue.end(),
[](XmppClient::GUIMessage& message)
{
return message.type == L"muc" && message.level == L"presence";
}
), m_GuiMessageQueue.end());
}
/**
* Used in order to update the GUI only once when multiple updates are queued.
*/
int XmppClient::GetMucMessageCount()
{
return std::count_if(m_GuiMessageQueue.begin(), m_GuiMessageQueue.end(),
[](XmppClient::GUIMessage& message)
{
return message.type == L"muc";
});
}
/** /**
* Handle a standard MUC textual message. * Handle a standard MUC textual message.
*/ */

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2014 Wildfire Games. /* Copyright (C) 2015 Wildfire Games.
* This file is part of 0 A.D. * This file is part of 0 A.D.
* *
* 0 A.D. is free software: you can redistribute it and/or modify * 0 A.D. is free software: you can redistribute it and/or modify
@ -20,13 +20,11 @@
#include "IXmppClient.h" #include "IXmppClient.h"
#include "glooxwrapper/glooxwrapper.h"
//game - script
#include <deque> #include <deque>
#include "glooxwrapper/glooxwrapper.h"
#include "scriptinterface/ScriptVal.h" #include "scriptinterface/ScriptVal.h"
//Game - script
class ScriptInterface; class ScriptInterface;
namespace glooxwrapper namespace glooxwrapper
@ -38,18 +36,22 @@ namespace glooxwrapper
class XmppClient : public IXmppClient, public glooxwrapper::ConnectionListener, public glooxwrapper::MUCRoomHandler, public glooxwrapper::IqHandler, public glooxwrapper::RegistrationHandler, public glooxwrapper::MessageHandler class XmppClient : public IXmppClient, public glooxwrapper::ConnectionListener, public glooxwrapper::MUCRoomHandler, public glooxwrapper::IqHandler, public glooxwrapper::RegistrationHandler, public glooxwrapper::MessageHandler
{ {
NONCOPYABLE(XmppClient); NONCOPYABLE(XmppClient);
private: private:
//Components //Components
glooxwrapper::Client* m_client; glooxwrapper::Client* m_client;
glooxwrapper::MUCRoom* m_mucRoom; glooxwrapper::MUCRoom* m_mucRoom;
glooxwrapper::Registration* m_registration; glooxwrapper::Registration* m_registration;
//Account infos //Account infos
std::string m_username; std::string m_username;
std::string m_password; std::string m_password;
std::string m_nick; std::string m_nick;
std::string m_xpartamuppId; std::string m_xpartamuppId;
// State // State
bool m_initialLoadComplete = false; bool m_initialLoadComplete = false;
public: public:
//Basic //Basic
XmppClient(const std::string& sUsername, const std::string& sPassword, const std::string& sRoom, const std::string& sNick, const int historyRequestSize = 0, const bool regOpt = false); XmppClient(const std::string& sUsername, const std::string& sPassword, const std::string& sRoom, const std::string& sNick, const int historyRequestSize = 0, const bool regOpt = false);
@ -80,6 +82,7 @@ public:
void GUIGetGameList(ScriptInterface& scriptInterface, JS::MutableHandleValue ret); void GUIGetGameList(ScriptInterface& scriptInterface, JS::MutableHandleValue ret);
void GUIGetBoardList(ScriptInterface& scriptInterface, JS::MutableHandleValue ret); void GUIGetBoardList(ScriptInterface& scriptInterface, JS::MutableHandleValue ret);
void GUIGetProfile(ScriptInterface& scriptInterface, JS::MutableHandleValue ret); void GUIGetProfile(ScriptInterface& scriptInterface, JS::MutableHandleValue ret);
//Script //Script
ScriptInterface& GetScriptInterface(); ScriptInterface& GetScriptInterface();
@ -122,6 +125,7 @@ protected:
void GetPresenceString(const gloox::Presence::PresenceType p, std::string& presence) const; void GetPresenceString(const gloox::Presence::PresenceType p, std::string& presence) const;
void GetRoleString(const gloox::MUCRoomRole r, std::string& role) const; void GetRoleString(const gloox::MUCRoomRole r, std::string& role) const;
std::string StanzaErrorToString(gloox::StanzaError err); std::string StanzaErrorToString(gloox::StanzaError err);
public: public:
/* Messages */ /* Messages */
struct GUIMessage struct GUIMessage
@ -136,6 +140,8 @@ public:
}; };
void GuiPollMessage(ScriptInterface& scriptInterface, JS::MutableHandleValue ret); void GuiPollMessage(ScriptInterface& scriptInterface, JS::MutableHandleValue ret);
void SendMUCMessage(const std::string& message); void SendMUCMessage(const std::string& message);
void ClearPresenceUpdates();
int GetMucMessageCount();
protected: protected:
void PushGuiMessage(XmppClient::GUIMessage message); void PushGuiMessage(XmppClient::GUIMessage message);
void CreateSimpleMessage(const std::string& type, const std::string& text, const std::string& level = "standard", const std::string& data = ""); void CreateSimpleMessage(const std::string& type, const std::string& text, const std::string& level = "standard", const std::string& data = "");

View File

@ -47,6 +47,8 @@ void JSI_Lobby::RegisterScriptFunctions(ScriptInterface& scriptInterface)
scriptInterface.RegisterFunction<void, &JSI_Lobby::SendUnregisterGame>("SendUnregisterGame"); scriptInterface.RegisterFunction<void, &JSI_Lobby::SendUnregisterGame>("SendUnregisterGame");
scriptInterface.RegisterFunction<void, std::wstring, std::wstring, &JSI_Lobby::SendChangeStateGame>("SendChangeStateGame"); scriptInterface.RegisterFunction<void, std::wstring, std::wstring, &JSI_Lobby::SendChangeStateGame>("SendChangeStateGame");
scriptInterface.RegisterFunction<JS::Value, &JSI_Lobby::GetPlayerList>("GetPlayerList"); scriptInterface.RegisterFunction<JS::Value, &JSI_Lobby::GetPlayerList>("GetPlayerList");
scriptInterface.RegisterFunction<void, &JSI_Lobby::LobbyClearPresenceUpdates>("LobbyClearPresenceUpdates");
scriptInterface.RegisterFunction<int, &JSI_Lobby::LobbyGetMucMessageCount>("LobbyGetMucMessageCount");
scriptInterface.RegisterFunction<JS::Value, &JSI_Lobby::GetGameList>("GetGameList"); scriptInterface.RegisterFunction<JS::Value, &JSI_Lobby::GetGameList>("GetGameList");
scriptInterface.RegisterFunction<JS::Value, &JSI_Lobby::GetBoardList>("GetBoardList"); scriptInterface.RegisterFunction<JS::Value, &JSI_Lobby::GetBoardList>("GetBoardList");
scriptInterface.RegisterFunction<JS::Value, &JSI_Lobby::GetProfile>("GetProfile"); scriptInterface.RegisterFunction<JS::Value, &JSI_Lobby::GetProfile>("GetProfile");
@ -189,6 +191,19 @@ JS::Value JSI_Lobby::GetPlayerList(ScriptInterface::CxPrivate* pCxPrivate)
return playerList; return playerList;
} }
void JSI_Lobby::LobbyClearPresenceUpdates(ScriptInterface::CxPrivate* UNUSED(pCxPrivate))
{
if (!g_XmppClient)
return;
g_XmppClient->ClearPresenceUpdates();
}
int JSI_Lobby::LobbyGetMucMessageCount(ScriptInterface::CxPrivate* UNUSED(pCxPrivate))
{
return g_XmppClient ? g_XmppClient->GetMucMessageCount() : 0;
}
JS::Value JSI_Lobby::GetGameList(ScriptInterface::CxPrivate* pCxPrivate) JS::Value JSI_Lobby::GetGameList(ScriptInterface::CxPrivate* pCxPrivate)
{ {
if (!g_XmppClient) if (!g_XmppClient)

View File

@ -45,6 +45,8 @@ namespace JSI_Lobby
void SendUnregisterGame(ScriptInterface::CxPrivate* pCxPrivate); void SendUnregisterGame(ScriptInterface::CxPrivate* pCxPrivate);
void SendChangeStateGame(ScriptInterface::CxPrivate* pCxPrivate, std::wstring nbp, std::wstring players); void SendChangeStateGame(ScriptInterface::CxPrivate* pCxPrivate, std::wstring nbp, std::wstring players);
JS::Value GetPlayerList(ScriptInterface::CxPrivate* pCxPrivate); JS::Value GetPlayerList(ScriptInterface::CxPrivate* pCxPrivate);
void LobbyClearPresenceUpdates(ScriptInterface::CxPrivate* pCxPrivate);
int LobbyGetMucMessageCount(ScriptInterface::CxPrivate* pCxPrivate);
JS::Value GetGameList(ScriptInterface::CxPrivate* pCxPrivate); JS::Value GetGameList(ScriptInterface::CxPrivate* pCxPrivate);
JS::Value GetBoardList(ScriptInterface::CxPrivate* pCxPrivate); JS::Value GetBoardList(ScriptInterface::CxPrivate* pCxPrivate);
JS::Value GetProfile(ScriptInterface::CxPrivate* pCxPrivate); JS::Value GetProfile(ScriptInterface::CxPrivate* pCxPrivate);