Allow using AI in lan racing game

This commit is contained in:
Benau 2019-10-09 14:08:22 +08:00
parent c801191d80
commit a26f67bf16
9 changed files with 136 additions and 31 deletions

View File

@ -251,6 +251,7 @@
#include "utils/log.hpp" #include "utils/log.hpp"
#include "utils/mini_glm.hpp" #include "utils/mini_glm.hpp"
#include "utils/profiler.hpp" #include "utils/profiler.hpp"
#include "utils/separate_process.hpp"
#include "utils/string_utils.hpp" #include "utils/string_utils.hpp"
#include "utils/translation.hpp" #include "utils/translation.hpp"
@ -1326,6 +1327,14 @@ int handleCmdLine(bool has_server_config, bool has_parent_process)
} }
} }
int ai_num = 0;
if (CommandLine::has("--server-ai", &ai_num))
{
Log::info("main", "Add %d server ai(s) server configurable will be "
"disabled.", ai_num);
ServerConfig::m_server_configurable = false;
}
std::string ipv4; std::string ipv4;
std::string ipv6; std::string ipv6;
bool has_ipv4 = CommandLine::has("--connect-now", &ipv4); bool has_ipv4 = CommandLine::has("--connect-now", &ipv4);
@ -1407,6 +1416,18 @@ int handleCmdLine(bool has_server_config, bool has_parent_process)
Log::info("main", "Creating a LAN server '%s'.", Log::info("main", "Creating a LAN server '%s'.",
server_name.c_str()); server_name.c_str());
} }
if (ai_num > 0)
{
STKHost::get()->setSeparateProcess(
new SeparateProcess(
SeparateProcess::getCurrentExecutableLocation(),
std::string("--stdout=server_ai.log --no-graphics"
" --auto-connect --connect-now=127.0.0.1:") +
StringUtils::toString(STKHost::get()->getPrivatePort()) +
" --no-console-log --network-ai="
+ StringUtils::toString(ai_num), false/*create_pipe*/,
"childprocess_ai"/*childprocess_name*/));
}
} }
if (CommandLine::has("--auto-connect")) if (CommandLine::has("--auto-connect"))

View File

@ -361,10 +361,12 @@ void ClientLobby::update(int ticks)
case LINKED: case LINKED:
{ {
NetworkConfig::get()->clearServerCapabilities(); NetworkConfig::get()->clearServerCapabilities();
std::string ua = StringUtils::getUserAgentString();
if (NetworkConfig::get()->isNetworkAITester())
ua = "AI";
NetworkString* ns = getNetworkString(); NetworkString* ns = getNetworkString();
ns->addUInt8(LE_CONNECTION_REQUESTED) ns->addUInt8(LE_CONNECTION_REQUESTED)
.addUInt32(ServerConfig::m_server_version) .addUInt32(ServerConfig::m_server_version).encodeString(ua)
.encodeString(StringUtils::getUserAgentString())
.addUInt16((uint16_t)stk_config->m_network_capabilities.size()); .addUInt16((uint16_t)stk_config->m_network_capabilities.size());
for (const std::string& cap : stk_config->m_network_capabilities) for (const std::string& cap : stk_config->m_network_capabilities)
ns->encodeString(cap); ns->encodeString(cap);
@ -391,7 +393,10 @@ void ClientLobby::update(int ticks)
bool encryption = false; bool encryption = false;
uint32_t id = PlayerManager::getCurrentOnlineId(); uint32_t id = PlayerManager::getCurrentOnlineId();
bool lan_ai = !m_server->supportsEncryption() &&
NetworkConfig::get()->isNetworkAITester();
if (lan_ai)
id = 0;
BareNetworkString* rest = new BareNetworkString(); BareNetworkString* rest = new BareNetworkString();
if (m_server->supportsEncryption() && id != 0) if (m_server->supportsEncryption() && id != 0)
{ {
@ -410,11 +415,22 @@ void ClientLobby::update(int ticks)
rest->encodeString(ServerConfig::m_private_server_password) rest->encodeString(ServerConfig::m_private_server_password)
.addUInt8(player_count); .addUInt8(player_count);
for (auto& p : NetworkConfig::get()->getNetworkPlayers()) for (unsigned i = 0;
i < NetworkConfig::get()->getNetworkPlayers().size(); i++)
{ {
core::stringw name; auto& p = NetworkConfig::get()->getNetworkPlayers()[i];
PlayerProfile* player = std::get<1>(p); PlayerProfile* player = std::get<1>(p);
rest->encodeString(player->getName()). core::stringw name = player->getName();
if (lan_ai)
{
// I18N: Shown in lobby to indicate it's a bot in LAN game
name = _("Bot");
if (i > 0)
{
name += core::stringw(" ") + StringUtils::toWString(i);
}
}
rest->encodeString(name).
addFloat(player->getDefaultKartColor()); addFloat(player->getDefaultKartColor());
// Per-player handicap // Per-player handicap
rest->addUInt8(std::get<2>(p)); rest->addUInt8(std::get<2>(p));

View File

@ -3201,7 +3201,7 @@ void ServerLobby::updateServerOwner()
for (auto peer: peers) for (auto peer: peers)
{ {
// Only 127.0.0.1 can be server owner in case of graphics-client-server // Only 127.0.0.1 can be server owner in case of graphics-client-server
if (peer->isValidated() && if (peer->isValidated() && peer->getUserVersion() != "AI" &&
(NetworkConfig::get()->getServerIdFile().empty() || (NetworkConfig::get()->getServerIdFile().empty() ||
peer->getAddress().getIP() == 0x7f000001)) peer->getAddress().getIP() == 0x7f000001))
{ {

View File

@ -1639,3 +1639,17 @@ void STKHost::updatePlayers(unsigned* ingame, unsigned* waiting,
if (total) if (total)
*total = total_players; *total = total_players;
} // updatePlayers } // updatePlayers
// ----------------------------------------------------------------------------
/** True if this is a client and server in graphics mode made by server
* creation screen. */
bool STKHost::isClientServer() const
{
return NetworkConfig::get()->isClient() && m_separate_process != NULL;
} // isClientServer
// ----------------------------------------------------------------------------
bool STKHost::hasServerAI() const
{
return NetworkConfig::get()->isServer() && m_separate_process != NULL;
} // hasServerAI

View File

@ -37,6 +37,7 @@
#include <enet/enet.h> #include <enet/enet.h>
#include <atomic> #include <atomic>
#include <cassert>
#include <list> #include <list>
#include <functional> #include <functional>
#include <map> #include <map>
@ -340,9 +341,15 @@ public:
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
void sendToServer(NetworkString *data, bool reliable = true); void sendToServer(NetworkString *data, bool reliable = true);
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
/** True if this is a client and server in graphics mode made by server bool isClientServer() const;
* creation screen. */ // ------------------------------------------------------------------------
bool isClientServer() const { return m_separate_process != NULL; } bool hasServerAI() const;
// ------------------------------------------------------------------------
void setSeparateProcess(SeparateProcess* p)
{
assert(m_separate_process == NULL);
m_separate_process = p;
}
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
void initClientNetwork(ENetEvent& event, Network* new_network); void initClientNetwork(ENetEvent& event, Network* new_network);
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------

View File

@ -86,6 +86,7 @@ void CreateServerScreen::loadedFromFile()
void CreateServerScreen::init() void CreateServerScreen::init()
{ {
Screen::init(); Screen::init();
m_supports_ai = NetworkConfig::get()->isLAN();
m_info_widget->setText("", false); m_info_widget->setText("", false);
LabelWidget *title = getWidget<LabelWidget>("title"); LabelWidget *title = getWidget<LabelWidget>("title");
@ -142,7 +143,14 @@ void CreateServerScreen::eventCallback(Widget* widget, const std::string& name,
updateMoreOption(selection); updateMoreOption(selection);
m_prev_mode = selection; m_prev_mode = selection;
} }
else if (name == m_max_players_widget->m_properties[PROP_ID] &&
m_supports_ai)
{
m_prev_value = m_more_options_spinner->getValue();
const int selection =
m_game_mode_widget->getSelection(PLAYER_ID_GAME_MASTER);
updateMoreOption(selection);
}
} // eventCallback } // eventCallback
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@ -154,17 +162,39 @@ void CreateServerScreen::updateMoreOption(int game_mode)
case 1: case 1:
{ {
m_more_options_text->setVisible(true); m_more_options_text->setVisible(true);
m_more_options_spinner->setVisible(true);
m_more_options_spinner->clearLabels();
if (m_supports_ai)
{
m_more_options_text->setText(_("Number of AI karts"),
false);
for (int i = 0; i <= m_max_players_widget->getValue() - 2; i++)
{
m_more_options_spinner->addLabel(
StringUtils::toWString(i));
}
if (m_prev_value > m_max_players_widget->getValue() - 2)
{
m_more_options_spinner->setValue(
m_max_players_widget->getValue() - 2);
}
else
m_more_options_spinner->setValue(m_prev_value);
}
else
{
//I18N: In the create server screen //I18N: In the create server screen
m_more_options_text->setText(_("No. of grand prix track(s)"), m_more_options_text->setText(_("No. of grand prix track(s)"),
false); false);
m_more_options_spinner->setVisible(true);
m_more_options_spinner->clearLabels();
m_more_options_spinner->addLabel(_("Disabled")); m_more_options_spinner->addLabel(_("Disabled"));
for (int i = 1; i <= 20; i++) for (int i = 1; i <= 20; i++)
{ {
m_more_options_spinner->addLabel(StringUtils::toWString(i)); m_more_options_spinner->addLabel(
StringUtils::toWString(i));
} }
m_more_options_spinner->setValue(m_prev_value); m_more_options_spinner->setValue(m_prev_value);
}
break; break;
} }
case 2: case 2:
@ -359,11 +389,19 @@ void CreateServerScreen::createServer()
server_cfg << " --battle-mode=" << esi; server_cfg << " --battle-mode=" << esi;
} }
else else
{
if (m_supports_ai)
{
if (esi > 0)
server_cfg << " --server-ai=" << esi;
}
else
{ {
// Grand prix track count // Grand prix track count
if (esi > 0) if (esi > 0)
server_cfg << " --network-gp=" << esi; server_cfg << " --network-gp=" << esi;
} }
}
m_prev_mode = gamemode_widget->getSelection(PLAYER_ID_GAME_MASTER); m_prev_mode = gamemode_widget->getSelection(PLAYER_ID_GAME_MASTER);
m_prev_value = esi; m_prev_value = esi;
} }

View File

@ -34,6 +34,8 @@ class CreateServerScreen : public GUIEngine::Screen,
private: private:
int m_prev_mode, m_prev_value; int m_prev_mode, m_prev_value;
bool m_supports_ai;
friend class GUIEngine::ScreenSingleton<CreateServerScreen>; friend class GUIEngine::ScreenSingleton<CreateServerScreen>;
CreateServerScreen(); CreateServerScreen();

View File

@ -79,14 +79,15 @@ std::string SeparateProcess::getCurrentExecutableLocation()
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
SeparateProcess::SeparateProcess(const std::string& exe, SeparateProcess::SeparateProcess(const std::string& exe,
const std::string& argument, bool create_pipe) const std::string& argument, bool create_pipe,
const std::string& childprocess_name)
{ {
#ifdef ANDROID #ifdef ANDROID
m_child_handle = NULL; m_child_handle = NULL;
m_child_abort_proc = NULL; m_child_abort_proc = NULL;
#endif #endif
if (!createChildProcess(exe, argument, create_pipe)) if (!createChildProcess(exe, argument, create_pipe, childprocess_name))
{ {
Log::error("SeparateProcess", "Failed to run %s %s", Log::error("SeparateProcess", "Failed to run %s %s",
exe.c_str(), argument.c_str()); exe.c_str(), argument.c_str());
@ -184,7 +185,8 @@ SeparateProcess::~SeparateProcess()
#if defined(WIN32) #if defined(WIN32)
bool SeparateProcess::createChildProcess(const std::string& exe, bool SeparateProcess::createChildProcess(const std::string& exe,
const std::string& argument, const std::string& argument,
bool create_pipe) bool create_pipe,
const std::string& childprocess_name)
{ {
// Based on: https://msdn.microsoft.com/en-us/library/windows/desktop/ms682499(v=vs.85).aspx // Based on: https://msdn.microsoft.com/en-us/library/windows/desktop/ms682499(v=vs.85).aspx
SECURITY_ATTRIBUTES sec_attr; SECURITY_ATTRIBUTES sec_attr;
@ -281,7 +283,8 @@ bool SeparateProcess::createChildProcess(const std::string& exe,
bool SeparateProcess::createChildProcess(const std::string& exe, bool SeparateProcess::createChildProcess(const std::string& exe,
const std::string& argument, const std::string& argument,
bool create_pipe) bool create_pipe,
const std::string& childprocess_name)
{ {
if (create_pipe) if (create_pipe)
{ {
@ -324,7 +327,8 @@ bool SeparateProcess::createChildProcess(const std::string& exe,
Log::info("SeparateProcess", "Data dir found in: %s", data_path.c_str()); Log::info("SeparateProcess", "Data dir found in: %s", data_path.c_str());
std::string child_path = data_path + "/files/libchildprocess.so"; std::string child_path = data_path + "/files/lib" +
childprocess_name + ".so";
if (access(child_path.c_str(), R_OK) != 0) if (access(child_path.c_str(), R_OK) != 0)
{ {
@ -408,7 +412,8 @@ bool SeparateProcess::createChildProcess(const std::string& exe,
bool SeparateProcess::createChildProcess(const std::string& exe, bool SeparateProcess::createChildProcess(const std::string& exe,
const std::string& argument, const std::string& argument,
bool create_pipe) bool create_pipe,
const std::string& childprocess_name)
{ {
const int PIPE_READ=0; const int PIPE_READ=0;
const int PIPE_WRITE=1; const int PIPE_WRITE=1;

View File

@ -51,7 +51,8 @@ private:
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
bool createChildProcess(const std::string& exe, bool createChildProcess(const std::string& exe,
const std::string& argument, bool create_pipe); const std::string& argument, bool create_pipe,
const std::string& childprocess_name);
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
std::string getLine(); std::string getLine();
@ -60,7 +61,8 @@ public:
static std::string getCurrentExecutableLocation(); static std::string getCurrentExecutableLocation();
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
SeparateProcess(const std::string& exe, const std::string& argument, SeparateProcess(const std::string& exe, const std::string& argument,
bool create_pipe = false); bool create_pipe = false,
const std::string& childprocess_name = "childprocess");
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
~SeparateProcess(); ~SeparateProcess();
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------