Allow server AI starting in a same process with client
This commit is contained in:
parent
92a11c075a
commit
e0f494abcd
@ -36,7 +36,9 @@ NetworkAIController::NetworkAIController(AbstractKart *kart,
|
||||
{
|
||||
m_ai_controller = ai;
|
||||
m_ai_controls = new KartControl;
|
||||
Camera::createCamera(kart, local_player_id);
|
||||
// We only need camera for real AI instance for debugging view
|
||||
if (NetworkConfig::get()->isNetworkAIInstance())
|
||||
Camera::createCamera(kart, local_player_id);
|
||||
ai->setControls(m_ai_controls);
|
||||
} // NetworkAIController
|
||||
|
||||
@ -47,6 +49,12 @@ NetworkAIController::~NetworkAIController()
|
||||
delete m_ai_controls;
|
||||
} // ~NetworkAIController
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
bool NetworkAIController::isLocalPlayerController() const
|
||||
{
|
||||
return NetworkConfig::get()->isNetworkAIInstance();
|
||||
} // isLocalPlayerController
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
void NetworkAIController::update(int ticks)
|
||||
{
|
||||
|
@ -38,6 +38,9 @@ public:
|
||||
virtual ~NetworkAIController();
|
||||
virtual void update(int ticks) OVERRIDE;
|
||||
virtual void reset() OVERRIDE;
|
||||
// ------------------------------------------------------------------------
|
||||
virtual bool isLocalPlayerController() const OVERRIDE;
|
||||
// ------------------------------------------------------------------------
|
||||
static void setAIFrequency(int freq) { m_ai_frequency = freq; }
|
||||
}; // class NetworkAIController
|
||||
|
||||
|
21
src/main.cpp
21
src/main.cpp
@ -1355,11 +1355,7 @@ 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;
|
||||
}
|
||||
NetworkConfig::get()->setNumFixedAI(ai_num);
|
||||
|
||||
std::string addr;
|
||||
bool has_addr = CommandLine::has("--connect-now", &addr);
|
||||
@ -1444,21 +1440,6 @@ int handleCmdLine(bool has_server_config, bool has_parent_process)
|
||||
Log::info("main", "Creating a LAN server '%s'.",
|
||||
server_name.c_str());
|
||||
}
|
||||
if (ai_num > 0)
|
||||
{
|
||||
std::string cmd =
|
||||
std::string("--stdout=server_ai.log --no-graphics"
|
||||
" --network-ai-freq=10 --connect-now=127.0.0.1:") +
|
||||
StringUtils::toString(STKHost::get()->getPrivatePort()) +
|
||||
" --no-console-log --disable-polling --network-ai="
|
||||
+ StringUtils::toString(ai_num);
|
||||
if (!server_password.empty())
|
||||
cmd += " --server-password=" + server_password;
|
||||
STKHost::get()->setSeparateProcess(
|
||||
new SeparateProcess(
|
||||
SeparateProcess::getCurrentExecutableLocation(), cmd,
|
||||
false/*create_pipe*/, "childprocess_ai"/*childprocess_name*/));
|
||||
}
|
||||
}
|
||||
|
||||
if (CommandLine::has("--auto-connect"))
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include "network/network_player_profile.hpp"
|
||||
#include "network/network_string.hpp"
|
||||
#include "network/protocols/game_events_protocol.hpp"
|
||||
#include "network/protocols/server_lobby.hpp"
|
||||
#include "network/server_config.hpp"
|
||||
#include "network/stk_host.hpp"
|
||||
#include "network/stk_peer.hpp"
|
||||
@ -172,7 +173,8 @@ void LinearWorld::reset(bool restart)
|
||||
*/
|
||||
void LinearWorld::update(int ticks)
|
||||
{
|
||||
if (NetworkConfig::get()->isServer() && getPhase() == RACE_PHASE)
|
||||
auto sl = LobbyProtocol::get<ServerLobby>();
|
||||
if (sl && getPhase() == RACE_PHASE)
|
||||
{
|
||||
bool all_players_finished = true;
|
||||
bool has_ai = false;
|
||||
@ -185,7 +187,7 @@ void LinearWorld::update(int ticks)
|
||||
if (npp)
|
||||
{
|
||||
auto peer = npp->getPeer();
|
||||
if (peer && peer->isAIPeer())
|
||||
if ((peer && peer->isAIPeer()) || sl->isAIProfile(npp))
|
||||
has_ai = true;
|
||||
else if (!getKart(i)->hasFinishedRace())
|
||||
all_players_finished = false;
|
||||
|
@ -468,7 +468,16 @@ std::shared_ptr<AbstractKart> World::createKart
|
||||
{
|
||||
case RaceManager::KT_PLAYER:
|
||||
{
|
||||
if (NetworkConfig::get()->isNetworkAIInstance())
|
||||
int local_player_count = -1;
|
||||
if (NetworkConfig::get()->isClient())
|
||||
{
|
||||
local_player_count =
|
||||
(int)NetworkConfig::get()->getNetworkPlayers().size();
|
||||
}
|
||||
// local_player_id >= local_player_count for fixed AI defined in create
|
||||
// server screen
|
||||
if (NetworkConfig::get()->isNetworkAIInstance() ||
|
||||
local_player_id >= local_player_count)
|
||||
{
|
||||
AIBaseController* ai = NULL;
|
||||
if (race_manager->isBattleMode())
|
||||
@ -495,8 +504,6 @@ std::shared_ptr<AbstractKart> World::createKart
|
||||
case RaceManager::KT_NETWORK_PLAYER:
|
||||
{
|
||||
controller = new NetworkPlayerController(new_kart.get());
|
||||
if (!online_name.empty())
|
||||
new_kart->setOnScreenText(online_name.c_str());
|
||||
m_num_players++;
|
||||
break;
|
||||
}
|
||||
@ -511,6 +518,8 @@ std::shared_ptr<AbstractKart> World::createKart
|
||||
break;
|
||||
}
|
||||
|
||||
if (!controller->isLocalPlayerController() && !online_name.empty())
|
||||
new_kart->setOnScreenText(online_name.c_str());
|
||||
new_kart->setController(controller);
|
||||
race_manager->setKartColor(index, ri->getHue());
|
||||
return new_kart;
|
||||
|
@ -73,6 +73,7 @@ NetworkConfig::NetworkConfig()
|
||||
m_network_ai_instance = false;
|
||||
m_state_frequency = 10;
|
||||
m_nat64_prefix_data.fill(-1);
|
||||
m_num_fixed_ai = 0;
|
||||
} // NetworkConfig
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
@ -85,6 +85,11 @@ private:
|
||||
* AI. (usually used together with ai-handling in server config) */
|
||||
bool m_network_ai_instance;
|
||||
|
||||
/** No. of fixed AI in all-in-one graphical client server, the player
|
||||
* connecting with 127.* or ::1/128 will be in charged of controlling the
|
||||
* AI. */
|
||||
unsigned m_num_fixed_ai;
|
||||
|
||||
/** The LAN port on which a client is waiting for a server connection. */
|
||||
uint16_t m_client_port;
|
||||
|
||||
@ -273,6 +278,10 @@ public:
|
||||
{ return m_nat64_prefix_data; }
|
||||
// ------------------------------------------------------------------------
|
||||
void initClientPort();
|
||||
// ------------------------------------------------------------------------
|
||||
void setNumFixedAI(unsigned num) { m_num_fixed_ai = num; }
|
||||
// ------------------------------------------------------------------------
|
||||
unsigned getNumFixedAI() const { return m_num_fixed_ai; }
|
||||
}; // class NetworkConfig
|
||||
|
||||
#endif // HEADER_NETWORK_CONFIG
|
||||
|
@ -802,7 +802,8 @@ void ClientLobby::updatePlayerList(Event* event)
|
||||
lp.m_user_name = _("%s (handicapped)", lp.m_user_name);
|
||||
}
|
||||
lp.m_kart_team = (KartTeam)data.getUInt8();
|
||||
if (lp.m_host_id == STKHost::get()->getMyHostId())
|
||||
// No handicap for AI peer
|
||||
if (!ai && lp.m_host_id == STKHost::get()->getMyHostId())
|
||||
{
|
||||
if (is_peer_server_owner)
|
||||
client_server_owner = true;
|
||||
|
@ -50,6 +50,7 @@ struct LobbyPlayer
|
||||
std::string m_country_code;
|
||||
/* Icon id for spectator in NetworkingLobby::loadedFromFile is 5. */
|
||||
bool isSpectator() const { return m_icon_id == 5; }
|
||||
bool isAI() const { return m_icon_id == 6; }
|
||||
};
|
||||
|
||||
class ClientLobby : public LobbyProtocol
|
||||
|
@ -99,6 +99,12 @@ void LobbyProtocol::configRemoteKart(
|
||||
// Set number of global and local players.
|
||||
race_manager->setNumPlayers((int)players.size(), local_player_size);
|
||||
|
||||
int local_player_count = -1;
|
||||
if (NetworkConfig::get()->isClient())
|
||||
{
|
||||
local_player_count =
|
||||
(int)NetworkConfig::get()->getNetworkPlayers().size();
|
||||
}
|
||||
// Create the kart information for the race manager:
|
||||
// -------------------------------------------------
|
||||
for (unsigned int i = 0; i < players.size(); i++)
|
||||
@ -110,7 +116,10 @@ void LobbyProtocol::configRemoteKart(
|
||||
// on the server, and all non-local players on a client (the local
|
||||
// karts are created in the ClientLobby).
|
||||
int local_player_id = profile->getLocalPlayerId();
|
||||
if (!is_local)
|
||||
|
||||
// local_player_id >= local_player_count for fixed AI defined in create
|
||||
// server screen
|
||||
if (!is_local || local_player_id >= local_player_count)
|
||||
{
|
||||
// No device or player profile is needed for remote kart.
|
||||
local_player_id =
|
||||
|
@ -57,6 +57,7 @@
|
||||
#include "utils/random_generator.hpp"
|
||||
#include "utils/string_utils.hpp"
|
||||
#include "utils/time.hpp"
|
||||
#include "utils/translation.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
@ -670,6 +671,8 @@ void ServerLobby::setup()
|
||||
for (auto player : ai->getPlayerProfiles())
|
||||
player->setKartName("");
|
||||
}
|
||||
for (auto ai : m_ai_profiles)
|
||||
ai->setKartName("");
|
||||
|
||||
StateManager::get()->resetActivePlayers();
|
||||
// We use maximum 16bit unsigned limit
|
||||
@ -1512,15 +1515,23 @@ void ServerLobby::asynchronousUpdate()
|
||||
ItemManager::updateRandomSeed(m_item_seed);
|
||||
m_game_setup->setRace(winner_vote);
|
||||
auto players = STKHost::get()->getPlayersForNewGame();
|
||||
auto ai = m_ai_peer.lock();
|
||||
if (supportsAI() && ai)
|
||||
auto ai_instance = m_ai_peer.lock();
|
||||
if (supportsAI())
|
||||
{
|
||||
auto ai_profiles = ai->getPlayerProfiles();
|
||||
if (m_ai_count > 0)
|
||||
if (ai_instance)
|
||||
{
|
||||
ai_profiles.resize(m_ai_count);
|
||||
players.insert(players.end(), ai_profiles.begin(),
|
||||
ai_profiles.end());
|
||||
auto ai_profiles = ai_instance->getPlayerProfiles();
|
||||
if (m_ai_count > 0)
|
||||
{
|
||||
ai_profiles.resize(m_ai_count);
|
||||
players.insert(players.end(), ai_profiles.begin(),
|
||||
ai_profiles.end());
|
||||
}
|
||||
}
|
||||
else if (!m_ai_profiles.empty())
|
||||
{
|
||||
players.insert(players.end(), m_ai_profiles.begin(),
|
||||
m_ai_profiles.end());
|
||||
}
|
||||
}
|
||||
m_game_setup->sortPlayersForGrandPrix(players);
|
||||
@ -3303,7 +3314,7 @@ void ServerLobby::connectionRequested(Event* event)
|
||||
|
||||
unsigned total_players = 0;
|
||||
STKHost::get()->updatePlayers(NULL, NULL, &total_players);
|
||||
if (total_players + player_count >
|
||||
if (total_players + player_count + m_ai_profiles.size() >
|
||||
(unsigned)ServerConfig::m_server_max_players)
|
||||
{
|
||||
NetworkString *message = getNetworkString(2);
|
||||
@ -3506,6 +3517,29 @@ void ServerLobby::handleUnencryptedConnection(std::shared_ptr<STKPeer> peer,
|
||||
.addUInt8(m_player_reports_table_exists ? 1 : 0);
|
||||
|
||||
peer->setSpectator(false);
|
||||
|
||||
// The 127.* or ::1/128 will be in charged for controlling AI
|
||||
if (m_ai_profiles.empty() && peer->getAddress().isLoopback())
|
||||
{
|
||||
unsigned ai_add = NetworkConfig::get()->getNumFixedAI();
|
||||
// We need to reserve at least 1 slot for new player
|
||||
if (player_count + ai_add + 1 > ServerConfig::m_server_max_players)
|
||||
ai_add = ServerConfig::m_server_max_players - player_count - 1;
|
||||
for (unsigned i = 0; i < ai_add; i++)
|
||||
{
|
||||
#ifdef SERVER_ONLY
|
||||
core::stringw name = L"Bot";
|
||||
#else
|
||||
core::stringw name = _("Bot");
|
||||
#endif
|
||||
if (i > 0)
|
||||
name += core::stringw(" ") + StringUtils::toWString(i);
|
||||
m_ai_profiles.insert(std::make_shared<NetworkPlayerProfile>
|
||||
(peer, name, peer->getHostId(), 0.0f, 0, HANDICAP_NONE,
|
||||
player_count + i, KART_TEAM_NONE, ""));
|
||||
}
|
||||
}
|
||||
|
||||
if (game_started)
|
||||
{
|
||||
peer->setWaitingForGame(true);
|
||||
@ -3538,6 +3572,7 @@ void ServerLobby::handleUnencryptedConnection(std::shared_ptr<STKPeer> peer,
|
||||
getRankingForPlayer(peer->getPlayerProfiles()[0]);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ENABLE_SQLITE3
|
||||
if (m_server_stats_table.empty() || peer->isAIPeer())
|
||||
return;
|
||||
@ -3624,28 +3659,36 @@ void ServerLobby::updatePlayerList(bool update_when_reset_server)
|
||||
|
||||
auto all_profiles = STKHost::get()->getAllPlayerProfiles();
|
||||
// N - 1 AI
|
||||
auto ai = m_ai_peer.lock();
|
||||
if (supportsAI() && ai)
|
||||
auto ai_instance = m_ai_peer.lock();
|
||||
if (supportsAI())
|
||||
{
|
||||
auto ai_profiles = ai->getPlayerProfiles();
|
||||
if (m_state.load() == WAITING_FOR_START_GAME ||
|
||||
update_when_reset_server)
|
||||
if (ai_instance)
|
||||
{
|
||||
if (all_profiles.size() > ai_profiles.size())
|
||||
ai_profiles.clear();
|
||||
else if (!all_profiles.empty())
|
||||
auto ai_profiles = ai_instance->getPlayerProfiles();
|
||||
if (m_state.load() == WAITING_FOR_START_GAME ||
|
||||
update_when_reset_server)
|
||||
{
|
||||
ai_profiles.resize(
|
||||
ai_profiles.size() - all_profiles.size() + 1);
|
||||
if (all_profiles.size() > ai_profiles.size())
|
||||
ai_profiles.clear();
|
||||
else if (!all_profiles.empty())
|
||||
{
|
||||
ai_profiles.resize(
|
||||
ai_profiles.size() - all_profiles.size() + 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use fixed number of AI calculated when started game
|
||||
ai_profiles.resize(m_ai_count);
|
||||
}
|
||||
all_profiles.insert(all_profiles.end(), ai_profiles.begin(),
|
||||
ai_profiles.end());
|
||||
}
|
||||
else
|
||||
else if (!m_ai_profiles.empty())
|
||||
{
|
||||
// Use fixed number of AI calculated when started game
|
||||
ai_profiles.resize(m_ai_count);
|
||||
all_profiles.insert(all_profiles.end(), m_ai_profiles.begin(),
|
||||
m_ai_profiles.end());
|
||||
}
|
||||
all_profiles.insert(all_profiles.end(), ai_profiles.begin(),
|
||||
ai_profiles.end());
|
||||
}
|
||||
m_lobby_players.store((int)all_profiles.size());
|
||||
|
||||
@ -3676,7 +3719,7 @@ void ServerLobby::updatePlayerList(bool update_when_reset_server)
|
||||
m_peers_ready.find(p) != m_peers_ready.end() &&
|
||||
m_peers_ready.at(p))
|
||||
boolean_combine |= (1 << 3);
|
||||
if (p && p->isAIPeer())
|
||||
if ((p && p->isAIPeer()) || isAIProfile(profile))
|
||||
boolean_combine |= (1 << 4);
|
||||
pl->addUInt8(boolean_combine);
|
||||
pl->addUInt8(profile->getHandicap());
|
||||
|
@ -127,8 +127,14 @@ private:
|
||||
* (disconnected). */
|
||||
std::weak_ptr<STKPeer> m_server_owner;
|
||||
|
||||
/** AI peer which holds the list of reserved AI for dedicated server. */
|
||||
std::weak_ptr<STKPeer> m_ai_peer;
|
||||
|
||||
/** AI profiles for all-in-one graphical client server, this will be a
|
||||
* fixed count thorough the live time of server, which its value is
|
||||
* configured in NetworkConfig. */
|
||||
std::set<std::shared_ptr<NetworkPlayerProfile> > m_ai_profiles;
|
||||
|
||||
std::atomic<uint32_t> m_server_owner_id;
|
||||
|
||||
/** Official karts and tracks available in server. */
|
||||
@ -379,6 +385,8 @@ public:
|
||||
void saveIPBanTable(const SocketAddress& addr);
|
||||
void listBanTable();
|
||||
void initServerStatsTable();
|
||||
bool isAIProfile(const std::shared_ptr<NetworkPlayerProfile>& npp) const
|
||||
{ return m_ai_profiles.find(npp) != m_ai_profiles.end(); }
|
||||
}; // class ServerLobby
|
||||
|
||||
#endif // SERVER_LOBBY_HPP
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "audio/sfx_manager.hpp"
|
||||
#include "config/player_manager.hpp"
|
||||
#include "config/user_config.hpp"
|
||||
#include "karts/controller/network_ai_controller.hpp"
|
||||
#include "network/network_config.hpp"
|
||||
#include "network/server.hpp"
|
||||
#include "network/server_config.hpp"
|
||||
@ -391,7 +392,10 @@ void CreateServerScreen::createServer()
|
||||
if (m_supports_ai)
|
||||
{
|
||||
if (esi > 0)
|
||||
{
|
||||
server_cfg << " --server-ai=" << esi;
|
||||
NetworkAIController::setAIFrequency(10);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -632,15 +632,16 @@ void NetworkingLobby::eventCallback(Widget* widget, const std::string& name,
|
||||
{
|
||||
return;
|
||||
}
|
||||
LobbyPlayer& lp =
|
||||
m_player_names.at(m_player_list->getSelectionInternalName());
|
||||
// For client server AI it doesn't make any sense to open the dialog
|
||||
// There is no way to kick or add handicap to them
|
||||
if (STKHost::get()->isClientServer() > 0 && lp.isAI())
|
||||
return;
|
||||
new NetworkPlayerDialog(host_online_local_ids[0],
|
||||
host_online_local_ids[1], host_online_local_ids[2],
|
||||
m_player_names.at(
|
||||
m_player_list->getSelectionInternalName()).m_user_name,
|
||||
m_player_names.at(
|
||||
m_player_list->getSelectionInternalName()).m_country_code,
|
||||
m_allow_change_team,
|
||||
m_player_names.at(
|
||||
m_player_list->getSelectionInternalName()).m_handicap);
|
||||
lp.m_user_name, lp.m_country_code, m_allow_change_team,
|
||||
lp.m_handicap);
|
||||
} // click on a user
|
||||
else if (name == m_send_button->m_properties[PROP_ID])
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user