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;
}
template <typename U> void emplaceLast (U &&object) {
template <typename ...Args> void emplaceLast (Args &&...args) {
auto rear = pickRearIndex ();
alloc.construct (&contents_[index_.second], cr::forward <U> (object));
alloc.construct (&contents_[index_.second], cr::forward <Args> (args)...);
index_.second = rear;
}
template <typename U> void emplaceFront (U &&object) {
template <typename ...Args> void emplaceFront (Args &&...args) {
index_.first = pickFrontIndex ();
alloc.construct (&contents_[index_.first], cr::forward <U> (object));
alloc.construct (&contents_[index_.first], cr::forward <Args> (args)...);
}
void discardFront () {

View file

@ -22,6 +22,12 @@ CR_DECLARE_SCOPED_ENUM (BotCommandResult,
BadFormat // wrong params
)
// print queue destination
CR_DECLARE_SCOPED_ENUM (PrintQueueDestination,
ServerConsole, // use server console
ClientConsole // use client console
);
// bot command manager
class BotControl final : public Singleton <BotControl> {
public:
@ -36,7 +42,9 @@ public:
public:
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
@ -46,13 +54,27 @@ public:
MenuHandler handler;
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:
StringArray m_args;
Array <BotCmd> m_cmds;
Array <BotMenu> m_menus;
Deque <PrintQueue> m_printQueue;
IntArray m_campIterator;
edict_t *m_ent;
@ -65,6 +87,8 @@ private:
int m_menuServerFillTeam;
int m_interMenuData[4] = { 0, };
float m_printQueueFlushTimestamp {};
public:
BotControl ();
~BotControl () = default;
@ -142,6 +166,7 @@ public:
void kickBotByMenu (int page);
void assignAdminRights (edict_t *ent, char *infobuffer);
void maintainAdminRights ();
void flushPrintQueue ();
public:
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)...);
// if no receiver or many message have to appear, just print to server console
if (game.isNullEntity (m_ent) || m_rapidOutput) {
game.print (result); // print the info
if (game.isNullEntity (m_ent)) {
if (m_rapidOutput) {
m_printQueue.emplaceLast (PrintQueueDestination::ServerConsole, result);
}
else {
game.print (result); // print the info
}
// enable translation aftetwards
if (isDedicated) {
@ -218,8 +249,13 @@ template <typename ...Args> inline void BotControl::msg (const char *fmt, Args &
return;
}
if (m_isFromConsole || strlen (result) > 56) {
game.clientPrint (m_ent, result);
if (m_isFromConsole || strlen (result) > 56 || m_rapidOutput) {
if (m_rapidOutput) {
m_printQueue.emplaceLast (PrintQueueDestination::ClientConsole, result);
}
else {
game.clientPrint (m_ent, result);
}
}
else {
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.puts ("// Configuration file for %s\n\n", product.name);
}
else {
ctrl.setRapidOutput (true);
}
for (const auto &cvar : game.getCvars ()) {
if (cvar.info.empty ()) {
@ -258,6 +261,7 @@ int BotControl::cmdCvars () {
msg (" ");
}
}
ctrl.setRapidOutput (false);
if (isSave) {
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 () {
m_ent = nullptr;
m_djump = nullptr;
@ -1862,6 +1882,7 @@ BotControl::BotControl () {
m_isMenuFillCommand = false;
m_rapidOutput = false;
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 ("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)) {
return;
}
const String &buffer = message;
// used to split messages
auto sendTextMsg = [&console, &ent] (StringRef text) {
@ -439,11 +440,11 @@ void Game::sendClientMessage (bool console, edict_t *ent, StringRef message) {
};
// 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?)
if (message.length () > maxSendLength) {
auto chunks = message.split (maxSendLength);
if (buffer.length () > maxSendLength) {
auto chunks = buffer.split (maxSendLength);
// send in chunks
for (size_t i = 0; i < chunks.length (); ++i) {
@ -451,7 +452,7 @@ void Game::sendClientMessage (bool console, edict_t *ent, StringRef message) {
}
return;
}
sendTextMsg (message);
sendTextMsg (buffer);
}
void Game::sendServerMessage (StringRef message) {

View file

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