mirror of
https://github.com/Mauler125/r5sdk.git
synced 2025-02-09 19:15:03 +01:00
Engine: large server host code refactor
This code was written at the start of the project before much of the engine was reverse engineered. There were some design problems where core server functions were shared with UI script. A second problem was that not everything was properly synced between another; CServerHostManager held its own instance of the server name and server description, while the engine has actual convars to store these. So scripters weren't able to get the server name and server description if the server was a listen server and launched through the title screen. The CServerHostManager class has been reworked to not keep a second instance, and the script functions for creating the servers have been reworked to always store the name and description in aforementioned convars. Also moved the CreateServer and DestroyServer function to the UI namespace of scripts, and it is now only registered in UI context. The server should use GameRules_ChangeMap() to switch levels instead. UI script also no longer registers core server functions, this was a design mistake and has been fully factored out in this patch. The server script function 'SetClassVarSynced' has also been deprecated and removed, since calling this sends a netmsg to all connected clients, and running this once will not apply the new class var values to clients connecting afterwards. This should be managed through player.SetClassVar in the connect codecallbacks in scripts.
This commit is contained in:
parent
67b43192ef
commit
3209af9a6c
@ -267,15 +267,17 @@ void Systems_Init()
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
ServerScriptRegister_Callback = Script_RegisterServerFunctions;
|
||||
CoreServerScriptRegister_Callback = Script_RegisterCoreServerFunctions;
|
||||
AdminPanelScriptRegister_Callback = Script_RegisterAdminPanelFunctions;
|
||||
|
||||
ServerScriptRegisterEnum_Callback = Script_RegisterServerEnums;
|
||||
#endif// !CLIENT_DLL
|
||||
|
||||
#ifndef SERVER_DLL
|
||||
ClientScriptRegister_Callback = Script_RegisterClientFunctions;
|
||||
UiScriptRegister_Callback = Script_RegisterUIFunctions;
|
||||
|
||||
#ifndef CLIENT_DLL
|
||||
UiServerScriptRegister_Callback = Script_RegisterUIServerFunctions;
|
||||
UiAdminPanelScriptRegister_Callback = Script_RegisterAdminServerFunctions;
|
||||
#endif // !CLIENT_DLL
|
||||
#endif // !SERVER_DLL
|
||||
|
||||
#ifdef CLIENT_DLL
|
||||
|
@ -63,8 +63,9 @@ static ConVar host_autoReloadRate("host_autoReloadRate", "0", FCVAR_RELEASE, "Ti
|
||||
static ConVar host_autoReloadRespectGameState("host_autoReloadRespectGameState", "0", FCVAR_RELEASE, "Check the game state before proceeding to auto-reload (don't reload in the middle of a match).");
|
||||
#endif // !CLIENT_DLL
|
||||
|
||||
ConVar hostdesc("hostdesc", "", FCVAR_RELEASE, "Host game server description.");
|
||||
|
||||
#ifdef DEDICATED
|
||||
static ConVar hostdesc("hostdesc", "", FCVAR_RELEASE, "Host game server description.");
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Send keep alive request to Pylon Master Server.
|
||||
// Output : Returns true on success, false otherwise.
|
||||
|
@ -1,6 +1,8 @@
|
||||
#pragma once
|
||||
#include "mathlib/vector.h"
|
||||
|
||||
extern ConVar hostdesc;
|
||||
|
||||
enum class HostStates_t : int
|
||||
{
|
||||
HS_NEW_GAME = 0x0,
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "engine/client/cl_main.h"
|
||||
#include "networksystem/pylon.h"
|
||||
#include "networksystem/listmanager.h"
|
||||
#include "networksystem/hostmanager.h"
|
||||
#include "game/shared/vscript_shared.h"
|
||||
|
||||
#include "vscript/vscript.h"
|
||||
@ -81,6 +82,17 @@ static SQBool Script_CheckServerIndexAndFailure(HSQUIRRELVM v, SQInteger iServer
|
||||
namespace VScriptCode
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: checks whether this SDK build is a client dll
|
||||
//-----------------------------------------------------------------------------
|
||||
SQRESULT IsClientDLL(HSQUIRRELVM v)
|
||||
{
|
||||
sq_pushbool(v, ::IsClientDLL());
|
||||
SCRIPT_CHECK_AND_RETURN(v, SQ_OK);
|
||||
}
|
||||
}
|
||||
namespace Ui
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: refreshes the server list
|
||||
@ -436,11 +448,52 @@ namespace VScriptCode
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: checks whether this SDK build is a client dll
|
||||
// Purpose: create server via native serverbrowser entries
|
||||
// TODO: return a boolean on failure instead of raising an error, so we could
|
||||
// determine from scripts whether or not to spin a local server, or connect
|
||||
// to a dedicated server (for disconnecting and loading the lobby, for example)
|
||||
//-----------------------------------------------------------------------------
|
||||
SQRESULT IsClientDLL(HSQUIRRELVM v)
|
||||
SQRESULT CreateServer(HSQUIRRELVM v)
|
||||
{
|
||||
sq_pushbool(v, ::IsClientDLL());
|
||||
const SQChar* serverName = nullptr;
|
||||
const SQChar* serverDescription = nullptr;
|
||||
const SQChar* serverMapName = nullptr;
|
||||
const SQChar* serverPlaylist = nullptr;
|
||||
|
||||
sq_getstring(v, 2, &serverName);
|
||||
sq_getstring(v, 3, &serverDescription);
|
||||
sq_getstring(v, 4, &serverMapName);
|
||||
sq_getstring(v, 5, &serverPlaylist);
|
||||
|
||||
SQInteger serverVisibility = 0;
|
||||
sq_getinteger(v, 6, &serverVisibility);
|
||||
|
||||
if (!VALID_CHARSTAR(serverName) ||
|
||||
!VALID_CHARSTAR(serverMapName) ||
|
||||
!VALID_CHARSTAR(serverPlaylist))
|
||||
{
|
||||
v_SQVM_ScriptError("Empty or null server criteria");
|
||||
SCRIPT_CHECK_AND_RETURN(v, SQ_ERROR);
|
||||
}
|
||||
|
||||
hostname->SetValue(serverName);
|
||||
hostdesc.SetValue(serverDescription);
|
||||
|
||||
// Launch server.
|
||||
g_ServerHostManager.SetVisibility(ServerVisibility_e(serverVisibility));
|
||||
g_ServerHostManager.LaunchServer(serverMapName, serverPlaylist);
|
||||
|
||||
SCRIPT_CHECK_AND_RETURN(v, SQ_OK);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: shuts the server down and disconnects all clients
|
||||
//-----------------------------------------------------------------------------
|
||||
SQRESULT DestroyServer(HSQUIRRELVM v)
|
||||
{
|
||||
if (g_pHostState->m_bActiveGame)
|
||||
g_pHostState->m_iNextState = HostStates_t::HS_GAME_SHUTDOWN;
|
||||
|
||||
SCRIPT_CHECK_AND_RETURN(v, SQ_OK);
|
||||
}
|
||||
}
|
||||
@ -456,6 +509,15 @@ void Script_RegisterClientFunctions(CSquirrelVM* s)
|
||||
Script_RegisterCoreClientFunctions(s);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------
|
||||
// Purpose: core client script functions
|
||||
// Input : *s -
|
||||
//---------------------------------------------------------------------------------
|
||||
void Script_RegisterCoreClientFunctions(CSquirrelVM* s)
|
||||
{
|
||||
DEFINE_CLIENT_SCRIPTFUNC_NAMED(s, IsClientDLL, "Returns whether this build is client only", "bool", "");
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------
|
||||
// Purpose: registers script functions in UI context
|
||||
// Input : *s -
|
||||
@ -465,37 +527,34 @@ void Script_RegisterUIFunctions(CSquirrelVM* s)
|
||||
Script_RegisterCommonAbstractions(s);
|
||||
Script_RegisterCoreClientFunctions(s);
|
||||
|
||||
DEFINE_CLIENT_SCRIPTFUNC_NAMED(s, RefreshServerList, "Refreshes the public server list and returns the count", "int", "");
|
||||
DEFINE_CLIENT_SCRIPTFUNC_NAMED(s, GetServerCount, "Gets the number of public servers", "int", "");
|
||||
DEFINE_UI_SCRIPTFUNC_NAMED(s, RefreshServerList, "Refreshes the public server list and returns the count", "int", "");
|
||||
DEFINE_UI_SCRIPTFUNC_NAMED(s, GetServerCount, "Gets the number of public servers", "int", "");
|
||||
|
||||
// Functions for retrieving server browser data
|
||||
DEFINE_CLIENT_SCRIPTFUNC_NAMED(s, GetHiddenServerName, "Gets hidden server name by token", "string", "string");
|
||||
DEFINE_CLIENT_SCRIPTFUNC_NAMED(s, GetServerName, "Gets the name of the server at the specified index of the server list", "string", "int");
|
||||
DEFINE_CLIENT_SCRIPTFUNC_NAMED(s, GetServerDescription, "Gets the description of the server at the specified index of the server list", "string", "int");
|
||||
DEFINE_UI_SCRIPTFUNC_NAMED(s, GetHiddenServerName, "Gets hidden server name by token", "string", "string");
|
||||
DEFINE_UI_SCRIPTFUNC_NAMED(s, GetServerName, "Gets the name of the server at the specified index of the server list", "string", "int");
|
||||
DEFINE_UI_SCRIPTFUNC_NAMED(s, GetServerDescription, "Gets the description of the server at the specified index of the server list", "string", "int");
|
||||
|
||||
DEFINE_CLIENT_SCRIPTFUNC_NAMED(s, GetServerMap, "Gets the map of the server at the specified index of the server list", "string", "int");
|
||||
DEFINE_CLIENT_SCRIPTFUNC_NAMED(s, GetServerPlaylist, "Gets the playlist of the server at the specified index of the server list", "string", "int");
|
||||
DEFINE_CLIENT_SCRIPTFUNC_NAMED(s, GetServerCurrentPlayers, "Gets the current player count of the server at the specified index of the server list", "int", "int");
|
||||
DEFINE_UI_SCRIPTFUNC_NAMED(s, GetServerMap, "Gets the map of the server at the specified index of the server list", "string", "int");
|
||||
DEFINE_UI_SCRIPTFUNC_NAMED(s, GetServerPlaylist, "Gets the playlist of the server at the specified index of the server list", "string", "int");
|
||||
DEFINE_UI_SCRIPTFUNC_NAMED(s, GetServerCurrentPlayers, "Gets the current player count of the server at the specified index of the server list", "int", "int");
|
||||
|
||||
DEFINE_CLIENT_SCRIPTFUNC_NAMED(s, GetServerMaxPlayers, "Gets the max player count of the server at the specified index of the server list", "int", "int");
|
||||
DEFINE_UI_SCRIPTFUNC_NAMED(s, GetServerMaxPlayers, "Gets the max player count of the server at the specified index of the server list", "int", "int");
|
||||
|
||||
// Misc main menu functions
|
||||
DEFINE_CLIENT_SCRIPTFUNC_NAMED(s, GetPromoData, "Gets promo data for specified slot type", "string", "int");
|
||||
DEFINE_CLIENT_SCRIPTFUNC_NAMED(s, GetEULAContents, "Gets EULA contents from masterserver", "string", "");
|
||||
DEFINE_UI_SCRIPTFUNC_NAMED(s, GetPromoData, "Gets promo data for specified slot type", "string", "int");
|
||||
DEFINE_UI_SCRIPTFUNC_NAMED(s, GetEULAContents, "Gets EULA contents from masterserver", "string", "");
|
||||
|
||||
// Functions for connecting to servers
|
||||
DEFINE_CLIENT_SCRIPTFUNC_NAMED(s, ConnectToServer, "Joins server by ip address and encryption key", "void", "string, string");
|
||||
DEFINE_CLIENT_SCRIPTFUNC_NAMED(s, ConnectToListedServer, "Joins listed server by index", "void", "int");
|
||||
DEFINE_CLIENT_SCRIPTFUNC_NAMED(s, ConnectToHiddenServer, "Joins hidden server by token", "void", "string");
|
||||
DEFINE_UI_SCRIPTFUNC_NAMED(s, ConnectToServer, "Joins server by ip address and encryption key", "void", "string, string");
|
||||
DEFINE_UI_SCRIPTFUNC_NAMED(s, ConnectToListedServer, "Joins listed server by index", "void", "int");
|
||||
DEFINE_UI_SCRIPTFUNC_NAMED(s, ConnectToHiddenServer, "Joins hidden server by token", "void", "string");
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------
|
||||
// Purpose: core client script functions
|
||||
// Input : *s -
|
||||
//---------------------------------------------------------------------------------
|
||||
void Script_RegisterCoreClientFunctions(CSquirrelVM* s)
|
||||
void Script_RegisterUIServerFunctions(CSquirrelVM* s)
|
||||
{
|
||||
DEFINE_CLIENT_SCRIPTFUNC_NAMED(s, IsClientDLL, "Returns whether this build is client only", "bool", "");
|
||||
DEFINE_UI_SCRIPTFUNC_NAMED(s, CreateServer, "Starts server with the specified settings", "void", "string, string, string, string, int");
|
||||
DEFINE_UI_SCRIPTFUNC_NAMED(s, DestroyServer, "Shuts the local server down", "void", "");
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------
|
||||
|
@ -4,6 +4,11 @@
|
||||
namespace VScriptCode
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
SQRESULT IsClientDLL(HSQUIRRELVM v);
|
||||
}
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
SQRESULT RefreshServerList(HSQUIRRELVM v);
|
||||
SQRESULT GetServerCount(HSQUIRRELVM v);
|
||||
@ -23,13 +28,12 @@ namespace VScriptCode
|
||||
SQRESULT ConnectToListedServer(HSQUIRRELVM v);
|
||||
SQRESULT ConnectToHiddenServer(HSQUIRRELVM v);
|
||||
SQRESULT ConnectToServer(HSQUIRRELVM v);
|
||||
|
||||
SQRESULT IsClientDLL(HSQUIRRELVM v);
|
||||
}
|
||||
}
|
||||
|
||||
void Script_RegisterClientFunctions(CSquirrelVM* s);
|
||||
void Script_RegisterUIFunctions(CSquirrelVM* s);
|
||||
void Script_RegisterUIServerFunctions(CSquirrelVM* s);
|
||||
void Script_RegisterCoreClientFunctions(CSquirrelVM* s);
|
||||
|
||||
#define DEFINE_CLIENT_SCRIPTFUNC_NAMED(s, functionName, helpString, \
|
||||
@ -37,6 +41,11 @@ void Script_RegisterCoreClientFunctions(CSquirrelVM* s);
|
||||
s->RegisterFunction(#functionName, MKSTRING(Script_##functionName), \
|
||||
helpString, returnType, parameters, VScriptCode::Client::##functionName); \
|
||||
|
||||
#define DEFINE_UI_SCRIPTFUNC_NAMED(s, functionName, helpString, \
|
||||
returnType, parameters) \
|
||||
s->RegisterFunction(#functionName, MKSTRING(Script_##functionName), \
|
||||
helpString, returnType, parameters, VScriptCode::Ui::##functionName); \
|
||||
|
||||
inline void (*v_Script_RegisterClientEntityClassFuncs)();
|
||||
inline void (*v_Script_RegisterClientPlayerClassFuncs)();
|
||||
inline void (*v_Script_RegisterClientAIClassFuncs)();
|
||||
|
@ -17,7 +17,6 @@
|
||||
#include "liveapi/liveapi.h"
|
||||
#include "vscript_server.h"
|
||||
#include <engine/host_state.h>
|
||||
#include <networksystem/hostmanager.h>
|
||||
#include "player.h"
|
||||
#include <common/callback.h>
|
||||
|
||||
@ -42,61 +41,6 @@ namespace VScriptCode
|
||||
{
|
||||
namespace Server
|
||||
{
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: create server via native serverbrowser entries
|
||||
// TODO: return a boolean on failure instead of raising an error, so we could
|
||||
// determine from scripts whether or not to spin a local server, or connect
|
||||
// to a dedicated server (for disconnecting and loading the lobby, for example)
|
||||
//-----------------------------------------------------------------------------
|
||||
SQRESULT CreateServer(HSQUIRRELVM v)
|
||||
{
|
||||
const SQChar* serverName = nullptr;
|
||||
const SQChar* serverDescription = nullptr;
|
||||
const SQChar* serverMapName = nullptr;
|
||||
const SQChar* serverPlaylist = nullptr;
|
||||
|
||||
sq_getstring(v, 2, &serverName);
|
||||
sq_getstring(v, 3, &serverDescription);
|
||||
sq_getstring(v, 4, &serverMapName);
|
||||
sq_getstring(v, 5, &serverPlaylist);
|
||||
|
||||
SQInteger serverVisibility = 0;
|
||||
sq_getinteger(v, 6, &serverVisibility);
|
||||
|
||||
if (!VALID_CHARSTAR(serverName) ||
|
||||
!VALID_CHARSTAR(serverMapName) ||
|
||||
!VALID_CHARSTAR(serverPlaylist))
|
||||
{
|
||||
v_SQVM_ScriptError("Empty or null server criteria");
|
||||
SCRIPT_CHECK_AND_RETURN(v, SQ_ERROR);
|
||||
}
|
||||
|
||||
// Adjust browser settings.
|
||||
NetGameServer_t& details = g_ServerHostManager.GetDetails();
|
||||
|
||||
details.name = serverName;
|
||||
details.description = serverDescription;
|
||||
details.map = serverMapName;
|
||||
details.playlist = serverPlaylist;
|
||||
|
||||
// Launch server.
|
||||
g_ServerHostManager.SetVisibility(ServerVisibility_e(serverVisibility));
|
||||
g_ServerHostManager.LaunchServer(g_pServer->IsActive());
|
||||
|
||||
SCRIPT_CHECK_AND_RETURN(v, SQ_OK);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: shuts the server down and disconnects all clients
|
||||
//-----------------------------------------------------------------------------
|
||||
SQRESULT DestroyServer(HSQUIRRELVM v)
|
||||
{
|
||||
if (g_pHostState->m_bActiveGame)
|
||||
g_pHostState->m_iNextState = HostStates_t::HS_GAME_SHUTDOWN;
|
||||
|
||||
SCRIPT_CHECK_AND_RETURN(v, SQ_OK);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: sets whether the server could auto reload at this time (e.g. if
|
||||
// server admin has host_autoReloadRate AND host_autoReloadRespectGameState
|
||||
@ -268,75 +212,6 @@ namespace VScriptCode
|
||||
|
||||
SCRIPT_CHECK_AND_RETURN(v, SQ_OK);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: checks whether this SDK build is a dedicated server
|
||||
//-----------------------------------------------------------------------------
|
||||
SQRESULT IsDedicated(HSQUIRRELVM v)
|
||||
{
|
||||
sq_pushbool(v, ::IsDedicated());
|
||||
SCRIPT_CHECK_AND_RETURN(v, SQ_OK);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: sets a class var on the server and each client
|
||||
// TODO: it might also be good to research potential ways to track class var
|
||||
// changes and sync them back to clients connecting after this has been called.
|
||||
//-----------------------------------------------------------------------------
|
||||
SQRESULT SetClassVarSynced(HSQUIRRELVM v)
|
||||
{
|
||||
const SQChar* key = nullptr;
|
||||
sq_getstring(v, 2, &key);
|
||||
|
||||
if (!VALID_CHARSTAR(key))
|
||||
{
|
||||
v_SQVM_ScriptError("Empty or null class key");
|
||||
SCRIPT_CHECK_AND_RETURN(v, SQ_ERROR);
|
||||
}
|
||||
|
||||
const SQChar* val = nullptr;
|
||||
sq_getstring(v, 3, &val);
|
||||
|
||||
if (!VALID_CHARSTAR(val))
|
||||
{
|
||||
v_SQVM_ScriptError("Empty or null class var");
|
||||
SCRIPT_CHECK_AND_RETURN(v, SQ_ERROR);
|
||||
}
|
||||
|
||||
const char* pArgs[3] = {
|
||||
"_setClassVarServer",
|
||||
key,
|
||||
val
|
||||
};
|
||||
|
||||
SVC_SetClassVar msg(key, val);
|
||||
const CCommand cmd((int)V_ARRAYSIZE(pArgs), pArgs, cmd_source_t::kCommandSrcCode);
|
||||
|
||||
bool failure = false;
|
||||
const int oldIdx = *g_nCommandClientIndex;
|
||||
|
||||
for (int i = 0; i < gpGlobals->maxClients; i++)
|
||||
{
|
||||
CClient* const client = g_pServer->GetClient(i);
|
||||
|
||||
// is this client fully connected
|
||||
if (client->GetSignonState() != SIGNONSTATE::SIGNONSTATE_FULL)
|
||||
continue;
|
||||
|
||||
if (client->SendNetMsgEx(&msg, false, true, false))
|
||||
{
|
||||
*g_nCommandClientIndex = client->GetUserID();
|
||||
v__setClassVarServer_f(cmd);
|
||||
}
|
||||
else // Not all clients have their class var set.
|
||||
failure = true;
|
||||
}
|
||||
|
||||
*g_nCommandClientIndex = oldIdx;
|
||||
|
||||
sq_pushbool(v, !failure);
|
||||
SCRIPT_CHECK_AND_RETURN(v, SQ_OK);
|
||||
}
|
||||
}
|
||||
|
||||
namespace PlayerEntity
|
||||
@ -405,7 +280,7 @@ void Script_RegisterServerFunctions(CSquirrelVM* s)
|
||||
{
|
||||
Script_RegisterCommonAbstractions(s);
|
||||
Script_RegisterCoreServerFunctions(s);
|
||||
Script_RegisterAdminPanelFunctions(s);
|
||||
Script_RegisterAdminServerFunctions(s);
|
||||
|
||||
Script_RegisterLiveAPIFunctions(s);
|
||||
}
|
||||
@ -421,28 +296,15 @@ void Script_RegisterServerEnums(CSquirrelVM* const s)
|
||||
//---------------------------------------------------------------------------------
|
||||
void Script_RegisterCoreServerFunctions(CSquirrelVM* s)
|
||||
{
|
||||
DEFINE_SERVER_SCRIPTFUNC_NAMED(s, IsServerActive, "Returns whether the server is active", "bool", "");
|
||||
DEFINE_SERVER_SCRIPTFUNC_NAMED(s, IsDedicated, "Returns whether this is a dedicated server", "bool", "");
|
||||
|
||||
DEFINE_SERVER_SCRIPTFUNC_NAMED(s, CreateServer, "Starts server with the specified settings", "void", "string, string, string, string, int");
|
||||
DEFINE_SERVER_SCRIPTFUNC_NAMED(s, DestroyServer, "Shuts the local server down", "void", "");
|
||||
|
||||
DEFINE_SERVER_SCRIPTFUNC_NAMED(s, SetAutoReloadState, "Set whether we can auto-reload the server", "void", "bool");
|
||||
|
||||
DEFINE_SERVER_SCRIPTFUNC_NAMED(s, GetServerID, "Gets the current server ID", "string", "");
|
||||
|
||||
DEFINE_SERVER_SCRIPTFUNC_NAMED(s, SetClassVarSynced, "Change a variable in the class settings for server and all connected clients", "bool", "string, string");
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------
|
||||
// Purpose: admin panel script functions
|
||||
// Purpose: admin server script functions
|
||||
// Input : *s -
|
||||
//
|
||||
// Ideally, these get dropped entirely in favor of remote functions. Currently,
|
||||
// the s3 build only supports remote function calls from server to client/ui.
|
||||
// Client/ui to server is all done through clientcommands.
|
||||
//---------------------------------------------------------------------------------
|
||||
void Script_RegisterAdminPanelFunctions(CSquirrelVM* s)
|
||||
void Script_RegisterAdminServerFunctions(CSquirrelVM* s)
|
||||
{
|
||||
DEFINE_SERVER_SCRIPTFUNC_NAMED(s, GetNumHumanPlayers, "Gets the number of human players on the server", "int", "");
|
||||
DEFINE_SERVER_SCRIPTFUNC_NAMED(s, GetNumFakeClients, "Gets the number of bot players on the server", "int", "");
|
||||
|
@ -29,7 +29,7 @@ namespace VScriptCode
|
||||
|
||||
void Script_RegisterServerFunctions(CSquirrelVM* s);
|
||||
void Script_RegisterCoreServerFunctions(CSquirrelVM* s);
|
||||
void Script_RegisterAdminPanelFunctions(CSquirrelVM* s);
|
||||
void Script_RegisterAdminServerFunctions(CSquirrelVM* s);
|
||||
|
||||
void Script_RegisterServerEnums(CSquirrelVM* const s);
|
||||
|
||||
|
@ -58,6 +58,9 @@ CBrowser::CBrowser(void)
|
||||
memset(m_serverNetKeyTextBuf, '\0', sizeof(m_serverNetKeyTextBuf));
|
||||
|
||||
m_lockedIconDataResource = GetModuleResource(IDB_PNG2);
|
||||
|
||||
m_levelName = "mp_lobby";
|
||||
m_gameMode = "dev_default";
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -517,47 +520,71 @@ void CBrowser::HiddenServersModal(void)
|
||||
}
|
||||
}
|
||||
|
||||
void CBrowser::HandleInvalidFields(const bool offline)
|
||||
{
|
||||
if (!offline && m_serverName.empty())
|
||||
{
|
||||
m_hostMessage = "Server name is required.";
|
||||
m_hostMessageColor = ImVec4(1.00f, 0.00f, 0.00f, 1.00f);
|
||||
}
|
||||
else if (m_gameMode.empty())
|
||||
{
|
||||
m_hostMessage = "Game mode is required.";
|
||||
m_hostMessageColor = ImVec4(1.00f, 0.00f, 0.00f, 1.00f);
|
||||
}
|
||||
else if (m_levelName.empty())
|
||||
{
|
||||
m_hostMessage = "Level name is required.";
|
||||
m_hostMessageColor = ImVec4(1.00f, 0.00f, 0.00f, 1.00f);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: draws the host section
|
||||
//-----------------------------------------------------------------------------
|
||||
void CBrowser::DrawHostPanel(void)
|
||||
{
|
||||
#ifndef CLIENT_DLL
|
||||
NetGameServer_t& details = g_ServerHostManager.GetDetails();
|
||||
if (ImGui::InputTextWithHint("##ServerHost_ServerName", "Server name (required)", &m_serverName))
|
||||
{
|
||||
hostname->SetValue(m_serverName.c_str());
|
||||
}
|
||||
|
||||
if (ImGui::InputTextWithHint("##ServerHost_ServerDesc", "Server description (optional)", &m_serverDescription))
|
||||
{
|
||||
hostdesc.SetValue(m_serverDescription.c_str());
|
||||
}
|
||||
|
||||
ImGui::InputTextWithHint("##ServerHost_ServerName", "Server name (required)", &details.name);
|
||||
ImGui::InputTextWithHint("##ServerHost_ServerDesc", "Server description (optional)", &details.description);
|
||||
ImGui::Spacing();
|
||||
|
||||
const char* const selectedPlaylists = details.playlist.c_str();
|
||||
|
||||
if (ImGui::BeginCombo("Mode", selectedPlaylists))
|
||||
if (ImGui::BeginCombo("Mode", m_gameMode.c_str()))
|
||||
{
|
||||
for (const CUtlString& svPlaylist : g_vecAllPlaylists)
|
||||
for (const CUtlString& playlist : g_vecAllPlaylists)
|
||||
{
|
||||
const char* const cachedPlaylists = svPlaylist.String();
|
||||
const char* const cachedPlaylists = playlist.String();
|
||||
|
||||
if (ImGui::Selectable(cachedPlaylists, (strcmp(cachedPlaylists, selectedPlaylists) == 0)))
|
||||
if (ImGui::Selectable(cachedPlaylists,
|
||||
playlist.IsEqual_CaseInsensitive(m_gameMode.c_str())))
|
||||
{
|
||||
details.playlist = svPlaylist;
|
||||
m_gameMode = cachedPlaylists;
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
|
||||
if (ImGui::BeginCombo("Map", details.map.c_str()))
|
||||
if (ImGui::BeginCombo("Map", m_levelName.c_str()))
|
||||
{
|
||||
g_InstalledMapsMutex.Lock();
|
||||
|
||||
FOR_EACH_VEC(g_InstalledMaps, i)
|
||||
for (const CUtlString& mapName : g_InstalledMaps)
|
||||
{
|
||||
const CUtlString& mapName = g_InstalledMaps[i];
|
||||
const char* const cachedMapName = mapName.String();
|
||||
|
||||
if (ImGui::Selectable(mapName.String(),
|
||||
mapName.IsEqual_CaseInsensitive(details.map.c_str())))
|
||||
if (ImGui::Selectable(cachedMapName,
|
||||
mapName.IsEqual_CaseInsensitive(m_levelName.c_str())))
|
||||
{
|
||||
details.map = mapName.String();
|
||||
m_levelName = cachedMapName;
|
||||
}
|
||||
}
|
||||
|
||||
@ -599,37 +626,22 @@ void CBrowser::DrawHostPanel(void)
|
||||
const bool serverActive = g_pServer->IsActive();
|
||||
const bool clientActive = g_pClientState->IsActive();
|
||||
|
||||
const bool isOffline = g_ServerHostManager.GetVisibility() == ServerVisibility_e::OFFLINE;
|
||||
const bool hasName = isOffline ? true : !m_serverName.empty();
|
||||
|
||||
if (!g_pHostState->m_bActiveGame)
|
||||
{
|
||||
if (ImGui::Button("Start server", ImVec2(contentRegionMax.x, 32)))
|
||||
{
|
||||
m_hostMessage.clear();
|
||||
|
||||
const bool enforceField = g_ServerHostManager.GetVisibility() == ServerVisibility_e::OFFLINE
|
||||
? true
|
||||
: !details.name.empty();
|
||||
|
||||
if (enforceField && !details.playlist.empty() && !details.map.empty())
|
||||
if (hasName && !m_levelName.empty() && !m_gameMode.empty())
|
||||
{
|
||||
g_ServerHostManager.LaunchServer(serverActive); // Launch server.
|
||||
g_ServerHostManager.LaunchServer(m_levelName.c_str(), m_gameMode.c_str()); // Launch server.
|
||||
}
|
||||
else
|
||||
{
|
||||
if (details.name.empty())
|
||||
{
|
||||
m_hostMessage = "Server name is required.";
|
||||
m_hostMessageColor = ImVec4(1.00f, 0.00f, 0.00f, 1.00f);
|
||||
}
|
||||
else if (details.playlist.empty())
|
||||
{
|
||||
m_hostMessage = "Playlist is required.";
|
||||
m_hostMessageColor = ImVec4(1.00f, 0.00f, 0.00f, 1.00f);
|
||||
}
|
||||
else if (details.map.empty())
|
||||
{
|
||||
m_hostMessage = "Level name is required.";
|
||||
m_hostMessageColor = ImVec4(1.00f, 0.00f, 0.00f, 1.00f);
|
||||
}
|
||||
HandleInvalidFields(isOffline);
|
||||
}
|
||||
}
|
||||
|
||||
@ -654,12 +666,14 @@ void CBrowser::DrawHostPanel(void)
|
||||
|
||||
if (ImGui::Button("Change level", ImVec2(contentRegionMax.x, 32)))
|
||||
{
|
||||
if (!details.map.empty())
|
||||
if (!m_levelName.empty() && !m_gameMode.empty())
|
||||
{
|
||||
g_ServerHostManager.LaunchServer(serverActive);
|
||||
g_ServerHostManager.ChangeLevel(m_levelName.c_str(), m_gameMode.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
HandleInvalidFields(isOffline);
|
||||
|
||||
m_hostMessage = "Failed to change level: 'levelname' was empty.";
|
||||
m_hostMessageColor = ImVec4(1.00f, 0.00f, 0.00f, 1.00f);
|
||||
}
|
||||
@ -783,37 +797,23 @@ void CBrowser::UpdateHostingStatus(void)
|
||||
}
|
||||
case HostStatus_e::HOSTING:
|
||||
{
|
||||
if (*g_nServerRemoteChecksum == NULL) // Check if script checksum is valid yet.
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
const ServerVisibility_e serverVisibility = g_ServerHostManager.GetVisibility();
|
||||
NetGameServer_t& details = g_ServerHostManager.GetDetails();
|
||||
|
||||
if (serverVisibility == ServerVisibility_e::OFFLINE)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (*g_nServerRemoteChecksum == NULL) // Check if script checksum is valid yet.
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
switch (serverVisibility)
|
||||
{
|
||||
|
||||
case ServerVisibility_e::HIDDEN:
|
||||
details.hidden = true;
|
||||
break;
|
||||
case ServerVisibility_e::PUBLIC:
|
||||
details.hidden = false;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
const NetGameServer_t netGameServer
|
||||
{
|
||||
details.name,
|
||||
details.description,
|
||||
details.hidden,
|
||||
hostname->GetString(),
|
||||
hostdesc.GetString(),
|
||||
serverVisibility == ServerVisibility_e::PUBLIC,
|
||||
g_pHostState->m_levelName,
|
||||
v_Playlists_GetCurrent(),
|
||||
hostip->GetString(),
|
||||
|
@ -26,6 +26,8 @@ public:
|
||||
void RefreshServerList(void);
|
||||
|
||||
void HiddenServersModal(void);
|
||||
|
||||
void HandleInvalidFields(const bool offline);
|
||||
void DrawHostPanel(void);
|
||||
|
||||
void UpdateHostingStatus(void);
|
||||
@ -72,6 +74,12 @@ private:
|
||||
////////////////////
|
||||
string m_hiddenServerRequestMessage;
|
||||
ImVec4 m_hiddenServerMessageColor;
|
||||
|
||||
string m_serverName;
|
||||
string m_serverDescription;
|
||||
|
||||
string m_levelName;
|
||||
string m_gameMode;
|
||||
};
|
||||
|
||||
extern CBrowser g_Browser;
|
||||
|
@ -6,6 +6,7 @@
|
||||
//
|
||||
//=============================================================================//
|
||||
#include "tier0/frametask.h"
|
||||
#include "common/callback.h"
|
||||
#include "rtech/playlists/playlists.h"
|
||||
#include "engine/cmd.h"
|
||||
#include "hostmanager.h"
|
||||
@ -20,32 +21,52 @@ CServerHostManager::CServerHostManager(void)
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Launch server with given parameters
|
||||
// Purpose: internal server launch handler
|
||||
//-----------------------------------------------------------------------------
|
||||
void CServerHostManager::LaunchServer(const bool changeLevel) const
|
||||
static void HostManager_HandleCommandInternal(const char* const map, const char* const mode, const bool changeLevel)
|
||||
{
|
||||
if (!ThreadInMainThread())
|
||||
Assert(!ThreadInServerFrameThread(), "Use server script GameRules_ChangeMap() instead!");
|
||||
|
||||
Msg(eDLL_T::ENGINE, "Starting server with name: \"%s\" map: \"%s\" mode: \"%s\"\n",
|
||||
hostname->GetString(), map, mode);
|
||||
|
||||
// NOTE: when the provided playlist is the same as the one we're currently
|
||||
// on, and there's already a pending map load request, the game will run
|
||||
// "map <mapName>" in Playlists_Parse, where the map name is dictated by
|
||||
// g_pPlaylistMapToLoad. If changelevel was specified, we have to null the
|
||||
// requested map here as to prevent Playlists_Parse from running the map
|
||||
// command on it, as we are going to run the changelevel command anyways.
|
||||
// Not doing this will result in running both map and changelevel commands.
|
||||
if (changeLevel)
|
||||
*g_pPlaylistMapToLoad = '\0';
|
||||
|
||||
const bool samePlaylist = v_Playlists_Parse(mode);
|
||||
char commandBuf[512];
|
||||
|
||||
if (!samePlaylist || !*g_pPlaylistMapToLoad)
|
||||
{
|
||||
g_TaskQueue.Dispatch([this, changeLevel]()
|
||||
{
|
||||
this->LaunchServer(changeLevel);
|
||||
}, 0);
|
||||
return;
|
||||
snprintf(commandBuf, sizeof(commandBuf), "%s %s\n", changeLevel ? "changelevel" : "map", map);
|
||||
Cbuf_AddText(Cbuf_GetCurrentPlayer(), commandBuf, cmd_source_t::kCommandSrcCode);
|
||||
}
|
||||
|
||||
Msg(eDLL_T::ENGINE, "Starting server with name: \"%s\" map: \"%s\" playlist: \"%s\"\n",
|
||||
m_Server.name.c_str(), m_Server.map.c_str(), m_Server.playlist.c_str());
|
||||
snprintf(commandBuf, sizeof(commandBuf), "mp_gamemode %s\n", mode);
|
||||
Cbuf_AddText(Cbuf_GetCurrentPlayer(), commandBuf, cmd_source_t::kCommandSrcCode);
|
||||
}
|
||||
|
||||
/*
|
||||
* Playlist gets parsed in two instances, first in Playlists_Parse() with all the necessary
|
||||
* values. Then when you would normally call launchplaylist which calls StartPlaylist it would cmd
|
||||
* call mp_gamemode which parses the gamemode specific part of the playlist..
|
||||
*/
|
||||
v_Playlists_Parse(m_Server.playlist.c_str());
|
||||
mp_gamemode->SetValue(m_Server.playlist.c_str());
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Launch server with given parameters
|
||||
//-----------------------------------------------------------------------------
|
||||
void CServerHostManager::LaunchServer(const char* const map, const char* const mode) const
|
||||
{
|
||||
HostManager_HandleCommandInternal(map, mode, false);
|
||||
}
|
||||
|
||||
const string command = Format("%s \"%s\"", changeLevel ? "changelevel" : "map", m_Server.map.c_str());
|
||||
Cbuf_AddText(Cbuf_GetCurrentPlayer(), command.c_str(), cmd_source_t::kCommandSrcCode);
|
||||
//-----------------------------------------------------------------------------
|
||||
// Purpose: Change level with given parameters
|
||||
//-----------------------------------------------------------------------------
|
||||
void CServerHostManager::ChangeLevel(const char* const map, const char* const mode) const
|
||||
{
|
||||
HostManager_HandleCommandInternal(map, mode, true);
|
||||
}
|
||||
|
||||
CServerHostManager g_ServerHostManager;
|
||||
|
@ -20,7 +20,8 @@ class CServerHostManager
|
||||
public:
|
||||
CServerHostManager();
|
||||
|
||||
void LaunchServer(const bool changeLevel) const;
|
||||
void LaunchServer(const char* const map, const char* const mode) const;
|
||||
void ChangeLevel(const char* const map, const char* const mode) const;
|
||||
|
||||
inline HostStatus_e GetHostStatus(void) const { return m_HostingStatus; }
|
||||
inline void SetHostStatus(const HostStatus_e hostStatus) { m_HostingStatus = hostStatus; }
|
||||
@ -28,8 +29,6 @@ public:
|
||||
inline ServerVisibility_e GetVisibility(void) const { return m_ServerVisibility; }
|
||||
inline void SetVisibility(const ServerVisibility_e visibility) { m_ServerVisibility = visibility; }
|
||||
|
||||
inline NetGameServer_t& GetDetails() { return m_Server; }
|
||||
|
||||
inline void SetCurrentToken(const string& token) { m_Token = token; }
|
||||
inline const string& GetCurrentToken() const { return m_Token; }
|
||||
|
||||
@ -43,8 +42,6 @@ private:
|
||||
HostStatus_e m_HostingStatus;
|
||||
ServerVisibility_e m_ServerVisibility;
|
||||
|
||||
NetGameServer_t m_Server;
|
||||
|
||||
string m_Token;
|
||||
string m_ErrorMsg;
|
||||
string m_HostIP;
|
||||
|
@ -23,9 +23,9 @@ void(*ServerScriptRegisterEnum_Callback)(CSquirrelVM* const s) = nullptr;
|
||||
void(*ClientScriptRegisterEnum_Callback)(CSquirrelVM* const s) = nullptr;
|
||||
void(*UIScriptRegisterEnum_Callback)(CSquirrelVM* const s) = nullptr;
|
||||
|
||||
// Admin panel functions, NULL on client only builds.
|
||||
void(*CoreServerScriptRegister_Callback)(CSquirrelVM* const s) = nullptr;
|
||||
void(*AdminPanelScriptRegister_Callback)(CSquirrelVM* const s) = nullptr;
|
||||
// Admin panel functions, NULL on dedicated and client only builds.
|
||||
void(*UiServerScriptRegister_Callback)(CSquirrelVM* const s) = nullptr;
|
||||
void(*UiAdminPanelScriptRegister_Callback)(CSquirrelVM* const s) = nullptr;
|
||||
|
||||
// Registering constants in scripts.
|
||||
void(*ScriptConstantRegister_Callback)(CSquirrelVM* const s) = nullptr;
|
||||
@ -66,10 +66,11 @@ bool CSquirrelVM::Init(CSquirrelVM* s, SQCONTEXT context, SQFloat curTime)
|
||||
if (UiScriptRegister_Callback)
|
||||
UiScriptRegister_Callback(s);
|
||||
|
||||
if (CoreServerScriptRegister_Callback)
|
||||
CoreServerScriptRegister_Callback(s);
|
||||
if (AdminPanelScriptRegister_Callback)
|
||||
AdminPanelScriptRegister_Callback(s);
|
||||
if (UiServerScriptRegister_Callback)
|
||||
UiServerScriptRegister_Callback(s);
|
||||
|
||||
if (UiAdminPanelScriptRegister_Callback)
|
||||
UiAdminPanelScriptRegister_Callback(s);
|
||||
|
||||
break;
|
||||
}
|
||||
|
@ -64,8 +64,8 @@ extern void(*ServerScriptRegisterEnum_Callback)(CSquirrelVM* const s);
|
||||
extern void(*ClientScriptRegisterEnum_Callback)(CSquirrelVM* const s);
|
||||
extern void(*UIScriptRegisterEnum_Callback)(CSquirrelVM* const s);
|
||||
|
||||
extern void(*CoreServerScriptRegister_Callback)(CSquirrelVM* const s);
|
||||
extern void(*AdminPanelScriptRegister_Callback)(CSquirrelVM* const s);
|
||||
extern void(*UiServerScriptRegister_Callback)(CSquirrelVM* const s);
|
||||
extern void(*UiAdminPanelScriptRegister_Callback)(CSquirrelVM* const s);
|
||||
|
||||
extern void(*ScriptConstantRegister_Callback)(CSquirrelVM* const s);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user