Changeset View
Standalone View
source/gui/scripting/ScriptFunctions.cpp
Show All 13 Lines | |||||
* You should have received a copy of the GNU General Public License | * You should have received a copy of the GNU General Public License | ||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>. | * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>. | ||||
*/ | */ | ||||
#include "precompiled.h" | #include "precompiled.h" | ||||
#include "scriptinterface/ScriptInterface.h" | #include "scriptinterface/ScriptInterface.h" | ||||
#include "graphics/Camera.h" | #include "graphics/Camera.h" | ||||
elexis: Also sounds like it could be moved to a separate diff | |||||
#include "graphics/FontMetrics.h" | #include "graphics/FontMetrics.h" | ||||
#include "graphics/GameView.h" | #include "graphics/GameView.h" | ||||
#include "graphics/MapReader.h" | #include "graphics/MapReader.h" | ||||
#include "graphics/scripting/JSInterface_GameView.h" | #include "graphics/scripting/JSInterface_GameView.h" | ||||
#include "gui/GUI.h" | #include "gui/GUI.h" | ||||
Not Done Inline ActionsIt might be cleaner if we moved the network related functions to a file of its own, might need fewer undefs. As that include is only needed for htonl (correct me if I'm wrong) we could just do a slightly ugly thing and assume that nobody is going to use a big endian Windows build and #define htonl to_be32 according to one of the definitions we have in lib/byte_order.h. Which would actually work on big endian machines too (which still doesn't mean even building on those would work). leper: It might be cleaner if we moved the network related functions to a file of its own, might need… | |||||
Not Done Inline ActionsJSInterface_Network and JSInterface_Game would definitely make this nicer to read. Using to_be32 is nice to dislodge those includes, but further complication such support isn't the cleanest thing either elexis: JSInterface_Network and JSInterface_Game would definitely make this nicer to read.
Using… | |||||
#include "gui/GUIManager.h" | #include "gui/GUIManager.h" | ||||
#include "gui/IGUIObject.h" | #include "gui/IGUIObject.h" | ||||
#include "gui/scripting/JSInterface_GUITypes.h" | #include "gui/scripting/JSInterface_GUITypes.h" | ||||
#include "i18n/L10n.h" | #include "i18n/L10n.h" | ||||
#include "i18n/scripting/JSInterface_L10n.h" | #include "i18n/scripting/JSInterface_L10n.h" | ||||
#include "lib/external_libraries/enet.h" | |||||
#include "lib/svn_revision.h" | #include "lib/svn_revision.h" | ||||
#include "lib/sysdep/sysdep.h" | #include "lib/sysdep/sysdep.h" | ||||
#include "lib/timer.h" | #include "lib/timer.h" | ||||
#include "lib/utf8.h" | #include "lib/utf8.h" | ||||
#include "lobby/scripting/JSInterface_Lobby.h" | #include "lobby/scripting/JSInterface_Lobby.h" | ||||
#include "lobby/IXmppClient.h" | |||||
#include "maths/FixedVector3D.h" | #include "maths/FixedVector3D.h" | ||||
#include "network/NetClient.h" | #include "network/NetClient.h" | ||||
#include "network/NetMessage.h" | #include "network/NetMessage.h" | ||||
#include "network/NetServer.h" | #include "network/NetServer.h" | ||||
#include "network/StunClient.h" | |||||
#include "ps/CConsole.h" | #include "ps/CConsole.h" | ||||
Not Done Inline ActionsThis hunk needed rebase, because the NetTurnManager was split into more classes in D16 elexis: This hunk needed rebase, because the NetTurnManager was split into more classes in D16 | |||||
#include "ps/CLogger.h" | #include "ps/CLogger.h" | ||||
#include "ps/Errors.h" | #include "ps/Errors.h" | ||||
#include "ps/GUID.h" | #include "ps/GUID.h" | ||||
#include "ps/Game.h" | #include "ps/Game.h" | ||||
#include "ps/GameSetup/Atlas.h" | #include "ps/GameSetup/Atlas.h" | ||||
#include "ps/GameSetup/Config.h" | #include "ps/GameSetup/Config.h" | ||||
#include "ps/Globals.h" // g_frequencyFilter | #include "ps/Globals.h" // g_frequencyFilter | ||||
#include "ps/Hotkey.h" | #include "ps/Hotkey.h" | ||||
▲ Show 20 Lines • Show All 181 Lines • ▼ Show 20 Lines | if (g_Game) | ||||
g_Game->SetViewedPlayerID(id); | g_Game->SetViewedPlayerID(id); | ||||
} | } | ||||
JS::Value GetEngineInfo(ScriptInterface::CxPrivate* pCxPrivate) | JS::Value GetEngineInfo(ScriptInterface::CxPrivate* pCxPrivate) | ||||
{ | { | ||||
return SavedGames::GetEngineInfo(*(pCxPrivate->pScriptInterface)); | return SavedGames::GetEngineInfo(*(pCxPrivate->pScriptInterface)); | ||||
} | } | ||||
JS::Value FindStunEndpoint(ScriptInterface::CxPrivate* pCxPrivate, int port) | |||||
{ | |||||
return StunClient::FindStunEndpoint(*(pCxPrivate->pScriptInterface), port); | |||||
} | |||||
void StartNetworkGame(ScriptInterface::CxPrivate* UNUSED(pCxPrivate)) | void StartNetworkGame(ScriptInterface::CxPrivate* UNUSED(pCxPrivate)) | ||||
{ | { | ||||
ENSURE(g_NetClient); | ENSURE(g_NetClient); | ||||
g_NetClient->SendStartGameMessage(); | g_NetClient->SendStartGameMessage(); | ||||
} | } | ||||
void StartGame(ScriptInterface::CxPrivate* pCxPrivate, JS::HandleValue attribs, int playerID) | void StartGame(ScriptInterface::CxPrivate* pCxPrivate, JS::HandleValue attribs, int playerID) | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 107 Lines • ▼ Show 20 Lines | void StartNetworkHost(ScriptInterface::CxPrivate* pCxPrivate, const CStrW& playerName, const u16 serverPort) | ||||
if (!g_NetClient->SetupConnection("127.0.0.1", serverPort)) | if (!g_NetClient->SetupConnection("127.0.0.1", serverPort)) | ||||
{ | { | ||||
pCxPrivate->pScriptInterface->ReportError("Failed to connect to server"); | pCxPrivate->pScriptInterface->ReportError("Failed to connect to server"); | ||||
SAFE_DELETE(g_NetClient); | SAFE_DELETE(g_NetClient); | ||||
SAFE_DELETE(g_Game); | SAFE_DELETE(g_Game); | ||||
} | } | ||||
} | } | ||||
void StartNetworkJoin(ScriptInterface::CxPrivate* pCxPrivate, const CStrW& playerName, const CStr& serverAddress, u16 serverPort) | void StartNetworkJoin(ScriptInterface::CxPrivate* pCxPrivate, const CStrW& playerName, const CStr& serverAddress, u16 serverPort, const std::string& hostJID) | ||||
Not Done Inline ActionsCStr in accordance with the other arguments elexis: CStr in accordance with the other arguments | |||||
{ | { | ||||
ENSURE(!g_NetClient); | ENSURE(!g_NetClient); | ||||
ENSURE(!g_NetServer); | ENSURE(!g_NetServer); | ||||
ENSURE(!g_Game); | ENSURE(!g_Game); | ||||
bool stunEnabled(false); | |||||
Not Done Inline ActionsWould be best to set this to false, which would have the expected behaviour in case the setting isn't present. leper: Would be best to set this to `false`, which would have the expected behaviour in case the… | |||||
CFG_GET_VAL("stun.enabled", stunEnabled); | |||||
ENetHost* enetClient = nullptr; | |||||
Not Done Inline Actionsnullptr, but I guess that is personal preference. leper: `nullptr`, but I guess that is personal preference. | |||||
if (stunEnabled) | |||||
Not Done Inline Actions\n{ leper: `\n{` | |||||
Not Done Inline ActionsDoes that even work in theory and practice independent of the host using STUN? elexis: Does that even work in theory and practice independent of the host using STUN? | |||||
Not Done Inline Actions
In theory if STUN is disabled on either client or host (or on both), the client should connect to the 'standard' lobby-detected host IP + host-reported port just like it's doing without the patch (see joinSelectedGame in lobby.js). I didn't test test it on practice though. fcxSanya: > Does that even work in theory and practice independent of the host using STUN?
In theory if… | |||||
{ | |||||
Not Done Inline ActionsYou could use ENetAddress hostAddr{ENET_HOST_ANY, serverPort};, would make this a bit shorter. leper: You could use `ENetAddress hostAddr{ENET_HOST_ANY, serverPort};`, would make this a bit shorter. | |||||
// By default we are binding client to the same port as host (20595), | |||||
// if there are multiple 0ad instances running on the same machine | |||||
Not Done Inline Actionsnot serverPort? elexis: not serverPort? | |||||
Not Done Inline ActionsIt was one of the test changes I made while trying to get the procedure working (see 2ed4795 and #2305#comment:36) and I expected to be able to revert it later. But when I got a reliable working version (where I was able to host on both my mobile connections) and reverted this change I wasn't able to host on one of the connections anymore (while still was able to reliable host on another). fcxSanya: It was one of the test changes I made while trying to get the procedure working (see [2ed4795]… | |||||
Not Done Inline ActionsPerhaps the segfault I got when trying to join a game on port 20595 if that port is forwarded is related to this place. elexis: Perhaps the segfault I got when trying to join a game on port 20595 if that port is forwarded… | |||||
// (host + client or multiple STUN-enabled clients), this will fail | |||||
// (with enet_host_create returning null as a result), | |||||
// so we are also trying a couple of subsequent ports. | |||||
ENetAddress hostAddr{ENET_HOST_ANY, 20595}; | |||||
for (int i = 0; i < 3 && enetClient == nullptr; ++i) | |||||
{ | |||||
enetClient = enet_host_create(&hostAddr, 1, 1, 0, 0); | |||||
hostAddr.port++; | |||||
} | |||||
StunClient::StunEndpoint stunEndpoint = StunClient::FindStunEndpoint(enetClient); | |||||
g_XmppClient->SendStunEndpointToHost(stunEndpoint, hostJID); | |||||
// Note: we are sending endpoint and starting to connect right away | |||||
// we may actually need to wait for host's response (this needs | |||||
// to be checked) | |||||
SDL_Delay(1000); | |||||
elexisUnsubmitted Not Done Inline Actions(100ms works well for me and reduces the impact of the freeze-join problem drastically, can become a config number trivially, got some 5 line commit for that) elexis: (100ms works well for me and reduces the impact of the freeze-join problem drastically, can… | |||||
} | |||||
g_Game = new CGame(); | g_Game = new CGame(); | ||||
g_NetClient = new CNetClient(g_Game, false); | g_NetClient = new CNetClient(g_Game, false); | ||||
g_NetClient->SetUserName(playerName); | g_NetClient->SetUserName(playerName); | ||||
if (!g_NetClient->SetupConnection(serverAddress, serverPort)) | |||||
if (stunEnabled) | |||||
StunClient::SendHolePunchingMessages(enetClient, serverAddress.c_str(), serverPort); | |||||
if (!g_NetClient->SetupConnection(serverAddress, serverPort, enetClient)) | |||||
{ | { | ||||
pCxPrivate->pScriptInterface->ReportError("Failed to connect to server"); | pCxPrivate->pScriptInterface->ReportError("Failed to connect to server"); | ||||
SAFE_DELETE(g_NetClient); | SAFE_DELETE(g_NetClient); | ||||
SAFE_DELETE(g_Game); | SAFE_DELETE(g_Game); | ||||
} | } | ||||
} | } | ||||
u16 GetDefaultPort(ScriptInterface::CxPrivate* UNUSED(pCxPrivate)) | u16 GetDefaultPort(ScriptInterface::CxPrivate* UNUSED(pCxPrivate)) | ||||
Not Done Inline ActionsThis (3 messages with delays from both sides) was a quick test, which turned out to be working, going to replace the copy-pasted statements with a loop. fcxSanya: This (3 messages with delays from both sides) was a quick test, which turned out to be working… | |||||
Not Done Inline Actions
Fixed in 29d5116 fcxSanya: > going to replace the copy-pasted statements with a loop
Fixed in [29d5116](https://github. | |||||
{ | { | ||||
return PS_DEFAULT_PORT; | return PS_DEFAULT_PORT; | ||||
} | } | ||||
void DisconnectNetworkGame(ScriptInterface::CxPrivate* UNUSED(pCxPrivate)) | void DisconnectNetworkGame(ScriptInterface::CxPrivate* UNUSED(pCxPrivate)) | ||||
{ | { | ||||
// TODO: we ought to do async reliable disconnections | // TODO: we ought to do async reliable disconnections | ||||
▲ Show 20 Lines • Show All 633 Lines • ▼ Show 20 Lines | void GuiScriptingInit(ScriptInterface& scriptInterface) | ||||
scriptInterface.RegisterFunction<std::vector<entity_id_t>, std::string, bool, bool, bool, &PickSimilarPlayerEntities>("PickSimilarPlayerEntities"); | scriptInterface.RegisterFunction<std::vector<entity_id_t>, std::string, bool, bool, bool, &PickSimilarPlayerEntities>("PickSimilarPlayerEntities"); | ||||
scriptInterface.RegisterFunction<CFixedVector3D, int, int, &GetTerrainAtScreenPoint>("GetTerrainAtScreenPoint"); | scriptInterface.RegisterFunction<CFixedVector3D, int, int, &GetTerrainAtScreenPoint>("GetTerrainAtScreenPoint"); | ||||
// Network / game setup functions | // Network / game setup functions | ||||
scriptInterface.RegisterFunction<void, &StartNetworkGame>("StartNetworkGame"); | scriptInterface.RegisterFunction<void, &StartNetworkGame>("StartNetworkGame"); | ||||
scriptInterface.RegisterFunction<void, JS::HandleValue, int, &StartGame>("StartGame"); | scriptInterface.RegisterFunction<void, JS::HandleValue, int, &StartGame>("StartGame"); | ||||
scriptInterface.RegisterFunction<void, &Script_EndGame>("EndGame"); | scriptInterface.RegisterFunction<void, &Script_EndGame>("EndGame"); | ||||
scriptInterface.RegisterFunction<void, CStrW, u16, &StartNetworkHost>("StartNetworkHost"); | scriptInterface.RegisterFunction<void, CStrW, u16, &StartNetworkHost>("StartNetworkHost"); | ||||
scriptInterface.RegisterFunction<void, CStrW, CStr, u16, &StartNetworkJoin>("StartNetworkJoin"); | scriptInterface.RegisterFunction<void, CStrW, CStr, u16, std::string, &StartNetworkJoin>("StartNetworkJoin"); | ||||
scriptInterface.RegisterFunction<u16, &GetDefaultPort>("GetDefaultPort"); | scriptInterface.RegisterFunction<u16, &GetDefaultPort>("GetDefaultPort"); | ||||
scriptInterface.RegisterFunction<void, &DisconnectNetworkGame>("DisconnectNetworkGame"); | scriptInterface.RegisterFunction<void, &DisconnectNetworkGame>("DisconnectNetworkGame"); | ||||
scriptInterface.RegisterFunction<std::string, &GetPlayerGUID>("GetPlayerGUID"); | scriptInterface.RegisterFunction<std::string, &GetPlayerGUID>("GetPlayerGUID"); | ||||
scriptInterface.RegisterFunction<void, CStrW, bool, &KickPlayer>("KickPlayer"); | scriptInterface.RegisterFunction<void, CStrW, bool, &KickPlayer>("KickPlayer"); | ||||
scriptInterface.RegisterFunction<JS::Value, &PollNetworkClient>("PollNetworkClient"); | scriptInterface.RegisterFunction<JS::Value, &PollNetworkClient>("PollNetworkClient"); | ||||
scriptInterface.RegisterFunction<void, JS::HandleValue, &SetNetworkGameAttributes>("SetNetworkGameAttributes"); | scriptInterface.RegisterFunction<void, JS::HandleValue, &SetNetworkGameAttributes>("SetNetworkGameAttributes"); | ||||
scriptInterface.RegisterFunction<void, int, std::string, &AssignNetworkPlayer>("AssignNetworkPlayer"); | scriptInterface.RegisterFunction<void, int, std::string, &AssignNetworkPlayer>("AssignNetworkPlayer"); | ||||
scriptInterface.RegisterFunction<void, &ClearAllPlayerReady>("ClearAllPlayerReady"); | scriptInterface.RegisterFunction<void, &ClearAllPlayerReady>("ClearAllPlayerReady"); | ||||
scriptInterface.RegisterFunction<void, std::wstring, &SendNetworkChat>("SendNetworkChat"); | scriptInterface.RegisterFunction<void, std::wstring, &SendNetworkChat>("SendNetworkChat"); | ||||
scriptInterface.RegisterFunction<void, int, &SendNetworkReady>("SendNetworkReady"); | scriptInterface.RegisterFunction<void, int, &SendNetworkReady>("SendNetworkReady"); | ||||
scriptInterface.RegisterFunction<JS::Value, &GetAIs>("GetAIs"); | scriptInterface.RegisterFunction<JS::Value, &GetAIs>("GetAIs"); | ||||
scriptInterface.RegisterFunction<JS::Value, &GetEngineInfo>("GetEngineInfo"); | scriptInterface.RegisterFunction<JS::Value, &GetEngineInfo>("GetEngineInfo"); | ||||
scriptInterface.RegisterFunction<JS::Value, int, &FindStunEndpoint>("FindStunEndpoint"); | |||||
// Saved games | // Saved games | ||||
scriptInterface.RegisterFunction<JS::Value, std::wstring, &StartSavedGame>("StartSavedGame"); | scriptInterface.RegisterFunction<JS::Value, std::wstring, &StartSavedGame>("StartSavedGame"); | ||||
scriptInterface.RegisterFunction<JS::Value, &GetSavedGames>("GetSavedGames"); | scriptInterface.RegisterFunction<JS::Value, &GetSavedGames>("GetSavedGames"); | ||||
scriptInterface.RegisterFunction<bool, std::wstring, &DeleteSavedGame>("DeleteSavedGame"); | scriptInterface.RegisterFunction<bool, std::wstring, &DeleteSavedGame>("DeleteSavedGame"); | ||||
scriptInterface.RegisterFunction<void, std::wstring, std::wstring, JS::HandleValue, &SaveGame>("SaveGame"); | scriptInterface.RegisterFunction<void, std::wstring, std::wstring, JS::HandleValue, &SaveGame>("SaveGame"); | ||||
scriptInterface.RegisterFunction<void, std::wstring, std::wstring, JS::HandleValue, &SaveGamePrefix>("SaveGamePrefix"); | scriptInterface.RegisterFunction<void, std::wstring, std::wstring, JS::HandleValue, &SaveGamePrefix>("SaveGamePrefix"); | ||||
scriptInterface.RegisterFunction<void, &QuickSave>("QuickSave"); | scriptInterface.RegisterFunction<void, &QuickSave>("QuickSave"); | ||||
▲ Show 20 Lines • Show All 60 Lines • Show Last 20 Lines |
Also sounds like it could be moved to a separate diff