Ticket #1504: 0ad-multiplayer-lobby-v30-06-2012.diff

File 0ad-multiplayer-lobby-v30-06-2012.diff, 68.7 KB (added by Badmadblacksad-, 12 years ago)

improve user interface

  • build/premake/extern_libs4.lua

     
    252252            })
    253253        end,
    254254    },
     255    gloox = {
     256        compile_settings = function()
     257            add_default_include_paths("gloox")
     258        end,
     259        link_settings = function()
     260            add_default_links({
     261                win_names  = { "gloox" },
     262                unix_names = { "gloox" },
     263            })
     264        end,
     265    },
    255266    cxxtest = {
    256267        compile_settings = function()
    257268            add_default_include_paths("cxxtest")
  • build/premake/premake4.lua

     
    486486
    487487
    488488    source_dirs = {
     489    "lobby",
     490    }
     491    extern_libs = {
     492    "spidermonkey",
     493    "gloox",
     494    }
     495    setup_static_lib_project("lobby", source_dirs, extern_libs, {})
     496
     497
     498    source_dirs = {
    489499        "simulation2",
    490500        "simulation2/components",
    491501        "simulation2/helpers",
     
    705715    "libcurl",
    706716
    707717    "valgrind",
     718
     719    "gloox",
    708720}
    709721
    710722if not os.is("windows") and not _OPTIONS["android"] and not os.is("macosx") then
  • source/ps/GameSetup/GameSetup.cpp

     
    9191#include "network/NetServer.h"
    9292#include "network/NetClient.h"
    9393
     94#include "lobby/XmppClient.h"
     95
    9496#include "ps/Pyrogenesis.h" // psSetLogDir
    9597#include "ps/GameSetup/Atlas.h"
    9698#include "ps/GameSetup/GameSetup.h"
     
    653655{
    654656    EndGame();
    655657
     658    SAFE_DELETE(g_XmppClient);
     659
    656660    ShutdownPs(); // Must delete g_GUI before g_ScriptingHost
    657661
    658662    in_reset_handlers();
     
    972976
    973977    ogl_WarnIfError();
    974978
     979  if (args.Has("looping"))
     980  {
     981    InitPs(true, L"page_multiplayerlobby.xml", JSVAL_VOID);
     982    return;
     983  }
     984
    975985    try
    976986    {
    977987        if (!Autostart(args))
  • source/gui/COList.h

     
     1#ifndef INCLUDED_COLIST
     2#define INCLUDED_COLIST
     3
     4//--------------------------------------------------------
     5//  Includes / Compiler directives
     6//--------------------------------------------------------
     7#include "GUI.h"
     8#include "CList.h"
     9
     10//--------------------------------------------------------
     11//  Macros
     12//--------------------------------------------------------
     13
     14//--------------------------------------------------------
     15//  Types
     16//--------------------------------------------------------
     17
     18//--------------------------------------------------------
     19//  Declarations
     20//--------------------------------------------------------
     21
     22struct ObjectDef
     23{
     24  CColor m_TextColor;
     25  CStr m_Id;
     26  int m_Width;
     27  CStrW m_Heading;
     28
     29};
     30
     31/**
     32 *  Todo : add description
     33 *
     34 */
     35class COList : public CList
     36{
     37  GUI_OBJECT(COList)
     38
     39public:
     40    COList();
     41
     42protected:
     43    void SetupText();
     44    void HandleMessage(SGUIMessage &Message);
     45
     46    /**
     47     * Handle the \<item\> tag.
     48     */
     49    virtual bool HandleAdditionalChildren(const XMBElement& child, CXeromyces* pFile);
     50
     51    void DrawList(const int &selected, const CStr& _sprite,
     52                    const CStr& _sprite_selected, const CStr& _textcolor);
     53
     54    virtual CRect GetListRect() const {
     55        return m_CachedActualSize + CRect(0, m_HeadingHeight, 0, 0);
     56
     57                CRect(m_CachedActualSize.left,
     58                                 m_CachedActualSize.top+m_HeadingHeight,
     59                                 m_CachedActualSize.right,
     60                                 m_CachedActualSize.bottom); }
     61
     62    std::vector<ObjectDef> m_ObjectsDefs;
     63
     64private:
     65    float m_HeadingHeight;
     66
     67};
     68
     69#endif // INCLUDED_COLIST
  • source/gui/scripting/ScriptFunctions.cpp

     
    4343#include "ps/UserReport.h"
    4444#include "ps/GameSetup/Atlas.h"
    4545#include "ps/GameSetup/Config.h"
     46#include "ps/ConfigDB.h"
    4647#include "tools/atlas/GameInterface/GameLoop.h"
     48#include "lobby/XmppClient.h"
    4749
    4850#include "simulation2/Simulation2.h"
    4951#include "simulation2/components/ICmpAIManager.h"
     
    556558    g_Game->GetTurnManager()->RewindTimeWarp();
    557559}
    558560
     561/* Begin lobby related functions */
     562
     563void StartXmppClient(void* cbdata, std::string sUsername, std::string sPassword, std::string sRoom, std::string sNick)
     564{
     565    CGUIManager* guiManager = static_cast<CGUIManager*> (cbdata);
     566
     567    ENSURE(!g_XmppClient);
     568
     569    g_XmppClient = new XmppClient(guiManager->GetScriptInterface(), sUsername, sPassword, sRoom, sNick);
     570}
     571
     572void StartRegisterXmppClient(void* cbdata, std::string sUsername, std::string sPassword)
     573{
     574    CGUIManager* guiManager = static_cast<CGUIManager*> (cbdata);
     575
     576    ENSURE(!g_XmppClient);
     577
     578    g_XmppClient = new XmppClient(guiManager->GetScriptInterface(), sUsername, sPassword, "", "", true);
     579}
     580
     581void StopXmppClient(void* UNUSED(cbdata))
     582{
     583    ENSURE(g_XmppClient);
     584    SAFE_DELETE(g_XmppClient);
     585}
     586
     587void ConnectXmppClient(void* UNUSED(cbdata))
     588{
     589    ENSURE(g_XmppClient);
     590    g_XmppClient->connect();
     591}
     592
     593void DisconnectXmppClient(void* UNUSED(cbdata))
     594
     595    ENSURE(g_XmppClient);
     596    g_XmppClient->disconnect();
     597}
     598
     599void RecvXmppClient(void* UNUSED(cbdata))
     600{
     601    if(!g_XmppClient)
     602        return;
     603    g_XmppClient->recv();
     604}
     605
     606void SendGetGameList(void* UNUSED(cbdata))
     607{
     608    if(!g_XmppClient)
     609        return;
     610    g_XmppClient->SendIqGetGameList();
     611}
     612
     613void SendRegisterGame(void* UNUSED(cbdata), CScriptVal data)
     614{
     615    if(!g_XmppClient)
     616        return;
     617    g_XmppClient->SendIqRegisterGame(data);
     618}
     619
     620void SendUnregisterGame(void* UNUSED(cbdata), std::string name)
     621{
     622    if(!g_XmppClient)
     623        return;
     624    g_XmppClient->SendIqUnregisterGame(name);
     625}
     626
     627CScriptVal GetPlayerList(void* UNUSED(cbdata))
     628{
     629    if(!g_XmppClient)
     630        return CScriptVal();
     631
     632    CScriptValRooted playerList = g_XmppClient->GUIGetPlayerList();
     633
     634    return playerList.get();
     635}
     636
     637CScriptVal GetGameList(void* UNUSED(cbdata))
     638{
     639    if(!g_XmppClient)
     640        return CScriptVal();
     641
     642    CScriptValRooted gameList = g_XmppClient->GUIGetGameList();
     643
     644    return gameList.get();
     645}
     646
     647CScriptVal LobbyGuiPollMessage(void* UNUSED(cbdata))
     648{
     649    if(!g_XmppClient)
     650        return CScriptVal();
     651
     652    CScriptValRooted poll = g_XmppClient->GuiPollMessage();
     653
     654    return poll.get();
     655}
     656
     657void LobbySendMessage(void* UNUSED(cbdata), std::string message)
     658{
     659    if(!g_XmppClient)
     660        return;
     661
     662    g_XmppClient->SendMUCMessage(message);
     663}
     664
     665std::string GetDefaultLobbyPlayerUsername(void* UNUSED(cbdata))
     666{
     667    std::string username;
     668    CFG_GET_USER_VAL("lobby.login", String, username);
     669    return username;
     670}
     671
     672std::string GetDefaultLobbyPlayerPassword(void* UNUSED(cbdata))
     673{
     674    std::string password;
     675    CFG_GET_USER_VAL("lobby.password", String, password);
     676    return password;
     677}
     678
     679void SetDefaultLobbyPlayerPair(void * UNUSED(cbdata), std::string username, std::string password)
     680{
     681    g_ConfigDB.CreateValue(CFG_USER, "lobby.login")->m_String = username;
     682    g_ConfigDB.CreateValue(CFG_USER, "lobby.password")->m_String = password;
     683    g_ConfigDB.WriteFile(CFG_USER);
     684}
     685
     686/* End lobby related functions */
     687
    559688void QuickSave(void* UNUSED(cbdata))
    560689{
    561690    g_Game->GetTurnManager()->QuickSave();
     
    648777    scriptInterface.RegisterFunction<void, unsigned int, &EnableTimeWarpRecording>("EnableTimeWarpRecording");
    649778    scriptInterface.RegisterFunction<void, &RewindTimeWarp>("RewindTimeWarp");
    650779    scriptInterface.RegisterFunction<void, bool, &SetBoundingBoxDebugOverlay>("SetBoundingBoxDebugOverlay");
     780
     781    // Lobby functions
     782    scriptInterface.RegisterFunction<void, std::string, std::string, std::string, std::string, &StartXmppClient>("StartXmppClient");
     783    scriptInterface.RegisterFunction<void, std::string, std::string, &StartRegisterXmppClient>("StartRegisterXmppClient");
     784    scriptInterface.RegisterFunction<void, &StopXmppClient>("StopXmppClient");
     785    scriptInterface.RegisterFunction<void, &ConnectXmppClient>("ConnectXmppClient");
     786    scriptInterface.RegisterFunction<void, &DisconnectXmppClient>("DisconnectXmppClient");
     787    scriptInterface.RegisterFunction<void, &RecvXmppClient>("RecvXmppClient");
     788    scriptInterface.RegisterFunction<void, &SendGetGameList>("SendGetGameList");
     789    scriptInterface.RegisterFunction<void, CScriptVal, &SendRegisterGame>("SendRegisterGame");
     790    scriptInterface.RegisterFunction<void, std::string, &SendUnregisterGame>("SendUnregisterGame");
     791    scriptInterface.RegisterFunction<CScriptVal, &GetPlayerList>("GetPlayerList");
     792    scriptInterface.RegisterFunction<CScriptVal, &GetGameList>("GetGameList");
     793    scriptInterface.RegisterFunction<CScriptVal, &LobbyGuiPollMessage>("LobbyGuiPollMessage");
     794    scriptInterface.RegisterFunction<void, std::string, &LobbySendMessage>("LobbySendMessage");
     795    scriptInterface.RegisterFunction<std::string, &GetDefaultLobbyPlayerUsername>("GetDefaultLobbyPlayerUsername");
     796    scriptInterface.RegisterFunction<std::string, &GetDefaultLobbyPlayerPassword>("GetDefaultLobbyPlayerPassword");
     797    scriptInterface.RegisterFunction<void, std::string, std::string, &SetDefaultLobbyPlayerPair>("SetDefaultLobbyPlayerPair");
    651798}
  • source/gui/CList.h

     
    8686     * Sets up text, should be called every time changes has been
    8787     * made that can change the visual.
    8888     */
    89     void SetupText();
     89    virtual void SetupText();
    9090
    9191    /**
    9292     * @see IGUIObject#HandleMessage()
     
    121121
    122122    // Extended drawing interface, this is so that classes built on the this one
    123123    //  can use other sprite names.
    124     void DrawList(const int &selected, const CStr& _sprite,
     124    virtual void DrawList(const int &selected, const CStr& _sprite,
    125125                  const CStr& _sprite_selected, const CStr& _textcolor);
    126126
    127127    // Get the area of the list. This is so that i can easily be changed, like in CDropDown
  • source/gui/CGUI.cpp

     
    3535#include "CRadioButton.h"
    3636#include "CInput.h"
    3737#include "CList.h"
     38#include "COList.h"
    3839#include "CDropDown.h"
    3940#include "CProgressBar.h"
    4041#include "CTooltip.h"
     
    442443    AddObjectType("minimap",        &CMiniMap::ConstructObject);
    443444    AddObjectType("input",          &CInput::ConstructObject);
    444445    AddObjectType("list",           &CList::ConstructObject);
     446    AddObjectType("olist",          &COList::ConstructObject);
    445447    AddObjectType("dropdown",       &CDropDown::ConstructObject);
    446448    AddObjectType("tooltip",        &CTooltip::ConstructObject);
    447449}
  • source/gui/IGUIObject.h

     
    424424     * have any additional children (and this function should never be called).
    425425     */
    426426    virtual bool HandleAdditionalChildren(const XMBElement& UNUSED(child),
    427                                           CXeromyces* UNUSED(pFile)) { return false; }
     427                                            CXeromyces* UNUSED(pFile)) { return false; }
    428428
    429429    /**
    430430     * Cached size, real size m_Size is actually dependent on resolution
  • source/gui/COList.cpp

     
     1#include "COList.h"
     2
     3#include "ps/CLogger.h"
     4
     5COList::COList() : CList(),m_HeadingHeight(30.f)
     6{
     7    AddSetting(GUIST_CGUISpriteInstance,    "sprite_heading");
     8}
     9
     10void COList::SetupText()
     11{
     12    if (!GetGUI())
     13        return;
     14
     15    CGUIList *pList;
     16    GUI<CGUIList>::GetSettingPointer(this, "list_ip", pList);
     17
     18    //ENSURE(m_GeneratedTexts.size()>=1);
     19
     20    m_ItemsYPositions.resize( pList->m_Items.size()+1 );
     21
     22    // Delete all generated texts. Some could probably be saved,
     23    //  but this is easier, and this function will never be called
     24    //  continuously, or even often, so it'll probably be okay.
     25    std::vector<SGUIText*>::iterator it;
     26    for (it=m_GeneratedTexts.begin(); it!=m_GeneratedTexts.end(); ++it)
     27    {
     28        if (*it)
     29            delete *it;
     30    }
     31    m_GeneratedTexts.clear();
     32
     33    CStrW font;
     34    if (GUI<CStrW>::GetSetting(this, "font", font) != PSRETURN_OK || font.empty())
     35        // Use the default if none is specified
     36        // TODO Gee: (2004-08-14) Don't define standard like this. Do it with the default style.
     37        font = L"default";
     38
     39    //CGUIString caption;
     40    bool scrollbar;
     41    //GUI<CGUIString>::GetSetting(this, "caption", caption);
     42    GUI<bool>::GetSetting(this, "scrollbar", scrollbar);
     43
     44    float width = GetListRect().GetWidth();
     45    // remove scrollbar if applicable
     46    if (scrollbar && GetScrollBar(0).GetStyle())
     47        width -= GetScrollBar(0).GetStyle()->m_Width;
     48
     49    float buffer_zone=0.f;
     50    GUI<float>::GetSetting(this, "buffer_zone", buffer_zone);
     51
     52
     53    for (unsigned int c=0; c<m_ObjectsDefs.size(); ++c)
     54    {
     55        SGUIText *text = new SGUIText();
     56        CGUIString gui_string;
     57        gui_string.SetValue(m_ObjectsDefs[c].m_Heading);
     58        *text = GetGUI()->GenerateText(gui_string, font, width, buffer_zone, this);
     59        AddText(text);
     60    }
     61
     62
     63    // Generate texts
     64    float buffered_y = 0.f;
     65
     66    for (int i=0; i<(int)pList->m_Items.size(); ++i)
     67    {
     68        m_ItemsYPositions[i] = buffered_y;
     69        for (unsigned int c=0; c<m_ObjectsDefs.size(); ++c)
     70        {
     71            CGUIList * pList_c;
     72            GUI<CGUIList>::GetSettingPointer(this, m_ObjectsDefs[c].m_Id, pList_c);
     73            SGUIText *text = new SGUIText();
     74            *text = GetGUI()->GenerateText(pList_c->m_Items[i], font, width, buffer_zone, this);
     75            if (c==0)
     76                buffered_y += text->m_Size.cy;
     77            AddText(text);
     78        }
     79    }
     80
     81    m_ItemsYPositions[pList->m_Items.size()] = buffered_y;
     82
     83    //if (! scrollbar)
     84    //  CalculateTextPosition(m_CachedActualSize, m_TextPos, *m_GeneratedTexts[0]);
     85
     86    // Setup scrollbar
     87    if (scrollbar)
     88    {
     89        GetScrollBar(0).SetScrollRange( m_ItemsYPositions.back() );
     90        GetScrollBar(0).SetScrollSpace( GetListRect().GetHeight() );
     91
     92        CRect rect = GetListRect();
     93        GetScrollBar(0).SetX( rect.right );
     94        GetScrollBar(0).SetY( rect.top );
     95        GetScrollBar(0).SetZ( GetBufferedZ() );
     96        GetScrollBar(0).SetLength( rect.bottom - rect.top );
     97    }
     98}
     99
     100void COList::HandleMessage(SGUIMessage &Message)
     101{
     102    CList::HandleMessage(Message);
     103//  switch (Message.type)
     104//  {
     105//  case GUIM_SETTINGS_UPDATED:
     106//      if (Message.value.Find("list_") != -1)
     107//      {
     108//          SetupText();
     109//      }
     110//  }
     111}
     112
     113bool COList::HandleAdditionalChildren(const XMBElement& child, CXeromyces* pFile)
     114{
     115    int elmt_item = pFile->GetElementID("item");
     116    int elmt_heading = pFile->GetElementID("heading");
     117    int elmt_def = pFile->GetElementID("def");
     118
     119    if (child.GetNodeName() == elmt_item)
     120    {
     121        AddItem(child.GetText().FromUTF8(), child.GetText().FromUTF8());
     122        return true;
     123    }
     124    else if (child.GetNodeName() == elmt_heading)
     125    {
     126        CStrW text (child.GetText().FromUTF8());
     127
     128        return true;
     129    }
     130    else if (child.GetNodeName() == elmt_def)
     131    {
     132        ObjectDef oDef;
     133
     134        XMBAttributeList attributes = child.GetAttributes();
     135        for (int i=0; i<attributes.Count; ++i)
     136        {
     137            XMBAttribute attr = attributes.Item(i);
     138            CStr attr_name (pFile->GetAttributeString(attr.Name));
     139            CStr attr_value (attr.Value);
     140
     141            if (attr_name == "color")
     142            {
     143                CColor color;
     144                if (!GUI<CColor>::ParseString(attr_value.FromUTF8(), color))
     145                    LOGERROR(L"GUI: Error parsing '%hs' (\"%ls\")", attr_name.c_str(), attr_value.c_str());
     146                else oDef.m_TextColor = color;
     147            }
     148            else if (attr_name == "id")
     149            {
     150                oDef.m_Id = "list_"+attr_value;
     151            }
     152            else if (attr_name == "width")
     153            {
     154                int width;
     155                if (!GUI<int>::ParseString(attr_value.FromUTF8(), width))
     156                    LOGERROR(L"GUI: Error parsing '%hs' (\"%ls\")", attr_name.c_str(), attr_value.c_str());
     157                else
     158                    oDef.m_Width = width;
     159            }
     160            else if (attr_name == "heading")
     161            {
     162                oDef.m_Heading = attr_value.FromUTF8();
     163            }
     164
     165        }
     166
     167        m_ObjectsDefs.push_back(oDef);
     168
     169        AddSetting(GUIST_CGUIList, oDef.m_Id);
     170        SetupText();
     171
     172        return true;
     173    }
     174    else
     175    {
     176        return false;
     177    }
     178}
     179
     180void COList::DrawList(const int &selected,
     181                     const CStr& _sprite,
     182                     const CStr& _sprite_selected,
     183                     const CStr& _textcolor)
     184{
     185    float bz = GetBufferedZ();
     186
     187    // First call draw on ScrollBarOwner
     188    bool scrollbar;
     189    GUI<bool>::GetSetting(this, "scrollbar", scrollbar);
     190
     191    if (scrollbar)
     192    {
     193        // Draw scrollbar
     194        IGUIScrollBarOwner::Draw();
     195    }
     196
     197    if (GetGUI())
     198    {
     199        CRect rect = GetListRect();
     200
     201        CGUISpriteInstance *sprite=NULL, *sprite_selectarea=NULL;
     202        int cell_id;
     203        GUI<CGUISpriteInstance>::GetSettingPointer(this, _sprite, sprite);
     204        GUI<CGUISpriteInstance>::GetSettingPointer(this, _sprite_selected, sprite_selectarea);
     205        GUI<int>::GetSetting(this, "cell_id", cell_id);
     206
     207        CGUIList *pList;
     208        GUI<CGUIList>::GetSettingPointer(this, "list_name", pList);
     209
     210        GetGUI()->DrawSprite(*sprite, cell_id, bz, rect);
     211
     212        float scroll=0.f;
     213        if (scrollbar)
     214        {
     215            scroll = GetScrollBar(0).GetPos();
     216        }
     217
     218        if (selected != -1)
     219        {
     220            ENSURE(selected >= 0 && selected+1 < (int)m_ItemsYPositions.size());
     221
     222            // Get rectangle of selection:
     223            CRect rect_sel(rect.left, rect.top + m_ItemsYPositions[selected] - scroll,
     224                                 rect.right, rect.top + m_ItemsYPositions[selected+1] - scroll);
     225
     226            if (rect_sel.top <= rect.bottom &&
     227                rect_sel.bottom >= rect.top)
     228            {
     229                if (rect_sel.bottom > rect.bottom)
     230                    rect_sel.bottom = rect.bottom;
     231                if (rect_sel.top < rect.top)
     232                    rect_sel.top = rect.top;
     233
     234                if (scrollbar)
     235                {
     236                    // Remove any overlapping area of the scrollbar.
     237                    if (rect_sel.right > GetScrollBar(0).GetOuterRect().left &&
     238                        rect_sel.right <= GetScrollBar(0).GetOuterRect().right)
     239                        rect_sel.right = GetScrollBar(0).GetOuterRect().left;
     240
     241                    if (rect_sel.left >= GetScrollBar(0).GetOuterRect().left &&
     242                        rect_sel.left < GetScrollBar(0).GetOuterRect().right)
     243                        rect_sel.left = GetScrollBar(0).GetOuterRect().right;
     244                }
     245
     246                GetGUI()->DrawSprite(*sprite_selectarea, cell_id, bz+0.05f, rect_sel);
     247            }
     248        }
     249
     250        CColor color;
     251        GUI<CColor>::GetSetting(this, _textcolor, color);
     252
     253        CGUISpriteInstance *sprite_heading=NULL;
     254        GUI<CGUISpriteInstance>::GetSettingPointer(this, "sprite_heading", sprite_heading);
     255        CRect rect_head(m_CachedActualSize.left, m_CachedActualSize.top, m_CachedActualSize.right,
     256                                        m_CachedActualSize.top + m_HeadingHeight);
     257        GetGUI()->DrawSprite(*sprite_heading, cell_id, bz, rect_head);
     258
     259        float xpos = 0;
     260        for (unsigned int def=0; def< m_ObjectsDefs.size(); ++def)
     261        {
     262            DrawText(def, color, m_CachedActualSize.TopLeft() + CPos(xpos, 4), bz+0.1f, rect_head);
     263            xpos += m_ObjectsDefs[def].m_Width;
     264        }
     265
     266        for (int i=0; i<(int)pList->m_Items.size(); ++i)
     267        {
     268            if (m_ItemsYPositions[i+1] - scroll < 0 ||
     269                m_ItemsYPositions[i] - scroll > rect.GetHeight())
     270                continue;
     271
     272            // Clipping area (we'll have to substract the scrollbar)
     273            CRect cliparea = GetListRect();
     274
     275            if (scrollbar)
     276            {
     277                if (cliparea.right > GetScrollBar(0).GetOuterRect().left &&
     278                    cliparea.right <= GetScrollBar(0).GetOuterRect().right)
     279                    cliparea.right = GetScrollBar(0).GetOuterRect().left;
     280
     281                if (cliparea.left >= GetScrollBar(0).GetOuterRect().left &&
     282                    cliparea.left < GetScrollBar(0).GetOuterRect().right)
     283                    cliparea.left = GetScrollBar(0).GetOuterRect().right;
     284            }
     285
     286            xpos = 0;
     287            for (unsigned int def=0; def< m_ObjectsDefs.size(); ++def)
     288            {
     289                DrawText(m_ObjectsDefs.size() * (i+/*Heading*/1) + def, m_ObjectsDefs[def].m_TextColor, rect.TopLeft() + CPos(xpos, -scroll + m_ItemsYPositions[i]), bz+0.1f, cliparea);
     290                xpos += m_ObjectsDefs[def].m_Width;
     291            }
     292        }
     293    }
     294}
  • source/tools/XpartaMuPP/XpartaMuPP.py

     
     1#!/usr/bin/env python3
     2# -*- coding: utf-8 -*-
     3
     4"""
     5    XpartaMuPP by :
     6    Badmadblacksad
     7    ..
     8    For : 0ad
     9    License : GPL
     10"""
     11
     12import sys
     13import logging
     14import time
     15from optparse import OptionParser
     16
     17import sleekxmpp
     18from sleekxmpp.stanza import Iq
     19from sleekxmpp.stanza import *
     20from sleekxmpp.xmlstream import ElementBase, register_stanza_plugin, ET
     21from sleekxmpp.xmlstream.handler import Callback
     22from sleekxmpp.xmlstream.matcher import StanzaPath
     23
     24from xml.dom.minidom import Document
     25
     26## Configuration ##
     27configDEMOModOn = False
     28## !Configuration ##
     29
     30class BasicGameList(ElementBase):
     31  name = 'query'
     32  namespace = 'jabber:iq:gamelist'
     33  interfaces = set(('game', 'command'))
     34  sub_interfaces = interfaces
     35  plugin_attrib = 'gamelist'
     36
     37  def addGame(self, name, ip, mapName, mapSize, victoryCondition, nbp, tnbp):
     38    itemXml = ET.Element("game", {"name":name, "ip":ip, "nbp":nbp, "tnbp":tnbp, "mapName":mapName, "mapSize":mapSize, "victoryCondition":victoryCondition})
     39    self.xml.append(itemXml)
     40
     41  def getGame(self):
     42    game = self.xml.find('{%s}game' % self.namespace)
     43    return game.get("name"), game.get("ip"), game.get("mapName"), game.get("mapSize"), game.get("victoryCondition"), game.get("nbp"), game.get("tnbp")   
     44
     45  def getCommand(self):
     46    command = self.xml.find('{%s}command' % self.namespace)
     47    return command
     48
     49class XpartaMuPP(sleekxmpp.ClientXMPP):
     50  """
     51  A simple game list provider
     52  """
     53
     54  def __init__(self, sjid, password, room, nick):
     55    sleekxmpp.ClientXMPP.__init__(self, sjid, password)
     56    self.sjid = sjid
     57    self.room = room
     58    self.nick = nick
     59
     60    # Game management
     61    self.m_gameList = {}
     62   
     63    #DEMO
     64    if configDEMOModOn:
     65      self.addGame("666.666.666.666", "Unplayable map", "666.666.666.666", "Serengeti", "128", "gold rush", "4", "4")
     66      self.addGame("666.666.666.667", "Unreachale liberty", "666.666.666.667", "oasis", "256", "conquest", "2", "4")
     67      #for i in range(50):
     68      #  self.addGame("666.666.666."+str(i), "X"+str(i), "666.666.666."+str(i), "Oasis", "large", "conquest", "1", "4")   
     69
     70    register_stanza_plugin(Iq, BasicGameList)
     71    self.register_handler(Callback('Iq Gamelist',
     72                                       StanzaPath('iq/gamelist'),
     73                                       self.iqhandler,
     74                                       instream=True))
     75
     76    self.add_event_handler("session_start", self.start)
     77    self.add_event_handler("message", self.message)
     78    self.add_event_handler("muc::%s::got_online" % self.room, self.muc_online)
     79    self.add_event_handler("muc::%s::got_offline" % self.room, self.muc_offline)
     80
     81  def start(self, event):
     82    """
     83    Process the session_start event
     84    """
     85    self.plugin['xep_0045'].joinMUC(self.room, self.nick)
     86
     87    self.send_presence()
     88    self.get_roster()
     89    logging.info("xpartamupp started")
     90
     91    #DEMO
     92    self.DEMOrequestGameList()
     93    #self.DEMOregisterGame()
     94
     95  def message(self, msg):
     96    """
     97    Process incoming message stanzas
     98    """
     99    if msg['type'] == 'chat':
     100      msg.reply("Thanks for sending\n%(body)s" % msg).send()
     101      logging.comm("receive message"+msg['body'])
     102
     103  def muc_online(self, presence):
     104    """
     105    Process presence stanza from a chat room.
     106    """
     107    if presence['muc']['nick'] != self.nick:
     108      self.send_message(mto=presence['from'], mbody="Hello %s, welcome in the 0ad alpha chatroom. Polishes your weapons and get ready to fight!" %(presence['muc']['nick']), mtype='')
     109
     110  def muc_offline(self, presence):
     111    """
     112    Process presence stanza from a chat room.
     113    """
     114    if presence['muc']['nick'] != self.nick:
     115      self.removeGame(presence['muc']['jid'].bare)
     116
     117  def iqhandler(self, iq):
     118    """
     119    Handle the custom <gamelist> stanza
     120    TODO: This method should be very robust because
     121    we could receive anything
     122    """
     123    if iq['type'] == 'error':
     124      logging.error('iqhandler error' + iq['error']['condition'])
     125      #self.disconnect()
     126    elif iq['type'] == 'get':
     127      """
     128      Request a gamelist
     129      """
     130      self.sendGameList(iq['from'])
     131    elif iq['type'] == 'result':
     132      """
     133      Iq successfully received
     134      """
     135      pass
     136    elif iq['type'] == 'set':
     137      """
     138      Register-update / unregister a game
     139      """
     140      command = iq['gamelist']['command'].text
     141      if command == 'register':
     142        try:
     143          name, ip, mapName, mapSize, victoryCondition, nbp, tnbp = iq['gamelist']['game']
     144          logging.debug("ip " + ip)
     145          self.addGame(iq['from'].bare,name,ip,mapName,mapSize,victoryCondition,nbp,tnbp)
     146        except:
     147          logging.error("Failed to process game data")
     148      elif command == 'unregister':
     149        self.removeGame(iq['from'].bare)
     150
     151  def sendGameList(self, to):
     152    """
     153    Send a massive stanza with the whole game list
     154    """
     155    stz = BasicGameList()
     156    for k in self.m_gameList:
     157      g = self.m_gameList[k]
     158      stz.addGame(g['name'], g['ip'], g['mapName'], g['mapSize'], g['victoryCondition'], g['nbp'], g['tnbp'])
     159    iq = self.Iq()
     160    iq['type'] = 'result'
     161    iq['to'] = to
     162    iq.setPayload(stz)
     163    try:
     164      iq.send()
     165    except:
     166      logging.error("Failed to send game list")
     167
     168  def DEMOrequestGameList(self):
     169    """
     170    Test function
     171    """
     172    iq = self.Iq()
     173    iq['type'] = 'get'
     174    iq['gamelist']['field'] = 'x'
     175    iq['to'] = self.boundjid.full
     176    iq.send(now=True, block=False)
     177    return True
     178
     179  def DEMOregisterGame(self):
     180    """
     181    Test function
     182    """
     183    stz = BasicGameList()
     184    stz.addGame("DEMOregister","DEMOip","DEMOmap","","","","")
     185    stz['command'] = 'register'
     186    iq = self.Iq()
     187    iq['type'] = 'set'
     188    iq['to'] = self.boundjid.full
     189    iq.setPayload(stz)
     190    iq.send(now=True, block=False)
     191    return True
     192
     193  # Game management
     194
     195  def addGame(self, sid, name, ip, mapName, mapSize, victoryCondition, nbp, tnbp):
     196    game = { 'name':name, 'ip':ip, 'nbp':nbp, 'tnbp':tnbp, 'mapName':mapName, 'mapSize':mapSize, 'victoryCondition':victoryCondition }
     197    self.m_gameList[sid] = game
     198
     199  def removeGame(self, sid):
     200    if sid in self.m_gameList:
     201      del self.m_gameList[sid]
     202
     203if __name__ == '__main__':
     204  # Setup the command line arguments.
     205  optp = OptionParser()
     206
     207  # Output verbosity options.
     208  optp.add_option('-q', '--quiet', help='set logging to ERROR',
     209                  action='store_const', dest='loglevel',
     210                  const=logging.ERROR, default=logging.INFO)
     211  optp.add_option('-d', '--debug', help='set logging to DEBUG',
     212                  action='store_const', dest='loglevel',
     213                  const=logging.DEBUG, default=logging.INFO)
     214  optp.add_option('-v', '--verbose', help='set logging to COMM',
     215                  action='store_const', dest='loglevel',
     216                  const=5, default=logging.INFO)
     217
     218  # XpartaMuPP configuration options
     219  optp.add_option('-m', '--domain', help='set xpartamupp domain',
     220                  action='store', dest='xdomain',
     221                  default="localhost")
     222  optp.add_option('-l', '--login', help='set xpartamupp login',
     223                  action='store', dest='xlogin',
     224                  default="xpartamupp")
     225  optp.add_option('-p', '--password', help='set xpartamupp password',
     226                  action='store', dest='xpassword',
     227                  default="XXXXXX")
     228  optp.add_option('-n', '--nickname', help='set xpartamupp nickname',
     229                  action='store', dest='xnickname',
     230                  default="XpartaMuCC")
     231  optp.add_option('-D', '--demo', help='set xpartamupp in DEMO mode (add a few fake games)',
     232                  action='store_true', dest='xdemomode',
     233                  default=False)
     234
     235  opts, args = optp.parse_args()
     236
     237  # Set DEMO mode
     238  configDEMOModOn = opts.xdemomode
     239
     240  # Setup logging.
     241  logging.basicConfig(level=opts.loglevel,
     242                      format='%(levelname)-8s %(message)s')
     243
     244  # XpartaMuPP
     245  xmpp = XpartaMuPP(opts.xlogin+'@'+opts.xdomain+'/CC', opts.xpassword, 'arena@conference.'+opts.xdomain, opts.xnickname)
     246  xmpp.register_plugin('xep_0030') # Service Discovery
     247  xmpp.register_plugin('xep_0004') # Data Forms
     248  xmpp.register_plugin('xep_0045') # Multi-User Chat    # used
     249  xmpp.register_plugin('xep_0060') # PubSub
     250  xmpp.register_plugin('xep_0199') # XMPP Ping
     251
     252  if xmpp.connect():
     253    xmpp.process(threaded=False)
     254  else:
     255    logging.error("Unable to connect")
     256
  • source/tools/XpartaMuPP/mod_ipstamp.erl

    Property changes on: source/tools/XpartaMuPP/XpartaMuPP.py
    ___________________________________________________________________
    Added: svn:executable
       + *
    
     
     1
     2-module(mod_ipstamp).
     3
     4-behaviour(gen_mod).
     5
     6-include("ejabberd.hrl").
     7
     8-export([start/2, stop/1, on_filter_packet/1]).
     9
     10start(_Host, _Opts) ->
     11    ?INFO_MSG("mod_ipip starting", []),
     12    ejabberd_hooks:add(filter_packet, global, ?MODULE, on_filter_packet, 50),
     13    ok.
     14
     15stop(_Host) ->
     16    ejabberd_hooks:delete(filter_packet, global, ?MODULE, on_filter_packet, 50),
     17    ok.
     18
     19on_filter_packet({From, To, Packet} = Input) ->
     20    {_,STo,_,_,_,_,_} = To,
     21    if STo == "xpartamupp" ->
     22      {_,SElement,LPacketInfo,LPacketQuery} = Packet,
     23      if SElement == "iq" ->
     24        {_, SType} = lists:keyfind("type",1,LPacketInfo),
     25        if SType == "set" ->
     26      {_,_,LXmlns,LGame} = lists:keyfind("query",2,LPacketQuery),
     27          {_,SXmlns} = lists:keyfind("xmlns",1,LXmlns),
     28          if SXmlns == "jabber:iq:gamelist" ->
     29            {_,_,_,LCommand} = lists:keyfind("command",2,LGame),
     30            {_,SCommand} = lists:keyfind(xmlcdata,1,LCommand),
     31            if SCommand == <<"register">> ->
     32              {_,_,KGame,_} = lists:keyfind("game",2,LGame),
     33              Info = ejabberd_sm:get_user_info("xpartamupp","localhost","CC"),
     34              {ip, {Ploc, _Port}} = lists:keyfind(ip, 1, Info),
     35              SIp = inet_parse:ntoa(Ploc),
     36              ?INFO_MSG(string:concat("stamp ip: ",SIp), []),
     37              {From,To,{xmlelement,"iq",LPacketInfo,[
     38                {xmlelement,"query",[{"xmlns","jabber:iq:gamelist"}],[
     39                  {xmlelement,"game",lists:keyreplace("ip",1,KGame,{"ip",SIp}),[]},
     40                  {xmlelement,"command",[],[{xmlcdata,<<"register">>}]}
     41                  ]
     42                }
     43              ]}}
     44            ; true -> Input
     45            end
     46          ; true -> Input
     47          end
     48        ; true -> Input
     49        end
     50      ; true -> Input
     51      end
     52    ; true -> Input
     53    end.
     54
  • source/tools/XpartaMuPP/Makefile

     
     1include_dir = /usr/lib/ejabberd/include/
     2ebin_dir = /usr/lib/ejabberd/ebin/
     3
     4module = mod_ipstamp.beam
     5all : ${module}
     6
     7%.beam : %.erl
     8    erlc -I ${include_dir} -pz ${ebin_dir} $<
     9
     10install :
     11    mv ${module} ${ebin_dir}
     12
     13clean :
     14    rm ${module}
     15
     16restart :
     17    rm -f /var/log/ejabberd/ejabberd.log
     18    /etc/init.d/ejabberd restart
  • source/tools/XpartaMuPP/README

     
     1@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     2@@ Install ejabberd and the erlang compiler @@
     3@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     4# apt-get install ejabberd erlang-dev?
     5
     6Configure it
     7# dpkg-reconfigure ejabberd
     8set the domain name (e.g. localhost if you installed it on your development computer)
     9and a login / password
     10
     11You should now be able to connect to this XMPP server using a normal XMPP client (e.g. Empathy).
     12
     13@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     14@@ Installation of the custom XMPP module @@
     15@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     16Go to it's source directory
     17$ cd source/tools/XpartaMuPP
     18
     19Build and install it
     20$ make
     21# make install
     22
     23Tell ejabberd that you want it to load the module
     24In /etc/ejabberd/ejabberd.cfg, add {mod_ipstamp, []}
     25in the Modules list "Modules enabled in all ejabberd virtual hosts"
     26
     27Restart ejabberd
     28# service ejabberd restart
     29
     30If something goes wrong read /var/log/ejabberd/ejabberd.log
     31
     32@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     33@@ Ejabberd administration @@
     34@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     35Go http://localhost:5280/admin and connect
     36(the login looks like login@domain (e.g. adminjabber@localhost))
     37
     38In "Acces rules" check that "register" is set to "[{allow,all}]"
     39
     40You can see the list of registered / connected users in
     41"Virtual Hosts" >> domain name >> "users"
     42
     43You must manually add a new user for XpartaMuPP.
     44Enter a login (use "xpartamupp" since that's what clients expect)
     45and password, then press "Add user"
     46
     47@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     48@@ Run XpartaMuPP - XMPP Multiplayer Game Manager @@
     49@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
     50You need to have python 3 installed
     51$ sudo apt-get install python3
     52
     53You also need the SleekXmpp Python library
     54Go to to github and follow their instructions
     55https://github.com/fritzy/SleekXMPP
     56
     57Then execute the following command to run the script with default options
     58$ ./source/tools/XpartaMuPP.py
     59
     60or rather a similar command to run a properly configured program
     61$ ./source/tools/XpartaMuPP.py --domain localhost --login xpartamupp --password XXXXXX --nickname XpartaMuCC
     62
     63Run ./source/tools/XpartaMuPP.py -h for the full list of options
     64
     65If everything is fine you should see something along these lines in your console
     66<<<<
     67INFO     Negotiating TLS
     68INFO     Using SSL version: 3
     69INFO     Node set to: xpartamupp@localhost/CC
     70xpartamupp started
     71<<<<
     72
     73Congratulations, you are running XpartaMuPP - the 0ad Multiplayer Game Manager.
     74
  • source/lobby/XmppClient.cpp

     
     1#include "precompiled.h"
     2#include "XmppClient.h"
     3#include "GameItemData.h"
     4
     5//debug
     6#include <iostream>
     7
     8#include <sstream>
     9
     10//Gloox
     11#include <gloox/rostermanager.h>
     12#include <gloox/rosteritem.h>
     13#include <gloox/error.h>
     14
     15//Game - script
     16#include "scriptinterface/ScriptInterface.h"
     17
     18//Configuration
     19#include "ps/ConfigDB.h"
     20
     21//global
     22XmppClient *g_XmppClient = NULL;
     23
     24//debug
     25#if 1
     26#define DbgXMPP(x)
     27#else
     28#define DbgXMPP(x) std::cout << x << std::endl;
     29#endif
     30
     31//utils
     32std::string StanzaErrorToString(StanzaError& err)
     33{
     34  std::string msg;
     35#define CASE(X, Y) case X: return Y;
     36  switch (err)
     37  {
     38    CASE(StanzaErrorBadRequest, "Bad request")
     39    CASE(StanzaErrorConflict, "Player name already used")
     40    CASE(StanzaErrorFeatureNotImplemented, "Feature not implemented")
     41    CASE(StanzaErrorForbidden, "Forbidden")
     42    CASE(StanzaErrorGone, "Recipient or server gone")
     43    CASE(StanzaErrorInternalServerError, "Internal server error")
     44    CASE(StanzaErrorItemNotFound, "Item not found")
     45    CASE(StanzaErrorJidMalformed, "Jid malformed")
     46    CASE(StanzaErrorNotAcceptable, "Not acceptable")
     47    CASE(StanzaErrorNotAllowed, "Not allowed")
     48    CASE(StanzaErrorNotAuthorized, "Not authorized")
     49    CASE(StanzaErrorNotModified, "Not modified")
     50    CASE(StanzaErrorPaymentRequired, "Payment required")
     51    CASE(StanzaErrorRecipientUnavailable, "Recipient unavailable")
     52    CASE(StanzaErrorRedirect, "Redirect")
     53    CASE(StanzaErrorRegistrationRequired, "Registration required")
     54    CASE(StanzaErrorRemoteServerNotFound, "Remote server not found")
     55    CASE(StanzaErrorRemoteServerTimeout, "Remote server timeout")
     56    CASE(StanzaErrorResourceConstraint, "Resource constraint")
     57    CASE(StanzaErrorServiceUnavailable, "Service unavailable")
     58    CASE(StanzaErrorSubscribtionRequired, "Subscribtion Required")
     59    CASE(StanzaErrorUndefinedCondition, "Undefined condition")
     60    CASE(StanzaErrorUnexpectedRequest, "Unexpected request")
     61    CASE(StanzaErrorUnknownSender, "Unknown sender")
     62    default:
     63      return "Error undefined";
     64  }
     65#undef CASE
     66}
     67
     68XmppClient::XmppClient(ScriptInterface& scriptInterface, std::string sUsername, std::string sPassword, std::string sRoom, std::string sNick, bool regOpt)
     69  : m_ScriptInterface(scriptInterface), _client(NULL), _mucRoom(NULL), _registration(NULL), _username(sUsername), _password(sPassword), _nick(sNick)
     70{
     71  // Read lobby configuration from default.cfg
     72  std::string sServer;
     73  std::string sXpartamupp;
     74  CFG_GET_USER_VAL("lobby.server", String, sServer);
     75  CFG_GET_USER_VAL("lobby.xpartamupp", String, sXpartamupp);
     76
     77  _xpartamuppId = sXpartamupp+std::string("@")+sServer+std::string("/CC");
     78  JID clientJid(sUsername+std::string("@")+sServer+std::string("/0ad"));
     79  JID roomJid(sRoom+std::string("@conference.")+sServer+std::string("/")+sNick);
     80
     81  // If we are connecting, use the full jid and a password
     82  // If we are registering, only use the server name
     83  if(!regOpt)
     84    _client = new Client(clientJid, sPassword);
     85  else
     86    _client = new Client(sServer);
     87
     88  _client->registerConnectionListener( this );
     89  _client->setPresence(Presence::Available, -1);
     90  _client->disco()->setVersion( "TestProg", "1.0" );
     91  _client->disco()->setIdentity( "client", "bot" );
     92  _client->setCompression(false);
     93
     94  _client->registerStanzaExtension( new GameListQuery() );
     95  _client->registerIqHandler( this, ExtGameListQuery);
     96
     97  _client->registerMessageHandler( this );
     98
     99  StringList ca;
     100  ca.push_back( "/path/to/cacert.crt" );
     101  _client->setCACerts( ca );
     102
     103  // Uncomment to see the raw stanzas
     104  //_client->logInstance().registerLogHandler( LogLevelDebug, LogAreaAll, this );
     105
     106  if (!regOpt)
     107  {
     108    // Create a Multi User Chat Room
     109    _mucRoom = new MUCRoom(_client, roomJid, this, 0);
     110    // Disable the history because its anoying
     111    _mucRoom->setRequestHistory(0, MUCRoom::HistoryMaxStanzas);
     112  }
     113  else
     114  {
     115    // Registration
     116    _registration = new Registration( _client );
     117    _registration->registerRegistrationHandler( this );
     118  }
     119}
     120
     121XmppClient::~XmppClient()
     122{
     123  DbgXMPP("XmppClient destroyed");
     124  delete _registration;
     125  delete _mucRoom;
     126  delete _client;
     127}
     128
     129// Game - script
     130ScriptInterface& XmppClient::GetScriptInterface()
     131{
     132  return m_ScriptInterface;
     133}
     134
     135//Network
     136void XmppClient::connect()
     137{
     138  _client->connect(false);
     139}
     140
     141void XmppClient::disconnect()
     142{
     143  _client->disconnect();
     144}
     145
     146void XmppClient::recv()
     147{
     148  _client->recv(1);
     149}
     150
     151/*
     152 *  MUC Handlers
     153 */
     154void XmppClient::handleMUCParticipantPresence(gloox::MUCRoom*, gloox::MUCRoomParticipant participant, const gloox::Presence& presence)
     155
     156  //std::string jid = participant.jid->full();
     157  std::string nick = participant.nick->resource();
     158  gloox::Presence::PresenceType presenceType = presence.presence();
     159  if (presenceType == Presence::Unavailable)
     160  {
     161    DbgXMPP(nick << " left the room");
     162    m_PlayerMap.erase(nick);
     163  }
     164  else
     165  {
     166    DbgXMPP(nick << " is in the room");
     167    m_PlayerMap[nick] = std::pair<std::string, int>(nick, (int)presenceType);
     168  }
     169  CreateSimpleMessage("system", "playerlist updated", "internal");
     170}
     171
     172void XmppClient::handleMUCMessage( MUCRoom*, const Message& msg, bool )
     173{
     174  DbgXMPP(msg.from().resource() << " said " << msg.body());
     175  std::string nick = msg.from().resource();
     176  std::string body = msg.body();
     177
     178  CScriptValRooted message;
     179  GetScriptInterface().Eval("({ 'type':'mucmessage'})", message);
     180  GetScriptInterface().SetProperty(message.get(), "from", nick);
     181  GetScriptInterface().SetProperty(message.get(), "text", body);
     182  PushGuiMessage(message);
     183}
     184
     185void XmppClient::handleMUCError(gloox::MUCRoom*, gloox::StanzaError err)
     186{
     187  std::string msg = StanzaErrorToString(err);
     188  CreateSimpleMessage("system", msg, "error");
     189}
     190
     191void XmppClient::handleMUCItems( MUCRoom * /*room*/, const Disco::ItemList& items )
     192{
     193  m_PlayerMap.clear();
     194
     195  // Add the received items
     196  Disco::ItemList::const_iterator it = items.begin();
     197  for( ; it != items.end(); ++it )
     198  {
     199    std::string jid = (*it)->jid().full().c_str();
     200    std::string nick = (*it)->name().c_str();
     201    m_PlayerMap[nick] = std::pair<std::string, int>(nick, Presence::Available);
     202    //printf( "%s -- %s is an item here\n", (*it)->jid().full().c_str(), (*it)->name().c_str() );
     203  }
     204  CreateSimpleMessage("system", "playerlist updated", "internal");
     205}
     206
     207/*
     208 *  Log (debug) Handler
     209 */
     210void XmppClient::handleLog( LogLevel level, LogArea area, const std::string& message )
     211{
     212  std::cout << "log: level: " <<  level << ", area: " << area << ", message: " << message << std::endl;
     213}
     214
     215/*
     216 *  IQ Handler
     217 */
     218bool XmppClient::handleIq( const IQ& iq )
     219{
     220  DbgXMPP("handleIq [" << iq.tag()->xml() << "]");
     221
     222  if(iq.subtype() == gloox::IQ::Result)
     223  {
     224    const GameListQuery* q = iq.findExtension<GameListQuery>( ExtGameListQuery );
     225    if(q)
     226    {
     227      m_GameList.clear();
     228      std::list<GameItemData*>::const_iterator it = q->gameList().begin();
     229      for(; it != q->gameList().end(); ++it)
     230      {
     231        m_GameList.push_back(**it);
     232      }
     233      CreateSimpleMessage("system", "gamelist updated", "internal");
     234    }
     235  }
     236  else if(iq.subtype() == gloox::IQ::Error)
     237  {
     238    StanzaError err = iq.error()->error();
     239    std::string msg = StanzaErrorToString(err);
     240    CreateSimpleMessage("system", msg, "error");
     241  }
     242  else
     243  {
     244    CreateSimpleMessage("system", std::string("unknown subtype : ") + iq.tag()->name(), "error");
     245  }
     246
     247  return true;
     248}
     249
     250/*
     251 *  Connection Handlers
     252 */
     253void XmppClient::onConnect()
     254{
     255  if (_mucRoom)
     256  {
     257    CreateSimpleMessage("system", "connected");
     258    _mucRoom->join();
     259    //_mucRoom->getRoomInfo();
     260    _mucRoom->getRoomItems();
     261    SendIqGetGameList();
     262  }
     263
     264  if (_registration)
     265  {
     266    _registration->fetchRegistrationFields();
     267  }
     268}
     269
     270void XmppClient::onDisconnect( ConnectionError e )
     271{
     272  // Make sure we properly leave the room so than
     273  // everything work if we decide to come back later
     274  if (_mucRoom)
     275    _mucRoom->leave();
     276
     277  if( e == ConnAuthenticationFailed )
     278    CreateSimpleMessage("system", "authentication failed", "error");
     279  else
     280    CreateSimpleMessage("system", "disconnected");
     281
     282  m_PlayerMap.clear();
     283  m_GameList.clear();
     284  CreateSimpleMessage("system", "playerlist updated", "internal");
     285  CreateSimpleMessage("system", "gamelist updated", "internal");
     286}
     287
     288bool XmppClient::onTLSConnect( const CertInfo& )
     289{
     290  return true;
     291}
     292
     293/*
     294 *  Requests
     295 */
     296
     297/* Request GameList from cloud */
     298void XmppClient::SendIqGetGameList()
     299{
     300  JID xpartamuppJid(_xpartamuppId);
     301
     302  // Send IQ
     303  IQ iq(gloox::IQ::Get, xpartamuppJid);
     304  iq.addExtension( new GameListQuery() );
     305  DbgXMPP("SendIqGetGameList [" << iq.tag()->xml() << "]");
     306  _client->send(iq);
     307}
     308
     309/* Register a game */
     310void XmppClient::SendIqRegisterGame(CScriptVal data)
     311{
     312  JID xpartamuppJid(_xpartamuppId);
     313
     314  std::string name, mapName, mapSize, victoryCondition, nbp, tnbp;
     315  GetScriptInterface().GetProperty(data.get(), "name", name);
     316  GetScriptInterface().GetProperty(data.get(), "mapName", mapName);
     317  GetScriptInterface().GetProperty(data.get(), "mapSize", mapSize);
     318  GetScriptInterface().GetProperty(data.get(), "victoryCondition", victoryCondition);
     319  GetScriptInterface().GetProperty(data.get(), "nbp", nbp);
     320  GetScriptInterface().GetProperty(data.get(), "tnbp", tnbp);
     321
     322  // Send IQ
     323  GameListQuery* g = new GameListQuery();
     324  g->m_command = "register";
     325  /* This "x" fake ip will be overwritten by the ip stamp XMPP module */
     326  GameItemData *pItemData = new GameItemData(name, "x");
     327  pItemData->m_mapName = mapName;
     328  pItemData->m_mapSize = mapSize;
     329  pItemData->m_victoryCondition = victoryCondition;
     330  pItemData->m_nbp = nbp;
     331  pItemData->m_tnbp = tnbp;
     332  g->m_gameList.push_back( pItemData );
     333
     334  IQ iq(gloox::IQ::Set, xpartamuppJid);
     335  iq.addExtension( g );
     336  DbgXMPP("SendIqRegisterGame [" << iq.tag()->xml() << "]");
     337  _client->send(iq);
     338}
     339
     340/* Unregister a game */
     341void XmppClient::SendIqUnregisterGame(std::string name)
     342{
     343  JID xpartamuppJid(_xpartamuppId);
     344
     345  // Send IQ
     346  GameListQuery* g = new GameListQuery();
     347  g->m_command = "unregister";
     348  g->m_gameList.push_back( new GameItemData(name) );
     349
     350  IQ iq(gloox::IQ::Set, xpartamuppJid);
     351  iq.addExtension( g );
     352  DbgXMPP("SendIqUnregisterGame [" << iq.tag()->xml() << "]");
     353  _client->send(iq);
     354}
     355
     356/*
     357 *  Registration
     358 */
     359void XmppClient::handleRegistrationFields( const JID& /*from*/, int fields, std::string )
     360{
     361  RegistrationFields vals;
     362  vals.username = _username;
     363  vals.password = _password;
     364  _registration->createAccount( fields, vals );
     365}
     366
     367void XmppClient::handleRegistrationResult( const JID& /*from*/, RegistrationResult result )
     368{
     369  if (result == gloox::RegistrationSuccess)
     370  {
     371    CreateSimpleMessage("system", "Registered");
     372  }
     373  else
     374  {
     375    std::string msg;
     376#define CASE(X, Y) case X: msg = Y; break;
     377    switch(result)
     378    {
     379      CASE(RegistrationNotAcceptable, "Registration not acceptable")
     380      CASE(RegistrationConflict, "Registration conflict")
     381      CASE(RegistrationNotAuthorized, "Registration not authorized")
     382      CASE(RegistrationBadRequest, "Registration bad request")
     383      CASE(RegistrationForbidden, "Registration forbidden")
     384      CASE(RegistrationRequired, "Registration required")
     385      CASE(RegistrationUnexpectedRequest, "Registration unexpected request")
     386      CASE(RegistrationNotAllowed, "Registration not allowed")
     387      default: msg = "Registration unknown error";
     388    }
     389#undef CASE
     390    CreateSimpleMessage("system", msg, "error");
     391  }
     392  disconnect();
     393}
     394
     395void XmppClient::handleAlreadyRegistered( const JID& /*from*/ )
     396{
     397  DbgXMPP("the account already exists");
     398}
     399
     400void XmppClient::handleDataForm( const JID& /*from*/, const DataForm& /*form*/ )
     401{
     402  DbgXMPP("dataForm received");
     403}
     404
     405void XmppClient::handleOOB( const JID& /*from*/, const OOB& /* oob */ )
     406{
     407  DbgXMPP("OOB registration requested");
     408}
     409
     410/**
     411  * Message
     412  */
     413void XmppClient::handleMessage( const Message& msg, MessageSession * /*session*/ )
     414{
     415  DbgXMPP("type " << msg.subtype() << ", subject " << msg.subject().c_str()
     416    << ", message " << msg.body().c_str() << ", thread id " << msg.thread().c_str());
     417
     418  std::string nick = msg.from().resource();
     419  std::string body = msg.body();
     420
     421  CScriptValRooted message;
     422  GetScriptInterface().Eval("({ 'type':'message'})", message);
     423  GetScriptInterface().SetProperty(message.get(), "from", nick);
     424  GetScriptInterface().SetProperty(message.get(), "text", body);
     425  PushGuiMessage(message);
     426}
     427
     428
     429
     430/* Requests from GUI */
     431CScriptValRooted XmppClient::GUIGetPlayerList()
     432{
     433  CScriptValRooted playerList;
     434  GetScriptInterface().Eval("({})", playerList);
     435  for(std::map<std::string, std::pair<std::string, int> >::iterator it = m_PlayerMap.begin(); it != m_PlayerMap.end(); ++it)
     436  {
     437    CScriptValRooted player;
     438    GetScriptInterface().Eval("({})", player);
     439    GetScriptInterface().SetProperty(player.get(), "name", it->second.first.c_str());
     440    GetScriptInterface().SetProperty(player.get(), "presenceType", it->second.first);
     441
     442    GetScriptInterface().SetProperty(playerList.get(), it->second.first.c_str(), player);
     443  }
     444
     445  return playerList;
     446}
     447
     448CScriptValRooted XmppClient::GUIGetGameList()
     449{
     450  CScriptValRooted gameList;
     451  //GetScriptInterface().Eval("({})", gameList);
     452  GetScriptInterface().Eval("([])", gameList);
     453  for(std::list<GameItemData>::iterator it = m_GameList.begin(); it !=m_GameList.end(); ++it)
     454  {
     455    CScriptValRooted game;
     456    GetScriptInterface().Eval("({})", game);
     457
     458#define ITEM(param)\
     459    GetScriptInterface().SetProperty(game.get(), #param, it->m_##param .c_str());
     460    ITEMS
     461#undef ITEM
     462
     463    //GetScriptInterface().SetProperty(gameList.get(), it->m_name.c_str(), game);
     464    GetScriptInterface().CallFunctionVoid(gameList.get(), "push", game);
     465  }
     466
     467  return gameList;
     468}
     469
     470/* Messages */
     471CScriptValRooted XmppClient::GuiPollMessage()
     472{
     473  if (m_GuiMessageQueue.empty())
     474    return CScriptValRooted();
     475
     476  CScriptValRooted r = m_GuiMessageQueue.front();
     477  m_GuiMessageQueue.pop_front();
     478  return r;
     479}
     480
     481void XmppClient::SendMUCMessage(std::string message)
     482{
     483  _mucRoom->send(message);
     484}
     485
     486void XmppClient::PushGuiMessage(const CScriptValRooted& message)
     487{
     488  ENSURE(!message.undefined());
     489
     490  m_GuiMessageQueue.push_back(message);
     491}
     492
     493void XmppClient::CreateSimpleMessage(std::string type, std::string text, std::string level)
     494{
     495  CScriptValRooted message;
     496  GetScriptInterface().Eval("({})", message);
     497  GetScriptInterface().SetProperty(message.get(), "type", type);
     498  GetScriptInterface().SetProperty(message.get(), "level", level);
     499  GetScriptInterface().SetProperty(message.get(), "text", text);
     500  PushGuiMessage(message);
     501}
     502
     503/*
     504 *  GameListQuery, custom IQ Stanza
     505 */
     506
     507GameListQuery::GameListQuery( const Tag* tag )
     508: StanzaExtension( ExtGameListQuery )
     509{
     510  if( !tag || tag->name() != "query" || tag->xmlns() != XMLNS_GAMELIST )
     511    return;
     512
     513  const Tag* c = tag->findTag( "query/game" );
     514  if (c)
     515    m_command = c->cdata();
     516
     517  const ConstTagList& l = tag->findTagList( "query/game" );
     518  ConstTagList::const_iterator it = l.begin();
     519  for( ; it != l.end(); ++it )
     520  {
     521    GameItemData *pItem = new GameItemData();
     522#define ITEM(param)\
     523    const std::string param = (*it)->findAttribute( #param ); \
     524    pItem->m_##param = param;
     525    ITEMS
     526#undef ITEM
     527    m_gameList.push_back( pItem );
     528  }
     529}
     530
     531GameListQuery::~GameListQuery()
     532{
     533  util::clearList( m_gameList );
     534}
     535
     536const std::string& GameListQuery::filterString() const
     537{
     538  static const std::string filter = "/iq/query[@xmlns='" + XMLNS_GAMELIST + "']";
     539  return filter;
     540}
     541
     542Tag* GameListQuery::tag() const
     543{
     544  Tag* t = new Tag( "query" );
     545  t->setXmlns( XMLNS_GAMELIST );
     546/*
     547  RosterData::const_iterator it = m_roster.begin();
     548  for( ; it != m_roster.end(); ++it )
     549  t->addChild( (*it)->tag() );
     550*/
     551
     552  // register / unregister command
     553  if(!m_command.empty())
     554    t->addChild(new Tag("command", m_command));
     555
     556  std::list<GameItemData*>::const_iterator it = m_gameList.begin();
     557  for( ; it != m_gameList.end(); ++it )
     558    t->addChild( (*it)->tag() );
     559
     560  return t;
     561}
     562
     563StanzaExtension* GameListQuery::clone() const
     564{
     565  GameListQuery* q = new GameListQuery();
     566
     567  return q;
     568}
     569
     570const std::list<GameItemData*>& GameListQuery::gameList() const
     571{
     572  return m_gameList;
     573}
  • source/lobby/GameItemData.h

     
     1#ifndef GAMEITEMDATA_H
     2#define GAMEITEMDATA_H
     3
     4#include <string>
     5
     6#define ITEMS \
     7  ITEM(name)      \
     8  ITEM(ip)        \
     9  ITEM(nbp)       \
     10  ITEM(tnbp)      \
     11  ITEM(mapName)   \
     12  ITEM(mapSize)   \
     13  ITEM(victoryCondition)
     14
     15class GameItemData
     16{
     17  friend class XmppClient;
     18  friend class GameListQuery;
     19public:
     20  GameItemData(std::string name= "", std::string ip = "")
     21  : m_name(name), m_ip(ip)
     22  {
     23  }
     24
     25  virtual ~GameItemData() {}
     26
     27  Tag* tag() const
     28  {
     29    Tag* i = new Tag( "game" );
     30
     31#define ITEM(param)\
     32    i->addAttribute( #param, m_##param );
     33    ITEMS
     34#undef ITEM
     35
     36    return i;
     37  }
     38
     39protected:
     40#define ITEM(param)\
     41  std::string m_##param ;
     42  ITEMS
     43#undef ITEM
     44};
     45
     46#endif
  • source/lobby/XmppClient.h

     
     1#ifndef XXXMPPCLIENT_H
     2#define XXXMPPCLIENT_H
     3
     4//network
     5#include <gloox/jid.h>
     6#include <gloox/client.h>
     7#include <gloox/mucroom.h>
     8#include <gloox/message.h>
     9
     10#include <gloox/messagehandler.h>
     11#include <gloox/presencehandler.h>
     12#include <gloox/mucroomhandler.h>
     13#include <gloox/loghandler.h>
     14#include <gloox/connectionlistener.h>
     15#include <gloox/registration.h>
     16
     17#include <gloox/iq.h>
     18#include <gloox/iqhandler.h>
     19
     20//game - script
     21#include <deque>
     22#include "scriptinterface/ScriptVal.h"
     23
     24//Global Gamelist Extension
     25#define ExtGameListQuery 1403
     26const std::string XMLNS_GAMELIST = "jabber:iq:gamelist";
     27
     28//debug
     29using namespace gloox;
     30
     31//Game - script
     32class ScriptInterface;
     33class GameItemData;
     34
     35class XmppClient : public ConnectionListener, public MUCRoomHandler, public IqHandler, public LogHandler, public RegistrationHandler, public MessageHandler
     36{
     37private:
     38  //Game - script
     39  ScriptInterface& m_ScriptInterface;
     40  //Components
     41  Client* _client;
     42  MUCRoom* _mucRoom;
     43  Registration* _registration;
     44  //Account infos
     45  std::string _username;
     46  std::string _password;
     47  std::string _nick;
     48  std::string _xpartamuppId;
     49
     50public:
     51  //Basic
     52  XmppClient(ScriptInterface& scriptInterface, std::string sUsername, std::string sPassword, std::string sRoom, std::string sNick, bool regOpt = false);
     53  virtual ~XmppClient();
     54
     55  //Network
     56  void connect();
     57  void disconnect();
     58  void recv();
     59  void SendIqGetGameList();
     60  void SendIqRegisterGame(CScriptVal data);
     61  void SendIqUnregisterGame(std::string name);
     62
     63  CScriptValRooted GUIGetPlayerList();
     64  CScriptValRooted GUIGetGameList();
     65
     66  //Script
     67  ScriptInterface& GetScriptInterface();
     68
     69protected:
     70  /* Xmpp handlers */
     71  /* MUC handlers */
     72  virtual void handleMUCParticipantPresence(gloox::MUCRoom*, gloox::MUCRoomParticipant, const gloox::Presence&);
     73  virtual bool handleMUCRoomCreation(gloox::MUCRoom*) {return false;}
     74  virtual void handleMUCSubject(gloox::MUCRoom*, const std::string&, const std::string&) {}
     75  virtual void handleMUCInviteDecline(gloox::MUCRoom*, const gloox::JID&, const std::string&) {}
     76  virtual void handleMUCError(gloox::MUCRoom*, gloox::StanzaError);
     77  virtual void handleMUCInfo(gloox::MUCRoom*, int, const std::string&, const gloox::DataForm*) {}
     78  virtual void handleMUCItems(gloox::MUCRoom*, const std::list<gloox::Disco::Item*, std::allocator<gloox::Disco::Item*> >&);
     79  virtual void handleMUCMessage( MUCRoom* room, const Message& msg, bool priv );
     80
     81  /* Log handler */
     82  virtual void handleLog( LogLevel level, LogArea area, const std::string& message );
     83
     84  /* ConnectionListener handlers*/
     85  virtual void onConnect();
     86  virtual void onDisconnect( ConnectionError e );
     87  virtual bool onTLSConnect( const CertInfo& info );
     88
     89  /* Iq Handlers */
     90  virtual bool handleIq( const IQ& iq );
     91  virtual void handleIqID( const IQ&, int ) {}
     92
     93  /* Registration Handlers */
     94  virtual void handleRegistrationFields( const JID& /*from*/, int fields, std::string instructions );
     95  virtual void handleRegistrationResult( const JID& /*from*/, RegistrationResult result );
     96  virtual void handleAlreadyRegistered( const JID& /*from*/ );
     97  virtual void handleDataForm( const JID& /*from*/, const DataForm& /*form*/ );
     98  virtual void handleOOB( const JID& /*from*/, const OOB& oob );
     99
     100  /* Message Handler */
     101  virtual void handleMessage( const Message& msg, MessageSession * session );
     102
     103  /* Messages */
     104public:
     105  CScriptValRooted GuiPollMessage();
     106  void SendMUCMessage(std::string message);
     107protected:
     108  void PushGuiMessage(const CScriptValRooted& message);
     109  void CreateSimpleMessage(std::string type, std::string text, std::string level = "standard");
     110
     111private:
     112  /// Map of players
     113  std::map<std::string, std::pair<std::string, int> > m_PlayerMap;
     114  /// List of games
     115  std::list< GameItemData > m_GameList;
     116  /// Queue of messages
     117  std::deque<CScriptValRooted> m_GuiMessageQueue;
     118};
     119
     120class GameListQuery : public StanzaExtension
     121{
     122  friend class XmppClient;
     123public:
     124  GameListQuery( const Tag* tag = 0 );
     125
     126  ~GameListQuery();
     127
     128  // reimplemented from StanzaExtension
     129  virtual const std::string& filterString() const;
     130
     131  // reimplemented from StanzaExtension
     132  virtual StanzaExtension* newInstance( const Tag* tag ) const
     133  {
     134    return new GameListQuery( tag );
     135  }
     136
     137  // reimplemented from StanzaExtension
     138  virtual Tag* tag() const;
     139
     140  // reimplemented from StanzaExtension
     141  virtual StanzaExtension* clone() const;
     142
     143  const std::list<GameItemData*>& gameList() const;
     144
     145private:
     146  std::string m_command;
     147  std::list<GameItemData*> m_gameList;
     148};
     149
     150extern XmppClient *g_XmppClient;
     151
     152#endif // XMPPCLIENT_H
  • source/pch/lobby/precompiled.cpp

     
     1/* Copyright (C) 2009 Wildfire Games.
     2 * This file is part of 0 A.D.
     3 *
     4 * 0 A.D. is free software: you can redistribute it and/or modify
     5 * it under the terms of the GNU General Public License as published by
     6 * the Free Software Foundation, either version 2 of the License, or
     7 * (at your option) any later version.
     8 *
     9 * 0 A.D. is distributed in the hope that it will be useful,
     10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     12 * GNU General Public License for more details.
     13 *
     14 * You should have received a copy of the GNU General Public License
     15 * along with 0 A.D.  If not, see <http://www.gnu.org/licenses/>.
     16 */
     17
     18#include "precompiled.h"
  • source/pch/lobby/precompiled.h

     
     1/* Copyright (C) 2009 Wildfire Games.
     2 * This file is part of 0 A.D.
     3 *
     4 * 0 A.D. is free software: you can redistribute it and/or modify
     5 * it under the terms of the GNU General Public License as published by
     6 * the Free Software Foundation, either version 2 of the License, or
     7 * (at your option) any later version.
     8 *
     9 * 0 A.D. is distributed in the hope that it will be useful,
     10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     12 * GNU General Public License for more details.
     13 *
     14 * You should have received a copy of the GNU General Public License
     15 * along with 0 A.D.  If not, see <http://www.gnu.org/licenses/>.
     16 */
     17
     18#include "lib/precompiled.h"    // common precompiled header
  • binaries/data/mods/public/gui/pregame/mainmenu.xml

     
    196196                    Matches
    197197                    <action on="Press">
    198198                        closeMenu();
    199                         Engine.PushGuiPage("page_gamesetup.xml", { type: "offline" });
     199                        Engine.PushGuiPage("page_gamesetup.xml", { type: "offline", source: "mainmenu" });
    200200                    </action>
    201201                </object>
    202202
     
    253253                    <action on="Press">
    254254                        closeMenu();
    255255                        // Open Multiplayer connection window with join option.
    256                         Engine.PushGuiPage("page_gamesetup_mp.xml", "join");
     256                        Engine.PushGuiPage("page_gamesetup_mp.xml", { multiplayerGameType: "join", source: "mainmenu" });
    257257                    </action>
    258258                </object>
    259259
     
    268268                    <action on="Press">
    269269                        closeMenu();
    270270                        // Open Multiplayer connection window with host option.
    271                         Engine.PushGuiPage("page_gamesetup_mp.xml", "host");
     271                        Engine.PushGuiPage("page_gamesetup_mp.xml", { multiplayerGameType: "host", source: "mainmenu" });
    272272                    </action>
    273273                </object>
    274             </object>
    275274
     275                <object name="subMenuMultiplayerLobbyButton"
     276                    type="button"
     277                    style="StoneButtonFancy"
     278                    size="0 64 100% 92"
     279                    tooltip_style="pgToolTip"
     280                    tooltip="Launch the multiplayer lobby."
     281                >
     282                    Game Lobby
     283                    <action on="Press">
     284                        closeMenu();
     285                        // Open Multiplayer game lobby.
     286                        Engine.PushGuiPage("page_prelobby.xml", []);
     287                    </action>
     288                </object>
     289                </object>
     290
    276291            <!-- submenuToolsAndOptions -->
    277292            <object name="submenuToolsAndOptions"
    278293                type="image"
     
    402417                    Multiplayer
    403418                    <action on="Press">
    404419                        closeMenu();
    405                         openMenu("submenuMultiplayer", (this.parent.size.top+this.size.top), (this.size.bottom-this.size.top), 2);
     420                        openMenu("submenuMultiplayer", (this.parent.size.top+this.size.top), (this.size.bottom-this.size.top), 3);
    406421                    </action>
    407422                </object>
    408423
  • binaries/data/mods/public/gui/gamesetup/gamesetup_mp.js

     
    11var g_IsConnecting = false;
    22var g_GameType; // "server" or "client"
     3var g_Source; // "mainmenu" or "lobby"
     4var g_ServerName = "";
     5var g_Name;
     6var g_Ip;
    37
    48var g_IsRejoining = false;
    59var g_GameAttributes; // used when rejoining
    610var g_PlayerAssignments; // used when rejoining
    711
    8 function init(multiplayerGameType)
     12function init(attribs)
    913{
    10     switch (multiplayerGameType)
     14        switch (attribs.multiplayerGameType)
     15        {
     16                case "join":
     17                        getGUIObjectByName("pageJoin").hidden = false;
     18                        getGUIObjectByName("pageHost").hidden = true;
     19                        break;
     20                case "host":
     21                        getGUIObjectByName("pageJoin").hidden = true;
     22                        getGUIObjectByName("pageHost").hidden = false;
     23                        break;
     24                default:
     25                        error("Unrecognised multiplayer game type : " + attribs.multiplayerGameType);
     26                        break;
     27        }
     28   
     29    switch (attribs.source)
    1130    {
    12     case "join":
    13         getGUIObjectByName("pageJoin").hidden = false;
    14         getGUIObjectByName("pageHost").hidden = true;
    15         break;
    16     case "host":
    17         getGUIObjectByName("pageJoin").hidden = true;
    18         getGUIObjectByName("pageHost").hidden = false;
    19         break;
    20     default:
    21         error("Unrecognised multiplayer game type : " + multiplayerGameType);
    22         break;
     31        case "mainmenu":
     32            g_Source = "mainmenu";
     33            break;
     34        case "lobby":
     35            g_Source = "lobby";
     36            getGUIObjectByName("hostServerNameWrapper").hidden = false;
     37            break;
     38        default:
     39            error("Unrecognised source : " + attribs.source);
    2340    }
     41
     42    if (attribs.name)
     43    {
     44        getGUIObjectByName("hostPlayerName").caption = attribs.name;
     45        getGUIObjectByName("joinPlayerName").caption = attribs.name;
     46    }
     47    if (attribs.ip) getGUIObjectByName("joinIP").caption = attribs.ip;
    2448}
    2549
    2650function cancelSetup()
    2751{
    2852    if (g_IsConnecting)
    2953        Engine.DisconnectNetworkGame();
    30     Engine.PopGuiPage();   
     54    Engine.PopGuiPage();
    3155}
    3256
    3357function startConnectionStatus(type)
     
    4367    if (!g_IsConnecting)
    4468        return;
    4569
     70    pollAndHandleNetworkClient();
     71}
     72
     73function pollAndHandleNetworkClient()
     74{
    4675    while (true)
    4776    {
    4877        var message = Engine.PollNetworkClient();
     
    119148                    else
    120149                    {
    121150                        Engine.PopGuiPage();
    122                         Engine.PushGuiPage("page_gamesetup.xml", { "type": g_GameType });
     151                        Engine.PushGuiPage("page_gamesetup.xml", { "type": g_GameType, "source": g_Source, "serverName": g_ServerName });
    123152                        return; // don't process any more messages - leave them for the game GUI loop
    124153                    }
    125154
     
    163192    }
    164193
    165194    startConnectionStatus("server");
    166     // TODO: ought to do something(?) with servername
     195    g_ServerName = servername;
    167196
    168197    return true;
    169198}
  • binaries/data/mods/public/gui/gamesetup/gamesetup.js

     
    1919// Is this user in control of game settings (i.e. is a network server, or offline player)
    2020var g_IsController;
    2121
     22// Where this user come from ("mainmenu" or "lobby")
     23var g_Source;
     24
     25//Server name, if user is a server, connected to the multiplayer lobby
     26var g_ServerName;
     27
    2228// Are we currently updating the GUI in response to network messages instead of user input
    2329// (and therefore shouldn't send further messages to the network)
    2430var g_IsInGuiUpdate;
     
    6975    default:
    7076        error("Unexpected 'type' in gamesetup init: "+attribs.type);
    7177    }
     78
     79    switch (attribs.source)
     80    {
     81    case "mainmenu":
     82        g_Source = "mainmenu";
     83        break;
     84    case "lobby":
     85        g_Source = "lobby";
     86        break;
     87    default:
     88        error("Unrecognised source : " + attribs.source);
     89    }
     90
     91        if (attribs.serverName)
     92        g_ServerName = attribs.serverName;
    7293}
    7394
    7495// Called after the map data is loaded and cached
     
    156177                updateGameAttributes();
    157178            }
    158179        };
     180        mapSize.selected = 0;
    159181
    160182        getGUIObjectByName("revealMap").onPress = function()
    161183        {   // Update attributes so other players can see change
     
    281303        {
    282304        case "disconnected":
    283305            Engine.DisconnectNetworkGame();
     306            if (isServerOnLobby()) Engine.SendUnregisterGame(g_ServerName);
    284307            Engine.PopGuiPage();
    285308            reportDisconnect(message.reason);
    286309            break;
     
    319342        // Update the player list
    320343        g_PlayerAssignments = message.hosts;
    321344        updatePlayerList();
     345
     346        if (isServerOnLobby())
     347        {
     348            sendRegisterGameStanza();
     349        }
    322350        break;
    323351
    324352    case "start":
     353        if (g_Source == "lobby") Engine.StopXmppClient();
    325354        Engine.SwitchGuiPage("page_loading.xml", {
    326355            "attribs": g_GameAttributes,
    327356            "isNetworked" : g_IsNetworked,
     
    942971    if (g_IsNetworked)
    943972    {
    944973        Engine.SetNetworkGameAttributes(g_GameAttributes);
     974        if (isServerOnLobby() && g_LoadingState >= 2)
     975        {
     976            sendRegisterGameStanza();
     977        }
    945978    }
    946979    else
    947980    {
     
    12591292    }
    12601293    return false;
    12611294}
     1295
     1296function isServerOnLobby()
     1297{
     1298    return (g_IsController && g_Source == "lobby") ? true : false;
     1299}
     1300
     1301function sendRegisterGameStanza()
     1302{
     1303    var selectedMapSize = getGUIObjectByName("mapSize").selected;
     1304    var selectedVictoryCondition = getGUIObjectByName("victoryCondition").selected;
     1305
     1306    var mapSize = getGUIObjectByName("mapSize").list_data[selectedMapSize];
     1307    var victoryCondition = getGUIObjectByName("victoryCondition").list[selectedVictoryCondition];
     1308
     1309    var numberOfPlayers = 0;
     1310    for (var guid in g_PlayerAssignments)
     1311    {   
     1312        numberOfPlayers++;
     1313    }
     1314        print(numberOfPlayers);
     1315
     1316    var nbp = numberOfPlayers ? numberOfPlayers : 1;
     1317    var tnbp = g_GameAttributes.settings.PlayerData.length;
     1318
     1319    gameData = {
     1320        "name":g_ServerName,
     1321        "mapName":g_GameAttributes.map,
     1322        "mapSize":mapSize,
     1323        "victoryCondition":victoryCondition,
     1324        "nbp":nbp,
     1325        "tnbp":tnbp
     1326    };
     1327    Engine.SendRegisterGame(gameData);
     1328}
  • binaries/data/mods/public/gui/gamesetup/gamesetup_mp.xml

     
    7272                ]]></action>
    7373            </object>
    7474
    75             <object hidden="true"> <!-- TODO: restore this when the server name is actually used -->
     75            <object name="hostServerNameWrapper" hidden="true">
    7676            <object type="text" size="0 80 200 110" style="RightLabelText">
    7777                Server name:
    7878            </object>
  • binaries/data/mods/public/gui/gamesetup/gamesetup.xml

     
    240240            style="StoneButton"
    241241            size="100%-164 100%-52 100%-24 100%-24"
    242242            tooltip_style="onscreenToolTip"
    243             tooltip="Return to the main menu."
    244243        >
    245             Main menu
     244            <action on="Load"><![CDATA[
     245              if(!isServerOnLobby())
     246              {
     247                this.caption = "Main menu";
     248                this.tooltip = "Return to the main menu."
     249              }
     250              else
     251              {
     252                this.caption = "Quit";
     253                this.tooltip = "Return to the lobby."
     254              }
     255            ]]></action>
    246256            <action on="Press">
    247257                <![CDATA[
    248258                    cancelSetup();
     259                    if(isServerOnLobby()) Engine.SendUnregisterGame(g_ServerName);
    249260                    Engine.PopGuiPage();
    250261                ]]>
    251262            </action>
  • binaries/data/mods/public/gui/page_lobby.xml

     
     1<?xml version="1.0" encoding="utf-8"?>
     2<page>
     3  <include>common/setup.xml</include>
     4  <include>common/styles.xml</include>
     5  <include>common/sprite1.xml</include>
     6
     7<include>common/common_sprites.xml</include>
     8<include>common/common_styles.xml</include>
     9
     10  <include>lobby/styles.xml</include>
     11  <include>lobby/lobby.xml</include>
     12</page>
  • binaries/data/mods/public/gui/page_prelobby.xml

     
     1<?xml version="1.0" encoding="utf-8"?>
     2<page>
     3  <include>common/setup.xml</include>
     4  <include>common/styles.xml</include>
     5  <include>common/sprite1.xml</include>
     6
     7<include>common/common_sprites.xml</include>
     8<include>common/common_styles.xml</include>
     9
     10  <include>gamesetup/styles.xml</include>
     11  <include>summary/sprites.xml</include>
     12  <include>lobby/prelobby.xml</include>
     13</page>
     14
  • binaries/data/config/default.cfg

     
    241241joystick.camera.rotate.y = 2
    242242joystick.camera.zoom.in = 5
    243243joystick.camera.zoom.out = 4
     244
     245; Multiplayer lobby preferences
     246lobby.server = "localhost"
     247lobby.xpartamupp = "xpartamupp"