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:
parent
1cad8919b4
commit
fba3837523
5 changed files with 76 additions and 16 deletions
|
|
@ -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 () {
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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) {
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue