add: rapid output console commands are now put on queue and sent with intervals. fixes #176, and overflows causes by yb cvars and yb g clean all commands.

This commit is contained in:
ds 2020-10-13 15:43:25 +03:00
commit fba3837523
5 changed files with 76 additions and 16 deletions

View file

@ -132,17 +132,16 @@ public:
return index_.first == index_.second; return index_.first == index_.second;
} }
template <typename U> void emplaceLast (U &&object) { template <typename ...Args> void emplaceLast (Args &&...args) {
auto rear = pickRearIndex (); auto rear = pickRearIndex ();
alloc.construct (&contents_[index_.second], cr::forward <U> (object)); alloc.construct (&contents_[index_.second], cr::forward <Args> (args)...);
index_.second = rear; index_.second = rear;
} }
template <typename U> void emplaceFront (U &&object) { template <typename ...Args> void emplaceFront (Args &&...args) {
index_.first = pickFrontIndex (); index_.first = pickFrontIndex ();
alloc.construct (&contents_[index_.first], cr::forward <Args> (args)...);
alloc.construct (&contents_[index_.first], cr::forward <U> (object));
} }
void discardFront () { void discardFront () {

View file

@ -22,6 +22,12 @@ CR_DECLARE_SCOPED_ENUM (BotCommandResult,
BadFormat // wrong params BadFormat // wrong params
) )
// print queue destination
CR_DECLARE_SCOPED_ENUM (PrintQueueDestination,
ServerConsole, // use server console
ClientConsole // use client console
);
// bot command manager // bot command manager
class BotControl final : public Singleton <BotControl> { class BotControl final : public Singleton <BotControl> {
public: public:
@ -36,7 +42,9 @@ public:
public: public:
BotCmd () = default; BotCmd () = default;
BotCmd (StringRef name, StringRef format, StringRef help, Handler handler) : name (name), format (format), help (help), handler (cr::move (handler)) { }
BotCmd (StringRef name, StringRef format, StringRef help, Handler handler) : name (name), format (format), help (help), handler (cr::move (handler))
{ }
}; };
// single bot menu // single bot menu
@ -46,13 +54,27 @@ public:
MenuHandler handler; MenuHandler handler;
public: public:
BotMenu (int ident, int slots, StringRef text, MenuHandler handler) : ident (ident), slots (slots), text (text), handler (cr::move (handler)) { } BotMenu (int ident, int slots, StringRef text, MenuHandler handler) : ident (ident), slots (slots), text (text), handler (cr::move (handler))
{ }
};
// queued text message to prevent overflow with rapid output
struct PrintQueue {
int32 destination;
String text;
public:
PrintQueue () = default;
PrintQueue (int32 destination, StringRef text) : destination (destination), text (text)
{ }
}; };
private: private:
StringArray m_args; StringArray m_args;
Array <BotCmd> m_cmds; Array <BotCmd> m_cmds;
Array <BotMenu> m_menus; Array <BotMenu> m_menus;
Deque <PrintQueue> m_printQueue;
IntArray m_campIterator; IntArray m_campIterator;
edict_t *m_ent; edict_t *m_ent;
@ -65,6 +87,8 @@ private:
int m_menuServerFillTeam; int m_menuServerFillTeam;
int m_interMenuData[4] = { 0, }; int m_interMenuData[4] = { 0, };
float m_printQueueFlushTimestamp {};
public: public:
BotControl (); BotControl ();
~BotControl () = default; ~BotControl () = default;
@ -142,6 +166,7 @@ public:
void kickBotByMenu (int page); void kickBotByMenu (int page);
void assignAdminRights (edict_t *ent, char *infobuffer); void assignAdminRights (edict_t *ent, char *infobuffer);
void maintainAdminRights (); void maintainAdminRights ();
void flushPrintQueue ();
public: public:
void setFromConsole (bool console) { void setFromConsole (bool console) {
@ -208,8 +233,14 @@ template <typename ...Args> inline void BotControl::msg (const char *fmt, Args &
auto result = strings.format (conf.translate (fmt), cr::forward <Args> (args)...); auto result = strings.format (conf.translate (fmt), cr::forward <Args> (args)...);
// if no receiver or many message have to appear, just print to server console // if no receiver or many message have to appear, just print to server console
if (game.isNullEntity (m_ent) || m_rapidOutput) { if (game.isNullEntity (m_ent)) {
game.print (result); // print the info
if (m_rapidOutput) {
m_printQueue.emplaceLast (PrintQueueDestination::ServerConsole, result);
}
else {
game.print (result); // print the info
}
// enable translation aftetwards // enable translation aftetwards
if (isDedicated) { if (isDedicated) {
@ -218,8 +249,13 @@ template <typename ...Args> inline void BotControl::msg (const char *fmt, Args &
return; return;
} }
if (m_isFromConsole || strlen (result) > 56) { if (m_isFromConsole || strlen (result) > 56 || m_rapidOutput) {
game.clientPrint (m_ent, result); if (m_rapidOutput) {
m_printQueue.emplaceLast (PrintQueueDestination::ClientConsole, result);
}
else {
game.clientPrint (m_ent, result);
}
} }
else { else {
game.centerPrint (m_ent, result); game.centerPrint (m_ent, result);

View file

@ -207,6 +207,9 @@ int BotControl::cmdCvars () {
cfg.open (strings.format ("%s/addons/%s/conf/%s.cfg", game.getRunningModName (), product.folder, product.folder), "wt"); cfg.open (strings.format ("%s/addons/%s/conf/%s.cfg", game.getRunningModName (), product.folder, product.folder), "wt");
cfg.puts ("// Configuration file for %s\n\n", product.name); cfg.puts ("// Configuration file for %s\n\n", product.name);
} }
else {
ctrl.setRapidOutput (true);
}
for (const auto &cvar : game.getCvars ()) { for (const auto &cvar : game.getCvars ()) {
if (cvar.info.empty ()) { if (cvar.info.empty ()) {
@ -258,6 +261,7 @@ int BotControl::cmdCvars () {
msg (" "); msg (" ");
} }
} }
ctrl.setRapidOutput (false);
if (isSave) { if (isSave) {
msg ("Bots cvars has been written to file."); msg ("Bots cvars has been written to file.");
@ -1854,6 +1858,22 @@ void BotControl::maintainAdminRights () {
} }
} }
void BotControl::flushPrintQueue () {
if (m_printQueueFlushTimestamp > game.time () || m_printQueue.empty ()) {
return;
}
auto printable = m_printQueue.popFront ();
// send to needed destination
if (printable.destination == PrintQueueDestination::ServerConsole) {
game.print (printable.text.chars ());
}
else if (!game.isNullEntity (m_ent)) {
game.clientPrint (m_ent, printable.text.chars ());
}
m_printQueueFlushTimestamp = game.time () + 0.05f;
}
BotControl::BotControl () { BotControl::BotControl () {
m_ent = nullptr; m_ent = nullptr;
m_djump = nullptr; m_djump = nullptr;
@ -1862,6 +1882,7 @@ BotControl::BotControl () {
m_isMenuFillCommand = false; m_isMenuFillCommand = false;
m_rapidOutput = false; m_rapidOutput = false;
m_menuServerFillTeam = 5; m_menuServerFillTeam = 5;
m_printQueueFlushTimestamp = 0.0f;
m_cmds.emplace ("add/addbot/add_ct/addbot_ct/add_t/addbot_t/addhs/addhs_t/addhs_ct", "add [difficulty[personality[team[model[name]]]]]", "Adding specific bot into the game.", &BotControl::cmdAddBot); m_cmds.emplace ("add/addbot/add_ct/addbot_ct/add_t/addbot_t/addhs/addhs_t/addhs_ct", "add [difficulty[personality[team[model[name]]]]]", "Adding specific bot into the game.", &BotControl::cmdAddBot);
m_cmds.emplace ("kick/kickone/kick_ct/kick_t/kickbot_ct/kickbot_t", "kick [team]", "Kicks off the random bot from the game.", &BotControl::cmdKickBot); m_cmds.emplace ("kick/kickone/kick_ct/kick_t/kickbot_ct/kickbot_t", "kick [team]", "Kicks off the random bot from the game.", &BotControl::cmdKickBot);

View file

@ -430,6 +430,7 @@ void Game::sendClientMessage (bool console, edict_t *ent, StringRef message) {
if (!util.isPlayer (ent) || util.isFakeClient (ent)) { if (!util.isPlayer (ent) || util.isFakeClient (ent)) {
return; return;
} }
const String &buffer = message;
// used to split messages // used to split messages
auto sendTextMsg = [&console, &ent] (StringRef text) { auto sendTextMsg = [&console, &ent] (StringRef text) {
@ -439,19 +440,19 @@ void Game::sendClientMessage (bool console, edict_t *ent, StringRef message) {
}; };
// do not excess limit // do not excess limit
constexpr size_t maxSendLength = 125; constexpr size_t maxSendLength = 187;
// split up the string into chunks if needed (maybe check if it's multibyte?) // split up the string into chunks if needed (maybe check if it's multibyte?)
if (message.length () > maxSendLength) { if (buffer.length () > maxSendLength) {
auto chunks = message.split (maxSendLength); auto chunks = buffer.split (maxSendLength);
// send in chunks // send in chunks
for (size_t i = 0; i < chunks.length (); ++i) { for (size_t i = 0; i < chunks.length (); ++i) {
sendTextMsg (chunks[i]); sendTextMsg (chunks[i]);
} }
return; return;
} }
sendTextMsg (message); sendTextMsg (buffer);
} }
void Game::sendServerMessage (StringRef message) { void Game::sendServerMessage (StringRef message) {

View file

@ -406,6 +406,9 @@ CR_EXPORT int GetEntityAPI (gamefuncs_t *table, int) {
// keep bot number up to date // keep bot number up to date
bots.maintainQuota (); bots.maintainQuota ();
// flush print queue to users
ctrl.flushPrintQueue ();
if (game.is (GameFlags::Metamod)) { if (game.is (GameFlags::Metamod)) {
RETURN_META (MRES_IGNORED); RETURN_META (MRES_IGNORED);