Ticket #1504: 0ad-multiplayer-lobby-v15-07-2012.diff

File 0ad-multiplayer-lobby-v15-07-2012.diff, 98.1 KB (added by Badmadblacksad-, 12 years ago)

Fixes windows build, adds missing files and minor bug fixes.

  • 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            if os.is("windows") then
     261                add_default_lib_paths("gloox")
     262            end
     263            add_default_links({
     264                win_names  = { "gloox-1.0" },
     265                unix_names = { "gloox" },
     266            })
     267        end,
     268    },
    255269    cxxtest = {
    256270        compile_settings = function()
    257271            add_default_include_paths("cxxtest")
  • build/premake/premake4.lua

     
    491491
    492492
    493493    source_dirs = {
     494    "lobby",
     495    }
     496    extern_libs = {
     497    "spidermonkey",
     498    "gloox",
     499    "boost",
     500    }
     501    setup_static_lib_project("lobby", source_dirs, extern_libs, {})
     502
     503
     504    source_dirs = {
    494505        "simulation2",
    495506        "simulation2/components",
    496507        "simulation2/helpers",
     
    538549        "boost",
    539550        "enet",
    540551        "libcurl",
     552        "gloox",
    541553    }
    542554    setup_static_lib_project("engine", source_dirs, extern_libs, {})
    543555
     
    580592        "spidermonkey",
    581593        "sdl",  -- key definitions
    582594        "opengl",
    583         "boost"
     595        "boost",
     596        "gloox",
    584597    }
    585598    setup_static_lib_project("gui", source_dirs, extern_libs, {})
    586599
     
    710723    "libcurl",
    711724
    712725    "valgrind",
     726
     727    "gloox",
    713728}
    714729
    715730if 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();
  • 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
     56    std::vector<ObjectDef> m_ObjectsDefs;
     57
     58private:
     59    float m_HeadingHeight;
     60
     61};
     62
     63#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 "precompiled.h"
     2#include "COList.h"
     3
     4#include "ps/CLogger.h"
     5
     6COList::COList() : CList(),m_HeadingHeight(30.f)
     7{
     8    AddSetting(GUIST_CGUISpriteInstance,    "sprite_heading");
     9}
     10
     11void COList::SetupText()
     12{
     13    if (!GetGUI())
     14        return;
     15
     16    CGUIList *pList;
     17    GUI<CGUIList>::GetSettingPointer(this, "list_ip", pList);
     18
     19    //ENSURE(m_GeneratedTexts.size()>=1);
     20
     21    m_ItemsYPositions.resize( pList->m_Items.size()+1 );
     22
     23    // Delete all generated texts. Some could probably be saved,
     24    //  but this is easier, and this function will never be called
     25    //  continuously, or even often, so it'll probably be okay.
     26    std::vector<SGUIText*>::iterator it;
     27    for (it=m_GeneratedTexts.begin(); it!=m_GeneratedTexts.end(); ++it)
     28    {
     29        if (*it)
     30            delete *it;
     31    }
     32    m_GeneratedTexts.clear();
     33
     34    CStrW font;
     35    if (GUI<CStrW>::GetSetting(this, "font", font) != PSRETURN_OK || font.empty())
     36        // Use the default if none is specified
     37        // TODO Gee: (2004-08-14) Don't define standard like this. Do it with the default style.
     38        font = L"default";
     39
     40    //CGUIString caption;
     41    bool scrollbar;
     42    //GUI<CGUIString>::GetSetting(this, "caption", caption);
     43    GUI<bool>::GetSetting(this, "scrollbar", scrollbar);
     44
     45    float width = GetListRect().GetWidth();
     46    // remove scrollbar if applicable
     47    if (scrollbar && GetScrollBar(0).GetStyle())
     48        width -= GetScrollBar(0).GetStyle()->m_Width;
     49
     50    float buffer_zone=0.f;
     51    GUI<float>::GetSetting(this, "buffer_zone", buffer_zone);
     52
     53
     54    for (unsigned int c=0; c<m_ObjectsDefs.size(); ++c)
     55    {
     56        SGUIText *text = new SGUIText();
     57        CGUIString gui_string;
     58        gui_string.SetValue(m_ObjectsDefs[c].m_Heading);
     59        *text = GetGUI()->GenerateText(gui_string, font, width, buffer_zone, this);
     60        AddText(text);
     61    }
     62
     63
     64    // Generate texts
     65    float buffered_y = 0.f;
     66
     67    for (int i=0; i<(int)pList->m_Items.size(); ++i)
     68    {
     69        m_ItemsYPositions[i] = buffered_y;
     70        for (unsigned int c=0; c<m_ObjectsDefs.size(); ++c)
     71        {
     72            CGUIList * pList_c;
     73            GUI<CGUIList>::GetSettingPointer(this, m_ObjectsDefs[c].m_Id, pList_c);
     74            SGUIText *text = new SGUIText();
     75            *text = GetGUI()->GenerateText(pList_c->m_Items[i], font, width, buffer_zone, this);
     76            if (c==0)
     77                buffered_y += text->m_Size.cy;
     78            AddText(text);
     79        }
     80    }
     81
     82    m_ItemsYPositions[pList->m_Items.size()] = buffered_y;
     83
     84    //if (! scrollbar)
     85    //  CalculateTextPosition(m_CachedActualSize, m_TextPos, *m_GeneratedTexts[0]);
     86
     87    // Setup scrollbar
     88    if (scrollbar)
     89    {
     90        GetScrollBar(0).SetScrollRange( m_ItemsYPositions.back() );
     91        GetScrollBar(0).SetScrollSpace( GetListRect().GetHeight() );
     92
     93        CRect rect = GetListRect();
     94        GetScrollBar(0).SetX( rect.right );
     95        GetScrollBar(0).SetY( rect.top );
     96        GetScrollBar(0).SetZ( GetBufferedZ() );
     97        GetScrollBar(0).SetLength( rect.bottom - rect.top );
     98    }
     99}
     100
     101CRect COList::GetListRect() const
     102{
     103    return m_CachedActualSize + CRect(0, m_HeadingHeight, 0, 0);
     104}
     105
     106void COList::HandleMessage(SGUIMessage &Message)
     107{
     108    CList::HandleMessage(Message);
     109//  switch (Message.type)
     110//  {
     111//  case GUIM_SETTINGS_UPDATED:
     112//      if (Message.value.Find("list_") != -1)
     113//      {
     114//          SetupText();
     115//      }
     116//  }
     117}
     118
     119bool COList::HandleAdditionalChildren(const XMBElement& child, CXeromyces* pFile)
     120{
     121    int elmt_item = pFile->GetElementID("item");
     122    int elmt_heading = pFile->GetElementID("heading");
     123    int elmt_def = pFile->GetElementID("def");
     124
     125    if (child.GetNodeName() == elmt_item)
     126    {
     127        AddItem(child.GetText().FromUTF8(), child.GetText().FromUTF8());
     128        return true;
     129    }
     130    else if (child.GetNodeName() == elmt_heading)
     131    {
     132        CStrW text (child.GetText().FromUTF8());
     133
     134        return true;
     135    }
     136    else if (child.GetNodeName() == elmt_def)
     137    {
     138        ObjectDef oDef;
     139
     140        XMBAttributeList attributes = child.GetAttributes();
     141        for (int i=0; i<attributes.Count; ++i)
     142        {
     143            XMBAttribute attr = attributes.Item(i);
     144            CStr attr_name (pFile->GetAttributeString(attr.Name));
     145            CStr attr_value (attr.Value);
     146
     147            if (attr_name == "color")
     148            {
     149                CColor color;
     150                if (!GUI<CColor>::ParseString(attr_value.FromUTF8(), color))
     151                    LOGERROR(L"GUI: Error parsing '%hs' (\"%ls\")", attr_name.c_str(), attr_value.c_str());
     152                else oDef.m_TextColor = color;
     153            }
     154            else if (attr_name == "id")
     155            {
     156                oDef.m_Id = "list_"+attr_value;
     157            }
     158            else if (attr_name == "width")
     159            {
     160                int width;
     161                if (!GUI<int>::ParseString(attr_value.FromUTF8(), width))
     162                    LOGERROR(L"GUI: Error parsing '%hs' (\"%ls\")", attr_name.c_str(), attr_value.c_str());
     163                else
     164                    oDef.m_Width = width;
     165            }
     166            else if (attr_name == "heading")
     167            {
     168                oDef.m_Heading = attr_value.FromUTF8();
     169            }
     170
     171        }
     172
     173        m_ObjectsDefs.push_back(oDef);
     174
     175        AddSetting(GUIST_CGUIList, oDef.m_Id);
     176        SetupText();
     177
     178        return true;
     179    }
     180    else
     181    {
     182        return false;
     183    }
     184}
     185
     186void COList::DrawList(const int &selected,
     187                     const CStr& _sprite,
     188                     const CStr& _sprite_selected,
     189                     const CStr& _textcolor)
     190{
     191    float bz = GetBufferedZ();
     192
     193    // First call draw on ScrollBarOwner
     194    bool scrollbar;
     195    GUI<bool>::GetSetting(this, "scrollbar", scrollbar);
     196
     197    if (scrollbar)
     198    {
     199        // Draw scrollbar
     200        IGUIScrollBarOwner::Draw();
     201    }
     202
     203    if (GetGUI())
     204    {
     205        CRect rect = GetListRect();
     206
     207        CGUISpriteInstance *sprite=NULL, *sprite_selectarea=NULL;
     208        int cell_id;
     209        GUI<CGUISpriteInstance>::GetSettingPointer(this, _sprite, sprite);
     210        GUI<CGUISpriteInstance>::GetSettingPointer(this, _sprite_selected, sprite_selectarea);
     211        GUI<int>::GetSetting(this, "cell_id", cell_id);
     212
     213        CGUIList *pList;
     214        GUI<CGUIList>::GetSettingPointer(this, "list_name", pList);
     215
     216        GetGUI()->DrawSprite(*sprite, cell_id, bz, rect);
     217
     218        float scroll=0.f;
     219        if (scrollbar)
     220        {
     221            scroll = GetScrollBar(0).GetPos();
     222        }
     223
     224        if (selected != -1)
     225        {
     226            ENSURE(selected >= 0 && selected+1 < (int)m_ItemsYPositions.size());
     227
     228            // Get rectangle of selection:
     229            CRect rect_sel(rect.left, rect.top + m_ItemsYPositions[selected] - scroll,
     230                                 rect.right, rect.top + m_ItemsYPositions[selected+1] - scroll);
     231
     232            if (rect_sel.top <= rect.bottom &&
     233                rect_sel.bottom >= rect.top)
     234            {
     235                if (rect_sel.bottom > rect.bottom)
     236                    rect_sel.bottom = rect.bottom;
     237                if (rect_sel.top < rect.top)
     238                    rect_sel.top = rect.top;
     239
     240                if (scrollbar)
     241                {
     242                    // Remove any overlapping area of the scrollbar.
     243                    if (rect_sel.right > GetScrollBar(0).GetOuterRect().left &&
     244                        rect_sel.right <= GetScrollBar(0).GetOuterRect().right)
     245                        rect_sel.right = GetScrollBar(0).GetOuterRect().left;
     246
     247                    if (rect_sel.left >= GetScrollBar(0).GetOuterRect().left &&
     248                        rect_sel.left < GetScrollBar(0).GetOuterRect().right)
     249                        rect_sel.left = GetScrollBar(0).GetOuterRect().right;
     250                }
     251
     252                GetGUI()->DrawSprite(*sprite_selectarea, cell_id, bz+0.05f, rect_sel);
     253            }
     254        }
     255
     256        CColor color;
     257        GUI<CColor>::GetSetting(this, _textcolor, color);
     258
     259        CGUISpriteInstance *sprite_heading=NULL;
     260        GUI<CGUISpriteInstance>::GetSettingPointer(this, "sprite_heading", sprite_heading);
     261        CRect rect_head(m_CachedActualSize.left, m_CachedActualSize.top, m_CachedActualSize.right,
     262                                        m_CachedActualSize.top + m_HeadingHeight);
     263        GetGUI()->DrawSprite(*sprite_heading, cell_id, bz, rect_head);
     264
     265        float xpos = 0;
     266        for (unsigned int def=0; def< m_ObjectsDefs.size(); ++def)
     267        {
     268            DrawText(def, color, m_CachedActualSize.TopLeft() + CPos(xpos, 4), bz+0.1f, rect_head);
     269            xpos += m_ObjectsDefs[def].m_Width;
     270        }
     271
     272        for (int i=0; i<(int)pList->m_Items.size(); ++i)
     273        {
     274            if (m_ItemsYPositions[i+1] - scroll < 0 ||
     275                m_ItemsYPositions[i] - scroll > rect.GetHeight())
     276                continue;
     277
     278            // Clipping area (we'll have to substract the scrollbar)
     279            CRect cliparea = GetListRect();
     280
     281            if (scrollbar)
     282            {
     283                if (cliparea.right > GetScrollBar(0).GetOuterRect().left &&
     284                    cliparea.right <= GetScrollBar(0).GetOuterRect().right)
     285                    cliparea.right = GetScrollBar(0).GetOuterRect().left;
     286
     287                if (cliparea.left >= GetScrollBar(0).GetOuterRect().left &&
     288                    cliparea.left < GetScrollBar(0).GetOuterRect().right)
     289                    cliparea.left = GetScrollBar(0).GetOuterRect().right;
     290            }
     291
     292            xpos = 0;
     293            for (unsigned int def=0; def< m_ObjectsDefs.size(); ++def)
     294            {
     295                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);
     296                xpos += m_ObjectsDefs[def].m_Width;
     297            }
     298        }
     299    }
     300}
  • 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//Gloox
     9#include <gloox/rostermanager.h>
     10#include <gloox/rosteritem.h>
     11#include <gloox/error.h>
     12
     13//Game - script
     14#include "scriptinterface/ScriptInterface.h"
     15
     16//Configuration
     17#include "ps/ConfigDB.h"
     18
     19using namespace gloox;
     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//Hack
     32#if 1
     33#if OS_WIN
     34const std::string gloox::EmptyString = "";
     35#endif
     36#endif
     37
     38//utils
     39std::string StanzaErrorToString(StanzaError& err)
     40{
     41  std::string msg;
     42#define CASE(X, Y) case X: return Y;
     43  switch (err)
     44  {
     45    CASE(StanzaErrorBadRequest, "Bad request")
     46    CASE(StanzaErrorConflict, "Player name already used")
     47    CASE(StanzaErrorFeatureNotImplemented, "Feature not implemented")
     48    CASE(StanzaErrorForbidden, "Forbidden")
     49    CASE(StanzaErrorGone, "Recipient or server gone")
     50    CASE(StanzaErrorInternalServerError, "Internal server error")
     51    CASE(StanzaErrorItemNotFound, "Item not found")
     52    CASE(StanzaErrorJidMalformed, "Jid malformed")
     53    CASE(StanzaErrorNotAcceptable, "Not acceptable")
     54    CASE(StanzaErrorNotAllowed, "Not allowed")
     55    CASE(StanzaErrorNotAuthorized, "Not authorized")
     56    CASE(StanzaErrorNotModified, "Not modified")
     57    CASE(StanzaErrorPaymentRequired, "Payment required")
     58    CASE(StanzaErrorRecipientUnavailable, "Recipient unavailable")
     59    CASE(StanzaErrorRedirect, "Redirect")
     60    CASE(StanzaErrorRegistrationRequired, "Registration required")
     61    CASE(StanzaErrorRemoteServerNotFound, "Remote server not found")
     62    CASE(StanzaErrorRemoteServerTimeout, "Remote server timeout")
     63    CASE(StanzaErrorResourceConstraint, "Resource constraint")
     64    CASE(StanzaErrorServiceUnavailable, "Service unavailable")
     65    CASE(StanzaErrorSubscribtionRequired, "Subscribtion Required")
     66    CASE(StanzaErrorUndefinedCondition, "Undefined condition")
     67    CASE(StanzaErrorUnexpectedRequest, "Unexpected request")
     68    CASE(StanzaErrorUnknownSender, "Unknown sender")
     69    default:
     70      return "Error undefined";
     71  }
     72#undef CASE
     73}
     74
     75XmppClient::XmppClient(ScriptInterface& scriptInterface, std::string sUsername, std::string sPassword, std::string sRoom, std::string sNick, bool regOpt)
     76  : m_ScriptInterface(scriptInterface), _client(NULL), _mucRoom(NULL), _registration(NULL), _username(sUsername), _password(sPassword), _nick(sNick)
     77{
     78  // Read lobby configuration from default.cfg
     79  std::string sServer;
     80  std::string sXpartamupp;
     81  CFG_GET_USER_VAL("lobby.server", String, sServer);
     82  CFG_GET_USER_VAL("lobby.xpartamupp", String, sXpartamupp);
     83
     84  _xpartamuppId = sXpartamupp+std::string("@")+sServer+std::string("/CC");
     85  JID clientJid(sUsername+std::string("@")+sServer+std::string("/0ad"));
     86  JID roomJid(sRoom+std::string("@conference.")+sServer+std::string("/")+sNick);
     87
     88  // If we are connecting, use the full jid and a password
     89  // If we are registering, only use the server name
     90  if(!regOpt)
     91    _client = new Client(clientJid, sPassword);
     92  else
     93    _client = new Client(sServer);
     94
     95  _client->registerConnectionListener( this );
     96  _client->setPresence(Presence::Available, -1);
     97  _client->disco()->setVersion( "TestProg", "1.0" );
     98  _client->disco()->setIdentity( "client", "bot" );
     99  _client->setCompression(false);
     100
     101  _client->registerStanzaExtension( new GameListQuery() );
     102  _client->registerIqHandler( this, ExtGameListQuery);
     103
     104  _client->registerMessageHandler( this );
     105
     106  StringList ca;
     107  ca.push_back( "/path/to/cacert.crt" );
     108  _client->setCACerts( ca );
     109
     110  // Uncomment to see the raw stanzas
     111  //_client->logInstance().registerLogHandler( LogLevelDebug, LogAreaAll, this );
     112
     113  if (!regOpt)
     114  {
     115    // Create a Multi User Chat Room
     116    _mucRoom = new MUCRoom(_client, roomJid, this, 0);
     117    // Disable the history because its anoying
     118    _mucRoom->setRequestHistory(0, MUCRoom::HistoryMaxStanzas);
     119  }
     120  else
     121  {
     122    // Registration
     123    _registration = new Registration( _client );
     124    _registration->registerRegistrationHandler( this );
     125  }
     126}
     127
     128XmppClient::~XmppClient()
     129{
     130  DbgXMPP("XmppClient destroyed");
     131  delete _registration;
     132  delete _mucRoom;
     133  delete _client;
     134}
     135
     136// Game - script
     137ScriptInterface& XmppClient::GetScriptInterface()
     138{
     139  return m_ScriptInterface;
     140}
     141
     142//Network
     143void XmppClient::connect()
     144{
     145  _client->connect(false);
     146}
     147
     148void XmppClient::disconnect()
     149{
     150  _client->disconnect();
     151}
     152
     153void XmppClient::recv()
     154{
     155  _client->recv(1);
     156}
     157
     158/*
     159 *  MUC Handlers
     160 */
     161void XmppClient::handleMUCParticipantPresence(gloox::MUCRoom*, gloox::MUCRoomParticipant participant, const gloox::Presence& presence)
     162
     163  //std::string jid = participant.jid->full();
     164  std::string nick = participant.nick->resource();
     165  gloox::Presence::PresenceType presenceType = presence.presence();
     166  if (presenceType == Presence::Unavailable)
     167  {
     168    DbgXMPP(nick << " left the room");
     169    m_PlayerMap.erase(nick);
     170  }
     171  else
     172  {
     173    DbgXMPP(nick << " is in the room");
     174    m_PlayerMap[nick] = std::pair<std::string, int>(nick, (int)presenceType);
     175  }
     176  CreateSimpleMessage("system", "playerlist updated", "internal");
     177}
     178
     179void XmppClient::handleMUCMessage( MUCRoom*, const Message& msg, bool )
     180{
     181  DbgXMPP(msg.from().resource() << " said " << msg.body());
     182  std::string nick = msg.from().resource();
     183  std::string body = msg.body();
     184
     185  CScriptValRooted message;
     186  GetScriptInterface().Eval("({ 'type':'mucmessage'})", message);
     187  GetScriptInterface().SetProperty(message.get(), "from", nick);
     188  GetScriptInterface().SetProperty(message.get(), "text", body);
     189  PushGuiMessage(message);
     190}
     191
     192void XmppClient::handleMUCError(gloox::MUCRoom*, gloox::StanzaError err)
     193{
     194  std::string msg = StanzaErrorToString(err);
     195  CreateSimpleMessage("system", msg, "error");
     196}
     197
     198void XmppClient::handleMUCItems( MUCRoom * /*room*/, const Disco::ItemList& items )
     199{
     200  m_PlayerMap.clear();
     201
     202  // Add the received items
     203  Disco::ItemList::const_iterator it = items.begin();
     204  for( ; it != items.end(); ++it )
     205  {
     206    std::string jid = (*it)->jid().full().c_str();
     207    std::string nick = (*it)->name().c_str();
     208    m_PlayerMap[nick] = std::pair<std::string, int>(nick, Presence::Available);
     209    //printf( "%s -- %s is an item here\n", (*it)->jid().full().c_str(), (*it)->name().c_str() );
     210  }
     211  CreateSimpleMessage("system", "playerlist updated", "internal");
     212}
     213
     214/*
     215 *  Log (debug) Handler
     216 */
     217void XmppClient::handleLog( LogLevel level, LogArea area, const std::string& message )
     218{
     219  std::cout << "log: level: " <<  level << ", area: " << area << ", message: " << message << std::endl;
     220}
     221
     222/*
     223 *  IQ Handler
     224 */
     225bool XmppClient::handleIq( const IQ& iq )
     226{
     227  DbgXMPP("handleIq [" << iq.tag()->xml() << "]");
     228
     229  if(iq.subtype() == gloox::IQ::Result)
     230  {
     231    const GameListQuery* q = iq.findExtension<GameListQuery>( ExtGameListQuery );
     232    if(q)
     233    {
     234      m_GameList.clear();
     235      std::list<GameItemData*>::const_iterator it = q->gameList().begin();
     236      for(; it != q->gameList().end(); ++it)
     237      {
     238        m_GameList.push_back(**it);
     239      }
     240      CreateSimpleMessage("system", "gamelist updated", "internal");
     241    }
     242  }
     243  else if(iq.subtype() == gloox::IQ::Error)
     244  {
     245    StanzaError err = iq.error()->error();
     246    std::string msg = StanzaErrorToString(err);
     247    CreateSimpleMessage("system", msg, "error");
     248  }
     249  else
     250  {
     251    CreateSimpleMessage("system", std::string("unknown subtype : ") + iq.tag()->name(), "error");
     252  }
     253
     254  return true;
     255}
     256
     257/*
     258 *  Connection Handlers
     259 */
     260void XmppClient::onConnect()
     261{
     262  if (_mucRoom)
     263  {
     264    CreateSimpleMessage("system", "connected");
     265    _mucRoom->join();
     266    //_mucRoom->getRoomInfo();
     267    _mucRoom->getRoomItems();
     268    SendIqGetGameList();
     269  }
     270
     271  if (_registration)
     272  {
     273    _registration->fetchRegistrationFields();
     274  }
     275}
     276
     277void XmppClient::onDisconnect( ConnectionError e )
     278{
     279  // Make sure we properly leave the room so than
     280  // everything work if we decide to come back later
     281  if (_mucRoom)
     282    _mucRoom->leave();
     283
     284  if( e == ConnAuthenticationFailed )
     285    CreateSimpleMessage("system", "authentication failed", "error");
     286  else
     287    CreateSimpleMessage("system", "disconnected");
     288
     289  m_PlayerMap.clear();
     290  m_GameList.clear();
     291}
     292
     293bool XmppClient::onTLSConnect( const CertInfo& )
     294{
     295  return true;
     296}
     297
     298/*
     299 *  Requests
     300 */
     301
     302/* Request GameList from cloud */
     303void XmppClient::SendIqGetGameList()
     304{
     305  JID xpartamuppJid(_xpartamuppId);
     306
     307  // Send IQ
     308  IQ iq(gloox::IQ::Get, xpartamuppJid);
     309  iq.addExtension( new GameListQuery() );
     310  DbgXMPP("SendIqGetGameList [" << iq.tag()->xml() << "]");
     311  _client->send(iq);
     312}
     313
     314/* Register a game */
     315void XmppClient::SendIqRegisterGame(CScriptVal data)
     316{
     317  JID xpartamuppJid(_xpartamuppId);
     318
     319  std::string name, mapName, mapSize, victoryCondition, nbp, tnbp;
     320  GetScriptInterface().GetProperty(data.get(), "name", name);
     321  GetScriptInterface().GetProperty(data.get(), "mapName", mapName);
     322  GetScriptInterface().GetProperty(data.get(), "mapSize", mapSize);
     323  GetScriptInterface().GetProperty(data.get(), "victoryCondition", victoryCondition);
     324  GetScriptInterface().GetProperty(data.get(), "nbp", nbp);
     325  GetScriptInterface().GetProperty(data.get(), "tnbp", tnbp);
     326
     327  // Send IQ
     328  GameListQuery* g = new GameListQuery();
     329  g->m_command = "register";
     330  /* This "x" fake ip will be overwritten by the ip stamp XMPP module */
     331  GameItemData *pItemData = new GameItemData(name, "x");
     332  pItemData->m_mapName = mapName;
     333  pItemData->m_mapSize = mapSize;
     334  pItemData->m_victoryCondition = victoryCondition;
     335  pItemData->m_nbp = nbp;
     336  pItemData->m_tnbp = tnbp;
     337  g->m_gameList.push_back( pItemData );
     338
     339  IQ iq(gloox::IQ::Set, xpartamuppJid);
     340  iq.addExtension( g );
     341  DbgXMPP("SendIqRegisterGame [" << iq.tag()->xml() << "]");
     342  _client->send(iq);
     343}
     344
     345/* Unregister a game */
     346void XmppClient::SendIqUnregisterGame(std::string name)
     347{
     348  JID xpartamuppJid(_xpartamuppId);
     349
     350  // Send IQ
     351  GameListQuery* g = new GameListQuery();
     352  g->m_command = "unregister";
     353  g->m_gameList.push_back( new GameItemData(name) );
     354
     355  IQ iq(gloox::IQ::Set, xpartamuppJid);
     356  iq.addExtension( g );
     357  DbgXMPP("SendIqUnregisterGame [" << iq.tag()->xml() << "]");
     358  _client->send(iq);
     359}
     360
     361/*
     362 *  Registration
     363 */
     364void XmppClient::handleRegistrationFields( const JID& /*from*/, int fields, std::string )
     365{
     366  RegistrationFields vals;
     367  vals.username = _username;
     368  vals.password = _password;
     369  _registration->createAccount( fields, vals );
     370}
     371
     372void XmppClient::handleRegistrationResult( const JID& /*from*/, RegistrationResult result )
     373{
     374  if (result == gloox::RegistrationSuccess)
     375  {
     376    CreateSimpleMessage("system", "registered");
     377  }
     378  else
     379  {
     380    std::string msg;
     381#define CASE(X, Y) case X: msg = Y; break;
     382    switch(result)
     383    {
     384      CASE(RegistrationNotAcceptable, "Registration not acceptable")
     385      CASE(RegistrationConflict, "Registration conflict")
     386      CASE(RegistrationNotAuthorized, "Registration not authorized")
     387      CASE(RegistrationBadRequest, "Registration bad request")
     388      CASE(RegistrationForbidden, "Registration forbidden")
     389      CASE(RegistrationRequired, "Registration required")
     390      CASE(RegistrationUnexpectedRequest, "Registration unexpected request")
     391      CASE(RegistrationNotAllowed, "Registration not allowed")
     392      default: msg = "Registration unknown error";
     393    }
     394#undef CASE
     395    CreateSimpleMessage("system", msg, "error");
     396  }
     397  disconnect();
     398}
     399
     400void XmppClient::handleAlreadyRegistered( const JID& /*from*/ )
     401{
     402  DbgXMPP("the account already exists");
     403}
     404
     405void XmppClient::handleDataForm( const JID& /*from*/, const DataForm& /*form*/ )
     406{
     407  DbgXMPP("dataForm received");
     408}
     409
     410void XmppClient::handleOOB( const JID& /*from*/, const OOB& /* oob */ )
     411{
     412  DbgXMPP("OOB registration requested");
     413}
     414
     415/**
     416  * Message
     417  */
     418void XmppClient::handleMessage( const Message& msg, MessageSession * /*session*/ )
     419{
     420  DbgXMPP("type " << msg.subtype() << ", subject " << msg.subject().c_str()
     421    << ", message " << msg.body().c_str() << ", thread id " << msg.thread().c_str());
     422
     423  std::string nick = msg.from().resource();
     424  std::string body = msg.body();
     425
     426  CScriptValRooted message;
     427  GetScriptInterface().Eval("({ 'type':'message'})", message);
     428  GetScriptInterface().SetProperty(message.get(), "from", nick);
     429  GetScriptInterface().SetProperty(message.get(), "text", body);
     430  PushGuiMessage(message);
     431}
     432
     433
     434
     435/* Requests from GUI */
     436CScriptValRooted XmppClient::GUIGetPlayerList()
     437{
     438  CScriptValRooted playerList;
     439  GetScriptInterface().Eval("({})", playerList);
     440  for(std::map<std::string, std::pair<std::string, int> >::iterator it = m_PlayerMap.begin(); it != m_PlayerMap.end(); ++it)
     441  {
     442    CScriptValRooted player;
     443    GetScriptInterface().Eval("({})", player);
     444    GetScriptInterface().SetProperty(player.get(), "name", it->second.first.c_str());
     445    GetScriptInterface().SetProperty(player.get(), "presenceType", it->second.first);
     446
     447    GetScriptInterface().SetProperty(playerList.get(), it->second.first.c_str(), player);
     448  }
     449
     450  return playerList;
     451}
     452
     453CScriptValRooted XmppClient::GUIGetGameList()
     454{
     455  CScriptValRooted gameList;
     456  GetScriptInterface().Eval("([])", gameList);
     457  for(std::list<GameItemData>::iterator it = m_GameList.begin(); it !=m_GameList.end(); ++it)
     458  {
     459    CScriptValRooted game;
     460    GetScriptInterface().Eval("({})", game);
     461
     462#define ITEM(param)\
     463    GetScriptInterface().SetProperty(game.get(), #param, it->m_##param .c_str());
     464    ITEMS
     465#undef ITEM
     466
     467    GetScriptInterface().CallFunctionVoid(gameList.get(), "push", game);
     468  }
     469
     470  return gameList;
     471}
     472
     473/* Messages */
     474CScriptValRooted XmppClient::GuiPollMessage()
     475{
     476  if (m_GuiMessageQueue.empty())
     477    return CScriptValRooted();
     478
     479  CScriptValRooted r = m_GuiMessageQueue.front();
     480  m_GuiMessageQueue.pop_front();
     481  return r;
     482}
     483
     484void XmppClient::SendMUCMessage(std::string message)
     485{
     486  _mucRoom->send(message);
     487}
     488
     489void XmppClient::PushGuiMessage(const CScriptValRooted& message)
     490{
     491  ENSURE(!message.undefined());
     492
     493  m_GuiMessageQueue.push_back(message);
     494}
     495
     496void XmppClient::CreateSimpleMessage(std::string type, std::string text, std::string level)
     497{
     498  CScriptValRooted message;
     499  GetScriptInterface().Eval("({})", message);
     500  GetScriptInterface().SetProperty(message.get(), "type", type);
     501  GetScriptInterface().SetProperty(message.get(), "level", level);
     502  GetScriptInterface().SetProperty(message.get(), "text", text);
     503  PushGuiMessage(message);
     504}
     505
     506/*
     507 *  GameListQuery, custom IQ Stanza
     508 */
     509
     510GameListQuery::GameListQuery( const Tag* tag )
     511: StanzaExtension( ExtGameListQuery )
     512{
     513  if( !tag || tag->name() != "query" || tag->xmlns() != XMLNS_GAMELIST )
     514    return;
     515
     516  const Tag* c = tag->findTag( "query/game" );
     517  if (c)
     518    m_command = c->cdata();
     519
     520  const ConstTagList& l = tag->findTagList( "query/game" );
     521  ConstTagList::const_iterator it = l.begin();
     522  for( ; it != l.end(); ++it )
     523  {
     524    GameItemData *pItem = new GameItemData();
     525#define ITEM(param)\
     526    const std::string param = (*it)->findAttribute( #param ); \
     527    pItem->m_##param = param;
     528    ITEMS
     529#undef ITEM
     530    m_gameList.push_back( pItem );
     531  }
     532}
     533
     534GameListQuery::~GameListQuery()
     535{
     536  util::clearList( m_gameList );
     537}
     538
     539const std::string& GameListQuery::filterString() const
     540{
     541  static const std::string filter = "/iq/query[@xmlns='" + XMLNS_GAMELIST + "']";
     542  return filter;
     543}
     544
     545Tag* GameListQuery::tag() const
     546{
     547  Tag* t = new Tag( "query" );
     548  t->setXmlns( XMLNS_GAMELIST );
     549/*
     550  RosterData::const_iterator it = m_roster.begin();
     551  for( ; it != m_roster.end(); ++it )
     552  t->addChild( (*it)->tag() );
     553*/
     554
     555  // register / unregister command
     556  if(!m_command.empty())
     557    t->addChild(new Tag("command", m_command));
     558
     559  std::list<GameItemData*>::const_iterator it = m_gameList.begin();
     560  for( ; it != m_gameList.end(); ++it )
     561    t->addChild( (*it)->tag() );
     562
     563  return t;
     564}
     565
     566StanzaExtension* GameListQuery::clone() const
     567{
     568  GameListQuery* q = new GameListQuery();
     569
     570  return q;
     571}
     572
     573const std::list<GameItemData*>& GameListQuery::gameList() const
     574{
     575  return m_gameList;
     576}
  • 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  gloox::Tag* tag() const
     28  {
     29    gloox::Tag* i = new gloox::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#if OS_WIN
     5// Prevent gloox from pulling in windows.h (which causes conflicts)
     6// and defines what is necessary in order to compile the lobby
     7#define _WINDOWS_
     8
     9    //Taken from WinDef.h
     10#define CONST               const
     11typedef unsigned char UCHAR;
     12typedef UCHAR *PUCHAR;
     13typedef unsigned long ULONG;
     14typedef ULONG *PULONG;
     15#define OPTIONAL
     16
     17    // Taken from WinNT.h
     18#define VOID void
     19typedef char CHAR;
     20typedef long LONG;
     21typedef wchar_t WCHAR;
     22typedef __nullterminated WCHAR *NWPSTR, *LPWSTR, *PWSTR;
     23typedef __nullterminated CHAR *NPSTR, *LPSTR, *PSTR;
     24typedef __nullterminated CONST WCHAR *LPCWSTR, *PCWSTR;
     25typedef __nullterminated CONST CHAR *LPCSTR, *PCSTR;
     26typedef unsigned char       BYTE;
     27typedef BYTE  BOOLEAN;   
     28typedef BOOLEAN *PBOOLEAN;   
     29typedef void *PVOID;
     30
     31    //Taken from BaseTsd.h
     32#if defined(_WIN64)
     33    typedef unsigned __int64 ULONG_PTR, *PULONG_PTR;
     34#else
     35    typedef _W64 unsigned long ULONG_PTR, *PULONG_PTR;
     36#endif
     37#include "specstrings.h"
     38
     39#endif
     40
     41//network
     42#include <gloox/jid.h>
     43#include <gloox/client.h>
     44#include <gloox/mucroom.h>
     45#include <gloox/message.h>
     46
     47#include <gloox/messagehandler.h>
     48#include <gloox/presencehandler.h>
     49#include <gloox/mucroomhandler.h>
     50#include <gloox/loghandler.h>
     51#include <gloox/connectionlistener.h>
     52#include <gloox/registration.h>
     53
     54#include <gloox/iq.h>
     55#include <gloox/iqhandler.h>
     56
     57//game - script
     58#include <deque>
     59#include "scriptinterface/ScriptVal.h"
     60
     61//Global Gamelist Extension
     62#define ExtGameListQuery 1403
     63const std::string XMLNS_GAMELIST = "jabber:iq:gamelist";
     64
     65//Game - script
     66class ScriptInterface;
     67class GameItemData;
     68
     69class XmppClient : public gloox::ConnectionListener, public gloox::MUCRoomHandler, public gloox::IqHandler, public gloox::LogHandler, public gloox::RegistrationHandler, public gloox::MessageHandler
     70{
     71private:
     72  //Game - script
     73  ScriptInterface& m_ScriptInterface;
     74  //Components
     75  gloox::Client* _client;
     76  gloox::MUCRoom* _mucRoom;
     77  gloox::Registration* _registration;
     78  //Account infos
     79  std::string _username;
     80  std::string _password;
     81  std::string _nick;
     82  std::string _xpartamuppId;
     83
     84public:
     85  //Basic
     86  XmppClient(ScriptInterface& scriptInterface, std::string sUsername, std::string sPassword, std::string sRoom, std::string sNick, bool regOpt = false);
     87  virtual ~XmppClient();
     88
     89  //Network
     90  void connect();
     91  void disconnect();
     92  void recv();
     93  void SendIqGetGameList();
     94  void SendIqRegisterGame(CScriptVal data);
     95  void SendIqUnregisterGame(std::string name);
     96
     97  CScriptValRooted GUIGetPlayerList();
     98  CScriptValRooted GUIGetGameList();
     99
     100  //Script
     101  ScriptInterface& GetScriptInterface();
     102
     103protected:
     104  /* Xmpp handlers */
     105  /* MUC handlers */
     106  virtual void handleMUCParticipantPresence(gloox::MUCRoom*, gloox::MUCRoomParticipant, const gloox::Presence&);
     107  virtual bool handleMUCRoomCreation(gloox::MUCRoom*) {return false;}
     108  virtual void handleMUCSubject(gloox::MUCRoom*, const std::string&, const std::string&) {}
     109  virtual void handleMUCInviteDecline(gloox::MUCRoom*, const gloox::JID&, const std::string&) {}
     110  virtual void handleMUCError(gloox::MUCRoom*, gloox::StanzaError);
     111  virtual void handleMUCInfo(gloox::MUCRoom*, int, const std::string&, const gloox::DataForm*) {}
     112  virtual void handleMUCItems(gloox::MUCRoom*, const std::list<gloox::Disco::Item*, std::allocator<gloox::Disco::Item*> >&);
     113  virtual void handleMUCMessage(gloox::MUCRoom* room, const gloox::Message& msg, bool priv);
     114
     115  /* Log handler */
     116  virtual void handleLog(gloox::LogLevel level, gloox::LogArea area, const std::string& message);
     117
     118  /* ConnectionListener handlers*/
     119  virtual void onConnect();
     120  virtual void onDisconnect(gloox::ConnectionError e);
     121  virtual bool onTLSConnect(const gloox::CertInfo& info);
     122
     123  /* Iq Handlers */
     124  virtual bool handleIq(const gloox::IQ& iq);
     125  virtual void handleIqID(const gloox::IQ&, int) {}
     126
     127  /* Registration Handlers */
     128  virtual void handleRegistrationFields(const gloox::JID& /*from*/, int fields, std::string instructions );
     129  virtual void handleRegistrationResult(const gloox::JID& /*from*/, gloox::RegistrationResult result);
     130  virtual void handleAlreadyRegistered(const gloox::JID& /*from*/);
     131  virtual void handleDataForm(const gloox::JID& /*from*/, const gloox::DataForm& /*form*/);
     132  virtual void handleOOB(const gloox::JID& /*from*/, const gloox::OOB& oob);
     133
     134  /* Message Handler */
     135  virtual void handleMessage(const gloox::Message& msg, gloox::MessageSession * session);
     136
     137  /* Messages */
     138public:
     139  CScriptValRooted GuiPollMessage();
     140  void SendMUCMessage(std::string message);
     141protected:
     142  void PushGuiMessage(const CScriptValRooted& message);
     143  void CreateSimpleMessage(std::string type, std::string text, std::string level = "standard");
     144
     145private:
     146  /// Map of players
     147  std::map<std::string, std::pair<std::string, int> > m_PlayerMap;
     148  /// List of games
     149  std::list< GameItemData > m_GameList;
     150  /// Queue of messages
     151  std::deque<CScriptValRooted> m_GuiMessageQueue;
     152};
     153
     154class GameListQuery : public gloox::StanzaExtension
     155{
     156  friend class XmppClient;
     157public:
     158  GameListQuery(const gloox::Tag* tag = 0);
     159
     160  ~GameListQuery();
     161
     162  // reimplemented from StanzaExtension
     163  virtual const std::string& filterString() const;
     164
     165  // reimplemented from StanzaExtension
     166  virtual StanzaExtension* newInstance(const gloox::Tag* tag) const
     167  {
     168    return new GameListQuery( tag );
     169  }
     170
     171  // reimplemented from StanzaExtension
     172  virtual gloox::Tag* tag() const;
     173
     174  // reimplemented from StanzaExtension
     175  virtual gloox::StanzaExtension* clone() const;
     176
     177  const std::list<GameItemData*>& gameList() const;
     178
     179private:
     180  std::string m_command;
     181  std::list<GameItemData*> m_gameList;
     182};
     183
     184extern XmppClient *g_XmppClient;
     185
     186#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;
     
    7985    default:
    8086        error("Unexpected 'type' in gamesetup init: "+attribs.type);
    8187    }
     88
     89    switch (attribs.source)
     90    {
     91    case "mainmenu":
     92        g_Source = "mainmenu";
     93        break;
     94    case "lobby":
     95        g_Source = "lobby";
     96        break;
     97    default:
     98        error("Unrecognised source : " + attribs.source);
     99    }
     100   
     101        if (attribs.serverName)
     102        g_ServerName = attribs.serverName;
     103
     104    // Init the Cancel Button caption and tooltip
     105    var cancelButton = getGUIObjectByName("cancelGame");
     106    if(g_Source != "lobby")
     107    {
     108        cancelButton.caption = "Main menu";
     109        cancelButton.tooltip = "Return to the main menu."
     110    }
     111    else
     112    {
     113        cancelButton.caption = "Quit";
     114        cancelButton.tooltip = "Return to the lobby."
     115    }
     116 
    82117}
    83118
    84119// Called after the map data is loaded and cached
     
    168203                updateGameAttributes();
    169204            }
    170205        };
     206        mapSize.selected = 0;
    171207
    172208        getGUIObjectByName("revealMap").onPress = function()
    173209        {   // Update attributes so other players can see change
     
    295331        {
    296332        case "disconnected":
    297333            Engine.DisconnectNetworkGame();
     334            if (isServerOnLobby()) Engine.SendUnregisterGame(g_ServerName);
    298335            Engine.PopGuiPage();
    299336            reportDisconnect(message.reason);
    300337            break;
     
    333370        // Update the player list
    334371        g_PlayerAssignments = message.hosts;
    335372        updatePlayerList();
     373
     374        if (isServerOnLobby())
     375        {
     376            sendRegisterGameStanza();
     377        }
    336378        break;
    337379
    338380    case "start":
     381        if (g_Source == "lobby") Engine.StopXmppClient();
    339382        Engine.SwitchGuiPage("page_loading.xml", {
    340383            "attribs": g_GameAttributes,
    341384            "isNetworked" : g_IsNetworked,
     
    9841027    if (g_IsNetworked)
    9851028    {
    9861029        Engine.SetNetworkGameAttributes(g_GameAttributes);
     1030        if (isServerOnLobby() && g_LoadingState >= 2)
     1031        {
     1032            sendRegisterGameStanza();
     1033        }
    9871034    }
    9881035    else
    9891036    {
     
    13021349    return false;
    13031350}
    13041351
     1352function isServerOnLobby()
     1353{
     1354    return (g_IsController && g_Source == "lobby") ? true : false;
     1355}
    13051356
     1357function sendRegisterGameStanza()
     1358{
     1359    var selectedMapSize = getGUIObjectByName("mapSize").selected;
     1360    var selectedVictoryCondition = getGUIObjectByName("victoryCondition").selected;
    13061361
     1362    var mapSize = getGUIObjectByName("mapSize").list_data[selectedMapSize];
     1363    var victoryCondition = getGUIObjectByName("victoryCondition").list[selectedVictoryCondition];
    13071364
     1365    var numberOfPlayers = 0;
     1366    for (var guid in g_PlayerAssignments)
     1367    {   
     1368        numberOfPlayers++;
     1369    }
     1370
     1371    var nbp = numberOfPlayers ? numberOfPlayers : 1;
     1372    var tnbp = g_GameAttributes.settings.PlayerData.length;
     1373
     1374    gameData = {
     1375        "name":g_ServerName,
     1376        "mapName":g_GameAttributes.map,
     1377        "mapSize":mapSize,
     1378        "victoryCondition":victoryCondition,
     1379        "nbp":nbp,
     1380        "tnbp":tnbp
     1381    };
     1382    Engine.SendRegisterGame(gameData);
     1383}
  • 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

     
    248248            style="StoneButton"
    249249            size="100%-164 100%-52 100%-24 100%-24"
    250250            tooltip_style="onscreenToolTip"
    251             tooltip="Return to the main menu."
    252251        >
    253             Main menu
    254252            <action on="Press">
    255253                <![CDATA[
    256254                    cancelSetup();
     255                    if(isServerOnLobby()) Engine.SendUnregisterGame(g_ServerName);
    257256                    Engine.PopGuiPage();
    258257                ]]>
    259258            </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/lobby/styles.xml

     
     1<?xml version="1.0" encoding="utf-8"?>
     2
     3<styles>
     4    <style name="ChatPanel"
     5        buffer_zone="5"
     6        font="serif-13"
     7        scrollbar="true"
     8        scrollbar_style="wheatScrollBar"
     9        scroll_bottom="true"
     10        textcolor="white"
     11        textcolor_selected="gold"
     12        text_align="left"
     13        text_valign="center"
     14    />
     15
     16    <style name="MapDescription"
     17        buffer_zone="8"
     18        font="serif-12"
     19        scrollbar="true"
     20        scrollbar_style="wheatScrollBar"
     21        scroll_bottom="true"
     22        textcolor="white"
     23        text_align="left"
     24        text_valign="top"
     25    />
     26
     27    <style  name="SmallStoneDropDown"
     28        dropdown_buffer="1"
     29        font="serif-14"
     30        textcolor="white"
     31        text_align="center"
     32        text_valign="center"
     33
     34        sprite="StoneButton"
     35        sprite_over="StoneButtonOver"
     36        sprite_pressed="StoneButtonGlow"
     37
     38        button_width="15"
     39        sprite2="StoneArrowDn"
     40        sprite2_pressed="StoneArrowDnOver"
     41
     42        buffer_zone="5"
     43        dropdown_size="200"
     44        sprite_list="BackgroundListBox"
     45        sprite_selectarea="BackgroundSelectArea"
     46        textcolor_selected="white"
     47
     48        scrollbar="true"
     49        scrollbar_style="wheatScrollBar"
     50    />
     51
     52</styles>
  • binaries/data/mods/public/gui/lobby/lobby.js

     
     1var g_ChatMessages = [];
     2var g_Name = "unknown Bob";
     3var g_GameList = {};
     4
     5////////////////////////////////////////////////////////////////////////////////////////////////
     6var g_mapSizes = {};
     7
     8function init(attribs)
     9{
     10    if (attribs.name) g_Name = attribs.name;
     11    else error("No name");
     12
     13    g_mapSizes = initMapSizes();
     14    g_mapSizes.names.push("Any");
     15    g_mapSizes.tiles.push("");
     16
     17    var mapSizeFilter = getGUIObjectByName("mapSizeFilter");
     18    mapSizeFilter.list = g_mapSizes.names;
     19    mapSizeFilter.list_data = g_mapSizes.tiles;
     20
     21    var playersNumberFilter = getGUIObjectByName("playersNumberFilter");
     22    playersNumberFilter.list = [2,3,4,5,6,7,8,"Any"];
     23    playersNumberFilter.list_data = [2,3,4,5,6,7,8,""];
     24
     25    var victoryConditionFilter = getGUIObjectByName("victoryConditionFilter");
     26    victoryConditionFilter.list = ["Conquest","Any"];
     27    victoryConditionFilter.list_data = ["conquest",""];
     28}
     29
     30////////////////////////////////////////////////////////////////////////////////////////////////
     31// Xmpp client connection management
     32////////////////////////////////////////////////////////////////////////////////////////////////
     33
     34
     35function lobbyStop()
     36{
     37    Engine.StopXmppClient();
     38}
     39
     40function lobbyConnect()
     41{
     42    Engine.ConnectXmppClient();
     43}
     44
     45function lobbyDisconnect()
     46{
     47    Engine.DisconnectXmppClient();
     48}
     49
     50////////////////////////////////////////////////////////////////////////////////////////////////
     51// Server requests functions
     52////////////////////////////////////////////////////////////////////////////////////////////////
     53
     54function lobbyRefreshGameList()
     55{
     56    Engine.SendGetGameList();
     57}
     58
     59////////////////////////////////////////////////////////////////////////////////////////////////
     60// Update functions
     61////////////////////////////////////////////////////////////////////////////////////////////////
     62
     63var g_mapSizeFilter = "";
     64var g_playersNumberFilter = "";
     65var g_victoryConditionFilter = "";
     66var g_hideFullFilter = false;
     67
     68function resetFilters()
     69{
     70    g_mapSizeFilter = "";
     71    g_playersNumberFilter = "";
     72    g_victoryConditionFilter = "";
     73    g_hideFullFilter = false;
     74    getGUIObjectByName("mapSizeFilter").selected = -1;
     75    getGUIObjectByName("playersNumberFilter").selected = -1;
     76    getGUIObjectByName("victoryConditionFilter").selected = -1;
     77    getGUIObjectByName("hideFullFilter").checked = false;
     78}
     79
     80function setFilters()
     81{
     82    var mapSizeFilter = getGUIObjectByName("mapSizeFilter");
     83    var playersNumberFilter = getGUIObjectByName("playersNumberFilter");
     84    var victoryConditionFilter = getGUIObjectByName("victoryConditionFilter");
     85    var hideFullFilter = getGUIObjectByName("hideFullFilter");
     86
     87    g_mapSizeFilter = mapSizeFilter.selected >= 0 ? mapSizeFilter.list_data[mapSizeFilter.selected] : "";
     88    g_playersNumberFilter = playersNumberFilter.selected >=0 ? playersNumberFilter.list_data[playersNumberFilter.selected] : "";
     89    g_victoryConditionFilter = victoryConditionFilter.selected >= 0 ? victoryConditionFilter.list_data[victoryConditionFilter.selected] : "";
     90    g_hideFullFilter = hideFullFilter.checked ? true : false;
     91}
     92
     93function displayGame(g)
     94{
     95    if(g_mapSizeFilter != "" && g.mapSize != g_mapSizeFilter) return false;
     96    if(g_victoryConditionFilter != "" && g.victoryCondition != g_victoryConditionFilter) return false;
     97    if(g_playersNumberFilter != "" && g.tnbp != g_playersNumberFilter) return false;
     98    if(g_hideFullFilter && g.tnbp == g.nbp) return false;
     99
     100    return true;
     101}
     102
     103function updateGameList()
     104{
     105    var gamesBox = getGUIObjectByName("gamesBox");
     106    var gameList = Engine.GetGameList();
     107    //Store the game whole game list data so that we can access it later
     108    //to update the game info panel.
     109    g_GameList = gameList;
     110
     111    var list_name = [];
     112    var list_ip = [];
     113    var list_mapName = [];
     114    var list_mapSize = [];
     115    var list_victoryCondition = [];
     116    var list_nPlayers = [];
     117    var list = [];
     118    var list_data = [];
     119
     120    var c = 0;
     121    for each (g in gameList)
     122    {
     123        if(displayGame(g))
     124        {
     125            list_name.push(toTitleCase(g.name));
     126            list_ip.push(g.ip);
     127            list_mapName.push(toTitleCase(g.mapName));
     128            list_mapSize.push(tilesToMapSize(g.mapSize));
     129            list_victoryCondition.push(toTitleCase(g.victoryCondition));
     130            list_nPlayers.push(g.nbp + "/" +g.tnbp);
     131            list.push(g.name);
     132            list_data.push(c);
     133        }
     134        c++;
     135    }
     136
     137    gamesBox.list_name = list_name;
     138    gamesBox.list_ip = list_ip;
     139    gamesBox.list_mapName = list_mapName;
     140    gamesBox.list_mapSize = list_mapSize;
     141    gamesBox.list_victoryCondition = list_victoryCondition;
     142    gamesBox.list_nPlayers = list_nPlayers;
     143    gamesBox.list = list;
     144    gamesBox.list_data = list_data;
     145
     146    if (gamesBox.selected >= gamesBox.list_name.length)
     147        gamesBox.selected = -1;
     148}
     149
     150function updatePlayerList()
     151{
     152    var playersBox = getGUIObjectByName("playersBox")
     153
     154        var playerList = Engine.GetPlayerList();
     155    var playerListNames = [ player.name for each (player in playerList) ];
     156
     157    playersBox.list = playerListNames;
     158    if (playersBox.selected >= playersBox.list.length)
     159        playersBox.selected = -1;
     160}
     161
     162function selectGame(selected)
     163{
     164    if(selected == -1)
     165    {
     166        // Hide the game info panel if not game is selected
     167        getGUIObjectByName("gameInfo").hidden = true;
     168        getGUIObjectByName("gameInfoEmpty").hidden = false;
     169        return;
     170    }
     171
     172    // Show the game info panel if a game is selected
     173    getGUIObjectByName("gameInfo").hidden = false;
     174    getGUIObjectByName("gameInfoEmpty").hidden = true;
     175
     176    //Get the selected map's name
     177    var gamesBox = getGUIObjectByName("gamesBox");
     178    var g = gamesBox.list_data[selected];
     179    var name = g_GameList[g].mapName;
     180    getGUIObjectByName("sgMapName").caption = toTitleCase(name);
     181
     182    var mapData = null;
     183
     184    //Search the selectep map in the scenarios
     185    var mapFiles = getXMLFileList("maps/scenarios/");
     186    for (var i = 0; i < mapFiles.length; ++i)
     187    {
     188        var file = mapFiles[i];
     189        if(name == file)
     190        {
     191            mapData = Engine.LoadMapSettings("maps/scenarios/"+file);
     192            break;
     193        }
     194    }
     195
     196    //Search the selectep map in the scenarios
     197    if(!mapData)
     198    {
     199        var mapFiles = getJSONFileList("maps/random/");
     200        for (var i = 0; i < mapFiles.length; ++i)
     201        {
     202            var file = mapFiles[i];
     203            if(name == file)
     204            {
     205                mapData = parseJSONData("maps/random/"+file+".json");
     206            }
     207        }
     208    }
     209
     210    if(!mapData)
     211    {
     212        log("Map '"+ name +"'  not found");
     213    }
     214
     215    // Load the description from the map file, if there is one, and display it
     216    var mapSettings = (mapData && mapData.settings ? deepcopy(mapData.settings) : {});
     217    var description = mapSettings.Description || "Sorry, no description available.";
     218    getGUIObjectByName("sgMapDescription").caption = description;
     219
     220    // Set the number of players, the map size and the victory condition text boxes
     221    getGUIObjectByName("sgNbPlayers").caption = g_GameList[g].nbp + "/" + g_GameList[g].tnbp;
     222    getGUIObjectByName("sgMapSize").caption = tilesToMapSize(g_GameList[g].mapSize);
     223    getGUIObjectByName("sgVictoryCondition").caption = toTitleCase(g_GameList[g].victoryCondition);
     224
     225}
     226
     227function joinSelectedGame()
     228{
     229    var gamesBox = getGUIObjectByName("gamesBox");
     230    if (gamesBox.selected >= 0)
     231    {
     232        var g = gamesBox.list_data[gamesBox.selected];
     233        var sname = g_Name;
     234        var sip = g_GameList[g].ip;
     235        // Open Multiplayer connection window with join option.
     236        Engine.PushGuiPage("page_gamesetup_mp.xml", { multiplayerGameType: "join", source: "lobby", name: sname, ip: sip });   
     237    }
     238}
     239
     240////////////////////////////////////////////////////////////////////////////////////////////////
     241// Utils
     242////////////////////////////////////////////////////////////////////////////////////////////////
     243function tilesToMapSize(tiles)
     244{
     245    var s = g_mapSizes.tiles.indexOf(Number(tiles));
     246    return s != -1 ? g_mapSizes.names[s].split(" ")[0] : "?";
     247}
     248
     249function twoDigits(n)
     250{
     251    return n < 10 ? "0" + n : n;
     252}
     253
     254////////////////////////////////////////////////////////////////////////////////////////////////
     255// GUI event handlers
     256////////////////////////////////////////////////////////////////////////////////////////////////
     257
     258function onTick()
     259{
     260    //Wake up XmppClient
     261    Engine.RecvXmppClient();
     262
     263    //Receive messages
     264    while (true)
     265    {
     266        var message = Engine.LobbyGuiPollMessage();
     267        if (!message)
     268            break;
     269        switch (message.type)
     270        {
     271            case "mucmessage":
     272                addChatMessage({ "from": message.from, "text": message.text , "color": "50 50 50"});
     273                break;
     274            case "system":
     275                switch (message.level)
     276                {
     277                    case "standard":
     278                        addChatMessage({ "from": "system", "text": message.text, "color": "0 150 0" });
     279                        break;
     280                    case "error":
     281                        addChatMessage({ "from": "system", "text": message.text, "color": "150 0 0" });
     282                        if (message.text == "disconnected")
     283                        {
     284                                updateGameList();
     285                                updatePlayerList();
     286                        }
     287                        break;
     288                    case "internal":
     289                        switch (message.text)
     290                        {
     291                            case "gamelist updated":
     292                                updateGameList();
     293                                var t = new Date(Date.now());
     294                                var time = twoDigits(t.getUTCHours())+":"+twoDigits(t.getUTCMinutes())+":"+twoDigits(t.getUTCSeconds());
     295                                getGUIObjectByName("updateStatusText").caption = "Updated at " + time;
     296                                break;
     297                            case "playerlist updated":
     298                                updatePlayerList();
     299                                break;
     300                        }
     301                        break
     302                }
     303                break;
     304            default:
     305                error("Unrecognised message type "+message.type);
     306        }
     307    }
     308}
     309
     310/* Messages */
     311function submitChatInput()
     312{
     313    var input = getGUIObjectByName("chatInput");
     314    var text = input.caption;
     315    if (text.length)
     316    {
     317        Engine.LobbySendMessage(text);
     318        input.caption = "";
     319    }
     320}
     321
     322function handleMessage(message)
     323{
     324
     325}
     326
     327function pp(txt)
     328{
     329    addChatMessage({"from":"debug", "color":"200 0 0", "text":txt});
     330}
     331
     332function addChatMessage(msg)
     333{
     334    var from = escapeText(msg.from);
     335    var text = escapeText(msg.text);
     336    var color = msg.color;
     337
     338    var formatted = '[font="serif-bold-13"]<[color="'+ color +'"]' + from + '[/color]>[/font] ' + text;
     339    g_ChatMessages.push(formatted);
     340    getGUIObjectByName("chatText").caption = g_ChatMessages.join("\n");
     341}
  • binaries/data/mods/public/gui/lobby/lobby.xml

     
     1<?xml version="1.0" encoding="utf-8"?>
     2
     3<objects>
     4  <script file="gui/lobby/lobby.js"/>
     5
     6  <script file="gui/common/functions_global_object.js"/>
     7  <script file="gui/common/functions_utility.js"/>
     8
     9  <object type="image" style="StoneWindow" size="0 0 100% 100%" name="lobbyWindow">
     10
     11    <object style="TitleText" type="text" size="50%-128 0%+4 50%+128 36">
     12      Multiplayer Lobby
     13    </object>
     14
     15    <action on="Tick">
     16      onTick();
     17    </action>
     18
     19    <object size="25 50 100%-25 0%+400">
     20      <object name="gameInfoEmpty" size="0 0 340 100%-10" type="image" sprite="BackgroundIndentFillDark" hidden="false">
     21        <object size="50%-110 50%-50 50%+110 50%+50" type="image" sprite="productLogo"/>
     22      </object>
     23      <object name="gameInfo" size="0 0 340 100%-10" type="image" sprite="BackgroundIndentFillDark" hidden="true">
     24        <object name="sgMapName" size="170 10 100%-10 30" type="text" style="TitleText"/>
     25        <object name="sgMapPicture" size="10 10 160 160" type="image" sprite="BackgroundIndentFillDark"/>
     26
     27    <!-- First Column -->
     28    <object size="170 40 250 160">
     29      <!-- Number of Players-->
     30      <object size="0 0 100% 32">
     31        <object size="0 0 100% 100%" type="text" style="LeftLabelText">Players:</object>
     32      </object>
     33
     34      <object size="0 32 100% 64">
     35        <object size="0 0 100% 100%" type="text" style="LeftLabelText">Map size:</object>
     36      </object>
     37
     38      <object size="0 64 100% 96">
     39        <object size="0 0 100% 100%" type="text" style="LeftLabelText">Victory:</object>
     40      </object>
     41    </object>
     42
     43    <!-- Second Column -->
     44    <object size="250 40 100%-10 160">
     45      <!-- Number of Players-->
     46      <object size="0 0 100% 32">
     47        <object name="sgNbPlayers" size="0 0 100% 100%" type="text" style="LeftLabelText"/>
     48      </object>
     49
     50      <object size="0 32 100% 64">
     51        <object name="sgMapSize" size="0 0 100% 100%" type="text" style="LeftLabelText"/>
     52      </object>
     53
     54      <object size="0 64 100% 96">
     55        <object name="sgVictoryCondition" size="0 0 100% 100%" type="text" style="LeftLabelText"/>
     56      </object>
     57    </object>
     58
     59    <object type="image" sprite="BackgroundIndentFillDark" size="10 170 100%-10 100%-40">
     60      <object name="sgMapDescription" type="text" style="MapDescription" size="0 0 100% 100%"/>
     61    </object>
     62
     63        <object type="button" style="StoneButton" size="100%-100 100%-30 100%-10 100%-10">
     64          Join
     65          <action on="Press">
     66       <![CDATA[
     67             joinSelectedGame();
     68            ]]>
     69          </action>
     70        </object>
     71
     72      </object>
     73
     74      <object name="gamesBox"
     75        style="StoneList"
     76        type="olist"
     77        size="350 0 100% 100%-50"
     78        tooltip_style="pgFloatingToolTip"
     79        sprite_heading="colour:0 0 0 255"
     80        textcolor="210 100 0 255">
     81        <action on="SelectionChange"> selectGame(this.selected);</action>
     82        <def id="name" heading="Name" color="0 60 0" width="200"/>
     83        <def id="ip" heading="IP" color="0 128 128" width="170"/>
     84        <def id="mapName" heading="Map name" color="128 128 128" width="150"/>
     85        <def id="mapSize" heading="Map size" color="128 128 128" width="120"/>
     86        <def id="victoryCondition" heading="Victory condition" color="0 128 128" width="140"/>
     87        <def id="nPlayers" heading="Players" color="0 128 128" width="30"/>
     88      </object>
     89
     90      <object name="filterPanel" size="380 100%-140 870 100%-10" type="image" sprite="BackgroundIndentFillDark" hidden="true">
     91        <object type="text" size="10 10 110 30" text_align="left" textcolor="white">Map size :</object>
     92        <object name="mapSizeFilter"
     93          type="dropdown"
     94          style="SmallStoneDropDown"
     95          size="120 10 310 30">
     96        <action on="SelectionChange"><!--selectMapSize(this.list_data[this.selected]);--></action>
     97        </object>
     98
     99        <object type="text" size="10 40 150 60" text_align="left" textcolor="white">Number of players :</object>
     100        <object name="playersNumberFilter"
     101          type="dropdown"
     102          style="SmallStoneDropDown"
     103          size="160 40 310 60">
     104        <action on="SelectionChange"></action>
     105        </object>
     106
     107        <object type="text" size="10 70 150 90" text_align="left" textcolor="white">Victory condition :</object>
     108        <object name="victoryConditionFilter"
     109          type="dropdown"
     110          style="SmallStoneDropDown"
     111          size="160 70 310 90">
     112        <action on="SelectionChange"></action>
     113        </object>
     114
     115        <object type="text" size="10 100 150 120" text_align="left" textcolor="white">Hide full games :</object>
     116        <object name="hideFullFilter"
     117          type="checkbox"
     118          style="StoneCrossBox"
     119          size="160 105 310 120">
     120        <action on="SelectionChange"></action>
     121        </object>
     122
     123        <object type="button" style="StoneButton" size="100%-230 100%-30 100%-130 100%-10">
     124          Reset
     125          <action on="Press"> <![CDATA[resetFilters();updateGameList();]]></action>
     126        </object>
     127
     128        <object type="button" style="StoneButton" size="100%-110 100%-30 100%-10 100%-10">
     129          Filter
     130          <action on="Press"> <![CDATA[setFilters();updateGameList();]]></action>
     131        </object>
     132
     133      </object>
     134
     135      <object name="gamesBar" size="350 100%-40 100% 100%">
     136        <object type="button" style="StoneButton" size="0 0 20 20">
     137          >>
     138          <action on="Press"><![CDATA[
     139          if(this.caption == ">>")
     140          {
     141            this.caption = "<<";
     142            getGUIObjectByName("filterPanel").hidden = false;
     143            getGUIObjectByName("gamesBox").size="350 0 100% 100%-150";
     144          }
     145          else
     146          {
     147            this.caption = ">>";
     148            getGUIObjectByName("filterPanel").hidden = true;
     149            getGUIObjectByName("gamesBox").size="350 0 100% 100%-50";
     150          }
     151          ]]>
     152          </action>
     153        </object>
     154
     155    <object name="updateStatusText" size="100%-440 0 100%-240 20" type="text" style="RightLabelText"/>
     156
     157        <object type="button" style="StoneButton" size="100%-220 0 100%-120 20">
     158          Update
     159          <action on="Press"> lobbyRefreshGameList();</action>
     160        </object>
     161
     162        <object type="button" style="StoneButton" size="100%-100 0 100% 20">
     163          Host Game
     164          <action on="Press">
     165        <![CDATA[
     166            var sname = g_Name;
     167            // Open Multiplayer connection window with host option.
     168            Engine.PushGuiPage("page_gamesetup_mp.xml", { multiplayerGameType: "host", source: "lobby", name: sname });
     169        ]]>
     170      </action>
     171        </object>
     172
     173      </object>
     174    </object>
     175
     176    <object size="25 0%+400 100%-25 100%-25">
     177      <object name="playersBox"
     178        style="StoneList"
     179        type="list"
     180        size="100%-200 0 100% 100%-40"
     181        tooltip_style="pgFloatingToolTip"
     182        tooltip="Players.">
     183      </object>
     184
     185      <object name="chatPanel" size="0 0 100%-220 100%-10" type="image" sprite="BackgroundIndentFillDark">
     186        <object name="chatText" size="3 1 100%-1 100%-25" type="text" style="ChatPanel"/>
     187        <object name="chatInput" size="2 100%-23 100%-66 100%-3" type="input" style="StoneInput">
     188          <action on="Press">submitChatInput();</action>
     189        </object>
     190
     191        <object size="100%-65 100%-25 100%-1 100%" type="button" style="StoneButton">
     192          Send
     193          <action on="Press">submitChatInput();</action>
     194        </object>
     195      </object>
     196    </object>
     197
     198      <object name="navBar" size="20 25 100%-20 45">
     199        <object type="button" style="StoneButton" size="100%-340 0 100%-240 20">
     200          Connect
     201          <action on="Press">lobbyConnect();</action>
     202        </object>
     203
     204        <object type="button" style="StoneButton" size="100%-220 0 100%-120 20">
     205          Disconnect
     206          <action on="Press">lobbyDisconnect();</action>
     207        </object>
     208
     209        <object type="button" style="StoneButton" size="100%-100 0 100% 20">
     210          Main Menu
     211          <action on="Press">
     212          <![CDATA[
     213          lobbyStop();
     214          Engine.PopGuiPage();
     215          ]]>
     216          </action>
     217        </object>
     218      </object>
     219
     220  </object>
     221</objects>
  • binaries/data/mods/public/gui/lobby/prelobby.js

     
     1var g_LobbyIsConnecting = false;
     2var g_InitialUsername = "";
     3var g_InitialPassword = "";
     4
     5function init()
     6{
     7    g_InitialUsername = Engine.GetDefaultLobbyPlayerUsername();
     8    g_InitialPassword = Engine.GetDefaultLobbyPlayerPassword();
     9}
     10
     11function lobbyStop()
     12{
     13    getGUIObjectByName("connectFeedback").caption = "";
     14    getGUIObjectByName("registerFeedback").caption = "";
     15
     16    if (g_LobbyIsConnecting == false)
     17        return;
     18
     19    g_LobbyIsConnecting = false;
     20    Engine.StopXmppClient();
     21}
     22
     23function lobbyStart()
     24{
     25    if (g_LobbyIsConnecting != false)
     26        return;
     27
     28    var username = getGUIObjectByName("connectUsername").caption;
     29    var password = getGUIObjectByName("connectPassword").caption;
     30    var playername = getGUIObjectByName("joinPlayerName").caption;
     31    var feedback = getGUIObjectByName("connectFeedback");
     32
     33    if (!username || !password)
     34    {
     35        feedback.caption = "Username or password empty";
     36    }
     37    else
     38    {
     39        feedback.caption = "Connecting..";
     40        Engine.StartXmppClient(username, password, "arena", playername);
     41        g_LobbyIsConnecting=true;
     42        Engine.ConnectXmppClient();
     43    }
     44}
     45
     46function lobbyStartRegister()
     47{
     48    if (g_LobbyIsConnecting != false)
     49        return;
     50
     51    var account = getGUIObjectByName("registerUsername").caption;
     52    var password = getGUIObjectByName("registerPassword").caption;
     53    var passwordAgain = getGUIObjectByName("registerPasswordAgain").caption;
     54    var feedback = getGUIObjectByName("registerFeedback");
     55
     56    if (!account || !password || !passwordAgain)
     57    {
     58        feedback.caption = "Account name or password empty";
     59    }
     60    else if (password != passwordAgain)
     61    {
     62        feedback.caption = "Password mismatch";
     63        getGUIObjectByName("registerPassword").caption = "";
     64        getGUIObjectByName("registerPasswordAgain").caption = "";
     65    }
     66    else
     67    {
     68        feedback.caption = "Registering..";
     69        Engine.StartRegisterXmppClient(
     70                account,
     71                password);
     72        g_LobbyIsConnecting=true;
     73        Engine.ConnectXmppClient();
     74    }
     75}
     76
     77function onTick()
     78{
     79    if (!g_LobbyIsConnecting)
     80    {
     81        // The Xmpp Client has not been created
     82    }
     83    else
     84    {
     85        // The XmppClient has been created, we are waiting
     86        // to be connected or to receive an error.
     87
     88        //Wake up XmppClient
     89        Engine.RecvXmppClient();
     90
     91        //Receive messages
     92        while (true)
     93        {
     94            var message = Engine.LobbyGuiPollMessage();
     95            if (!message)
     96                break;
     97
     98            if (message.type == "system" && message.text == "connected")
     99            {
     100                // We are connected, switch to the lobby page
     101                Engine.PopGuiPage();
     102                var sname = getGUIObjectByName("joinPlayerName").caption;
     103                Engine.PushGuiPage("page_lobby.xml", { name: sname } );
     104
     105                var username = getGUIObjectByName("connectUsername").caption;
     106                var password = getGUIObjectByName("connectPassword").caption;
     107                // Store latest username and password if they changed
     108                if(username != g_InitialUsername || password != g_InitialPassword)
     109                {
     110                    Engine.SetDefaultLobbyPlayerPair(username, password);
     111                }
     112
     113                return;
     114            }
     115            else if (message.type == "system" && message.text == "registered")
     116            {
     117                // Great, we are registered. Switch to the connection window.
     118                getGUIObjectByName("registerFeedback").caption = message.text;
     119                getGUIObjectByName("connectFeedback").caption = message.text;
     120                Engine.StopXmppClient();
     121                g_LobbyIsConnecting = false;
     122                getGUIObjectByName("connectUsername").caption = getGUIObjectByName("registerUsername").caption;
     123                getGUIObjectByName("pageRegister").hidden = true;
     124                getGUIObjectByName("pageConnect").hidden = false;
     125            }
     126            else if(message.type == "system" && message.level == "error")
     127            {
     128                getGUIObjectByName("connectFeedback").caption = message.text;
     129                getGUIObjectByName("registerFeedback").caption = message.text;
     130                Engine.StopXmppClient();
     131                g_LobbyIsConnecting = false;
     132            }
     133        }
     134    }
     135}
  • binaries/data/mods/public/gui/lobby/prelobby.xml

     
     1<?xml version="1.0" encoding="utf-8"?>
     2
     3<objects>
     4  <script file="gui/lobby/prelobby.js"/>
     5
     6  <script file="gui/common/functions_global_object.js"/>
     7  <script file="gui/common/functions_utility.js"/>
     8
     9  <object name="dialog" type="image" style="StoneDialog" size="50%-190 50%-140 50%+190 50%+140">
     10
     11    <action on="Tick">
     12      onTick();
     13    </action>
     14 
     15    <object name="pageConnecting" hidden="true">
     16      <object name="connectionStatus" type="text" text_align="center" size="0 100 100% 120">
     17        [Connection status]
     18      </object>
     19    </object>
     20
     21    <object style="TitleText" type="text" size="50%-128 0%-16 50%+128 16">
     22      Multiplayer Lobby
     23    </object>
     24
     25    <object name="pageConnect" size="0 32 100% 100%">
     26      <object type="text" style="CenteredLabelText" size="0 0 400 30">
     27        Connect to the game lobby.
     28      </object>
     29      <object type="text" size="0 40 200 70" style="RightLabelText">
     30        Player name:
     31      </object>
     32      <object name="joinPlayerName" type="input" size="210 40 100%-32 64" style="StoneInput">
     33        <action on="Load"><![CDATA[
     34          this.caption = Engine.GetDefaultPlayerName();
     35        ]]></action>
     36      </object>
     37      <object type="text" size="0 80 200 110" style="RightLabelText">
     38        0ad xmpp id:
     39      </object>
     40      <object name="connectUsername" type="input" size="210 80 100%-32 104" style="StoneInput">
     41        <action on="Load"><![CDATA[
     42          this.caption = Engine.GetDefaultLobbyPlayerUsername();
     43        ]]></action>
     44      </object>
     45      <object type="text" size="0 120 200 150" style="RightLabelText">
     46        Password:
     47      </object>
     48      <object name="connectPassword" type="input" size="210 120 100%-32 144" style="StoneInput">
     49        <action on="Load"><![CDATA[
     50          this.caption = Engine.GetDefaultLobbyPlayerPassword();
     51        ]]></action>
     52      </object>
     53      <object name="connectFeedback" type="text" style="CenteredLabelText" size="32 150 100%-32 180" textcolor="red"/>
     54      <object type="button" size="32 100%-60 122 100%-32" style="StoneButton">
     55        Cancel
     56        <action on="Press"><![CDATA[
     57          lobbyStop();
     58          Engine.PopGuiPage();
     59        ]]></action>
     60      </object>
     61      <object type="button" size="145 100%-60 235 100%-32" style="StoneButton">
     62        Register
     63        <action on="Press"><![CDATA[
     64          lobbyStop();
     65          getGUIObjectByName("pageConnect").hidden = true;
     66          getGUIObjectByName("pageRegister").hidden = false;
     67        ]]></action>
     68      </object>
     69      <object type="button" size="258 100%-60 100%-32 100%-32" style="StoneButton">
     70        Connect
     71        <action on="Press"><![CDATA[
     72          lobbyStart();
     73        ]]></action>
     74      </object>
     75    </object>
     76
     77    <object name="pageRegister" size="0 32 100% 100%" hidden="true">
     78      <object type="text" style="CenteredLabelText" size="0 0 400 30">
     79        Register to the game lobby.
     80      </object>
     81      <object type="text" size="0 40 200 70" style="RightLabelText">
     82        Account name:
     83      </object>
     84      <object name="registerUsername" type="input" size="210 40 100%-32 64" style="StoneInput">
     85      </object>
     86      <object type="text" size="0 80 200 110" style="RightLabelText">
     87        Password:
     88      </object>
     89      <object name="registerPassword" type="input" size="210 80 100%-32 104" style="StoneInput">
     90      </object>
     91      <object type="text" size="0 120 200 150" style="RightLabelText">
     92        Password again:
     93      </object>
     94      <object name="registerPasswordAgain" type="input" size="210 120 100%-32 144" style="StoneInput">
     95      </object>
     96      <object name="registerFeedback" type="text" style="CenteredLabelText" size="32 150 100%-32 180" textcolor="red"/>
     97      <object type="button" size="32 100%-60 122 100%-32" style="StoneButton">
     98        Back
     99        <action on="Press"><![CDATA[
     100          lobbyStop();
     101          getGUIObjectByName("pageRegister").hidden = true;
     102          getGUIObjectByName("pageConnect").hidden = false;
     103        ]]></action>
     104      </object>
     105      <object type="button" size="258 100%-60 100%-32 100%-32" style="StoneButton">
     106        Register
     107        <action on="Press"><![CDATA[
     108          lobbyStartRegister()
     109        ]]></action>
     110      </object>
     111    </object>
     112
     113  </object>
     114
     115</objects>
  • 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"