// Ryzom - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . /* Petite documentation sur le fonctionnement du plugin 1) Le WorldEditor se connecte au plugin (config dans WorldEditorPlugin.cfg) 2) Le plugin se connecte au World_Editor_Service 3) Le World_Editor_Service (config dans WorldEditorService.cfg) envoie des paquets contenant au maximum 100 joueurs. Ces joueurs sont soit nouveaux, soit leurs coordonnées ont changé. 4) Les informations des joueurs sont envoyées (voir onIdle) sous forme de primitives "player": Voici la définition de la primitive "player", dans WORLD_EDITOR_SCRIPT.XML 5) World_Editor_Service utilise un cache pour stocker les déplacements des joueurs, afin de n'envoyer que ce qui bouge 6) World_Editor_Plugin utilise aussi un cache avec un pointeur sur les Primitives, afin de ne modifier dans WE que ce qui bouge */ #include "stdafx.h" #include "plugin.h" #include "resource.h" #include "nel/misc/path.h" #include "LoadDialog.h" #include "nel/sound/u_listener.h" using namespace NLMISC; using namespace NLLIGO; using namespace NLSOUND; using namespace NLNET; using namespace std; class Player { public: string _name; float _x, _y; const IPrimitive *primitive; // Constructor Player::Player() { primitive = NULL; } Player::Player(string name, float x, float y) { primitive = NULL; _name = name; _x = x; _y = y; } /// Destructor Player::~Player() { } }; vector StackPlayers; map StoredPlayers; extern "C" { void *createPlugin() { return new CPlugin(); } } CPlugin::CPlugin() : _PluginAccess(0) { m_Initialized = false; _Client = NULL; StackPlayers.clear(); } CPlugin::~CPlugin() { delete _Client; if (m_Initialized) { _PluginAccess->deleteRootPluginPrimitive(); m_Initialized = false; } } void CPlugin::progress (float progressValue) { /*char tmp[1024]; sprintf(tmp, "Initializing mixer : %i%%", int(progressValue * 100)); LoadDlg->Message = tmp; LoadDlg->UpdateData(FALSE); LoadDlg->RedrawWindow();*/ } // *************************************************************************** void serverSentPos (CMessage &msgin, TSockId from, CCallbackNetBase &netbase) { // Called when the server sent a POS message uint32 count; msgin.serial(count); for (uint i = 0;i < count;++i) { string name; msgin.serial(name); float x, y; msgin.serial(x); msgin.serial(y); // we received name, x, y, we save it in the stack StackPlayers.push_back (Player(name, x, y)); } } // *************************************************************************** void serverSentInfo (CMessage &msgin, TSockId from, CCallbackNetBase &netbase) { // Called when the server sent a INFO message string text; msgin.serial(text); printf("%s\n", text.c_str()); } // *************************************************************************** // All messages handled by this server #define NB_CB 2 TCallbackItem CallbackArray[NB_CB] = { { "POS", serverSentPos }, { "INFO", serverSentInfo }, }; void CPlugin::init(IPluginAccess *pluginAccess) { CLoadDialog *LoadDlg; AFX_MANAGE_STATE(AfxGetStaticModuleState()); AfxEnableControlContainer(); _PluginAccess = pluginAccess; _PluginName="Player Plugin"; //#undef new LoadDlg = new CLoadDialog; //#define new NL_NEW LoadDlg->Create(IDD_DIALOG_LOAD); LoadDlg->Message = "Connecting..."; LoadDlg->UpdateData(FALSE); //LoadDlg->Invalidate(); LoadDlg->ShowWindow(SW_SHOW); //LoadDlg->RedrawWindow(); // connect to the server here... // Read the host where to connect in the client.cfg file CConfigFile ConfigFile; ConfigFile.load ("client.cfg"); string LSHost(ConfigFile.getVar("LSHost").asString()); // Init and Connect the client to the server located on port 3333 _Client = new CCallbackClient(); _Client->addCallbackArray (CallbackArray, NB_CB); //printf("Please wait connecting...\n"); try { CInetAddress addr(LSHost+":48888"); _Client->connect(addr); } catch(ESocket &e) { MessageBox (NULL, e.what(), "Error", MB_ICONERROR|MB_OK); delete LoadDlg; LoadDlg = 0; return; } delete LoadDlg; LoadDlg = 0; if (!_Client->connected()) { MessageBox (NULL, "The connection failed", "Error", MB_ICONERROR|MB_OK); return; } //#undef new _DialogFlag = new CDialogFlags(/*_Mixer*/); //#define new NL_NEW // open the dialog flag window _DialogFlag->Create(IDD_DIALOG_FLAGS, CWnd::FromHandle(_PluginAccess->getMainWindow()->m_hWnd)); _DialogFlag->init(this); _DialogFlag->ShowWindow(TRUE); // { CMessage msg; msg.setType("WINDOW"); float xmin = 0; float xmax = 10000; float ymin = 0; float ymax = 10000; msg.serial (xmin); msg.serial (ymin); msg.serial (xmax); msg.serial (ymax); _Client->send(msg); } } /// The current region has changed. void CPlugin::primitiveChanged(const NLLIGO::IPrimitive *root) { } /// The listener has been moved on the map. void CPlugin::positionMoved(const NLMISC::CVector &position) { } void CPlugin::lostPositionControl() { } void CPlugin::onIdle() { if (_Client && _Client->connected()) { // during the first call, we create a Root primitive to store all players if (!m_Initialized) { m_Initialized = true; _PluginAccess->createRootPluginPrimitive(); } else { // first, we receive the stack of messages, which is composed of players informations _Client->update(); // now, we insert the players into the GUI for (uint i = 0; i < StackPlayers.size(); ++i) { map::const_iterator ite; ite = StoredPlayers.find(StackPlayers[i]._name); if (ite == StoredPlayers.end()) { // if the player doesn't exist in the static list, we add it //StoredPlayers.insert(map::value_type(StackPlayers[i]._name, StackPlayers[i])); StoredPlayers[StackPlayers[i]._name] = StackPlayers[i]; std::vector Parameters; Parameters.push_back (CPrimitiveClass::CInitParameters ()); CPrimitiveClass::CInitParameters ¶m1 = Parameters.back (); param1.DefaultValue.resize (1); param1.Name = "x"; param1.DefaultValue[0].GenID = false; param1.DefaultValue[0].Name = toString(StackPlayers[i]._x); Parameters.push_back (CPrimitiveClass::CInitParameters ()); CPrimitiveClass::CInitParameters ¶m2 = Parameters.back (); param2.DefaultValue.resize (1); param2 = Parameters.back (); param2.Name = "y"; param2.DefaultValue[0].GenID = false; param2.DefaultValue[0].Name = toString(StackPlayers[i]._y); // create a player in WorldEditor StoredPlayers[StackPlayers[i]._name].primitive = _PluginAccess->createPluginPrimitive("player",StackPlayers[i]._name.c_str(),NLMISC::CVector(StackPlayers[i]._x,StackPlayers[i]._y,0),0,Parameters); } else { // the player has moved, we need to change its coordinates _PluginAccess->movePluginPrimitive(StoredPlayers[StackPlayers[i]._name].primitive, CVector(StackPlayers[i]._x, StackPlayers[i]._y, 0)); } } // we clear the stack StackPlayers.clear(); } } } std::string& CPlugin::getName() { return _PluginName; } bool CPlugin::isActive() { return _PluginActive; } bool CPlugin::activatePlugin() { if(!_PluginActive) { AFX_MANAGE_STATE(AfxGetStaticModuleState()); AfxEnableControlContainer(); //_DialogFlag->Create(IDD_DIALOG_FLAGS, CWnd::FromHandle(_PluginAccess->getMainWindow()->m_hWnd)); _DialogFlag->ShowWindow(TRUE); //_DialogFlag->init(this); _PluginActive=true; return true; } return false; } bool CPlugin::closePlugin() { if (_PluginActive) { //_DialogFlag->CloseWindow(); _DialogFlag->ShowWindow(FALSE); _PluginActive=false; return true; } return false; }