PDA

View Full Version : Kicking bots



IzNoGoD
21st May 2014, 19:23
[18:08] php: kicking bots
[18:08] php: is zo easy

http://www.xfire.com/video/625d3f

Coming soon to a libcod installation near you

php
21st May 2014, 22:21
For people interested, use the stock function SV_DropClient then after that set the client's state to CS_FREE, that's all folks.

filthy_freak_
22nd May 2014, 00:39
Would love this.

Solves a few problems I have with the old method.

GJ.

kung foo man
22nd May 2014, 15:31
Ok, merged all stuff: https://github.com/kungfooman/libcod/commit/94ace0750cd7d516ffa7a94aaf2e49446ff4eac9

Download: http://killtube.org/downloads/libcod/2014_05_22/

Usage:


[20:07] IzNoGoD:

entnum = players[i] getentitynumber();
kick(entnum);
free_slot(entnum);


Credits to php for discovering this method and IzNoGod for implementing it in libcod. :)

Video by IzNoGod: http://www.xfire.com/videos/625d3f

Ni3ls
23rd May 2014, 07:59
Also possible without libcod?

Mitch
23rd May 2014, 09:09
Also possible without libcod?

No, because it uses libcod to set the slot to CS_FREE.

filthy_freak_
23rd May 2014, 14:49
Here's a challenge for you;

Changing bot names.

IzNoGoD
23rd May 2014, 16:23
Here's a challenge for you;

Changing bot names.

Please look up the word "challenge" in a dictionary:

A test of one's abilities or resources in a demanding but stimulating undertaking

710

filthy_freak_
23rd May 2014, 16:34
Please look up the word "challenge" in a dictionary:

Haha thats gold.

Too bad you can't change specific ones.

Mitch
23rd May 2014, 17:04
Haha thats gold.

Too bad you can't change specific ones.

Why wouldn't it be possible? I would assume that it should be possible.

filthy_freak_
23rd May 2014, 18:29
Why wouldn't it be possible? I would assume that it should be possible.

I'm only guessing here but I think he's manipulating the default bot name (Which can be done without libcod by editing cod2_mp with a hex editor, but the bot name is limited to 3 chars without libcod) which affects all bots globally.

If its possible to individually change their name (Without making your own scoreboard/obituary) then by all means prove me wrong =D

IzNoGoD
23rd May 2014, 20:09
Of course im manipulating the bot names individually, however, it seems like i missed something, as the bot is in fact renamed (in rcon status), but ingame it is still botxx

php
23rd May 2014, 21:09
http://cod1.eu/screenshots/bots_name.png


names = [];
names[names.size] = "Rob";
names[names.size] = "Richard";
names[names.size] = "Jim";
names[names.size] = "IzNoGoD";
names[names.size] = "Harry";
names[names.size] = "Wizard";
names[names.size] = "Pancakes";
for(i=0;i<15;i++) {
b = addtestclient();
b renamebot(names[randomInt(names.size-1)]);

filthy_freak_
24th May 2014, 06:25
Lmao.

Looks like I was wrong. Makes me want to strap down and learn how libcod works. Well done.

Any chance of including your rename method in a future libcod update?

filthy_freak_
24th May 2014, 08:29
Found a bug with kicking the bots.

It seems that if you create a testclient & spawn them (If they're not spawned it will not trigger the bug) it will crash the server after creating & spawning over 1.3k bots.

Heres the error it will give:
711

You can duplicate this crash with ease. On start gametype, add 64 testclients, spawn them, then cycle the map. Within 3-5 minutes you will go through 1.3k bots and it will crash the server.

IzNoGoD
24th May 2014, 11:29
Found a bug with kicking the bots.

It seems that if you create a testclient & spawn them (If they're not spawned it will not trigger the bug) it will crash the server after creating & spawning over 1.3k bots.

Heres the error it will give:
711

You can duplicate this crash with ease. On start gametype, add 64 testclients, spawn them, then cycle the map. Within 3-5 minutes you will go through 1.3k bots and it will crash the server.
ye well, dont put them in an array and you'll be fine.

Tally
24th May 2014, 11:34
It will do that for any spawned entity - there is obviously a limit to the number of such entities you can spawn.

Solution: every time you kick a bot, also remove it from all spawn arrays in _spawnlogic.gsc.

php
24th May 2014, 12:34
For changing bot names;




void PlayerCmd_renamebot(int a1) {
char* key = Script_GetString(0);
char userinfo[MAX_STRING_CHARS];
getuserinfo(a1, userinfo, sizeof(userinfo));

/*char* value = Info_ValueForKey(userinfo, key);
if(value == NULL)
Script_AddString("");
else
Script_AddString(value);*/
Info_SetValueForKey(userinfo, "name", key);
setuserinfo(a1, userinfo);

client_t* cl = getclient(a1);
if(cl) {
memcpy(&cl->name[0], key, 32);
cl->name[31] = '\0';
}

printf("name = %s\n", cl->name);
}


I didn't check if it only works with cl->name or userinfo so I set both and I really don't care to find out.
As for name changing instantly, just call *_UserinfoChanged (harder way for non-libcod people)
For convience I held on to the q3/wolf SDK name conventions so you can look it up yourself what it does and all.

Easier way is just to use the builtin script function



UpdateClientNames()
Module: Level
MP Only

Summary:
Update all of the client names: only works in 'manual_change' mode


Usage:



newname = "harry you're a wizard";
players=getentarray("player","classname");
for(i=0;i<players.size;i++){
if(players[i] isbot()) {
players[i] renamebot(newname);
}
updateclientnames(); //calling it for every bot name change in a loop is not recommended except when you're only changing one bot name
//since it's a loop let's call it at the end
//it will notify in a iprintln with "bot<number> changed name to <newname>"
//so find the UserinfoChanged or set the start of that string (hex edit) to \0
}




void PlayerCmd_isbot(int a1) {
client_t* cl = getclient(a1);
if(cl) {
if(cl->remoteAddress.type == NA_BOT)
Script_AddBool(true);
else
Script_AddBool(false);
} else {
Script_AddBool(false);
}
}


As for the CoDExtended functions if you'd like to convert them to libcod, just look up the Q3/WOLF SDK
a1 = entityNumber
getclient = function gets client_t pointer for number

filthy_freak_
24th May 2014, 17:34
Epic, I'll definitely use your method soon and post results.

Also, fixed my other problem by moving bots to spectator before kicking.

Cheers all for the help!

filthy_freak_
24th May 2014, 18:09
Before I attempt to implement the method into my libcod, I have a quick question;

Why is it


void PlayerCmd_renamebot(int a1) {


instead of


void PlayerCmd_renamebot(string newname) {


since you do


players[i] renamebot(newname);

Mitch
24th May 2014, 18:24
Before I attempt to implement the method into my libcod, I have a quick question;

Why is it


void PlayerCmd_renamebot(int a1) {


instead of


void PlayerCmd_renamebot(string newname) {


since you do


players[i] renamebot(newname);


a1 is like he said the entity number. The parameters you use are stored in the stack of cod script. They get retrieved by Script_GetString(0). (different function in libcod)

filthy_freak_
24th May 2014, 18:26
a1 is like he said the entity number. The parameters you use are stored in the stack of cod script. They get retrieved by Script_GetString(0). (different function in libcod)

Ahh that makes sense, thanks the explanation.

IzNoGoD
24th May 2014, 18:30
Because it is a method being called on a player, and the integer is the entitynumber.

The function itself gets the string you want, using getStackString() or something named quite similar.

filthy_freak_
24th May 2014, 19:19
Alright so keep in mind that libcod is new for me so I don't understand it much at all.

That being said... I have a really noob problem.

I'm getting this when compiling;


##### COMPILE cod2_1_0 GSC_PLAYER.CPP #####
gsc_player.cpp: In function "void PlayerCmd_renamebot(int)":
gsc_player.cpp:59:35: error: "Script_GetString" was not declared in this scope
gsc_player.cpp:60:19: error: "MAX_STRING_CHARS" was not declared in this scope
gsc_player.cpp:61:21: error: "userinfo" was not declared in this scope
gsc_player.cpp:61:47: error: "getuserinfo" was not declared in this scope
gsc_player.cpp:68:46: error: "Info_SetValueForKey" was not declared in this scope
gsc_player.cpp:69:29: error: "setuserinfo" was not declared in this scope
gsc_player.cpp:71:5: error: "client_t" was not declared in this scope
gsc_player.cpp:71:15: error: "cl" was not declared in this scope
gsc_player.cpp:71:32: error "getclient" was not declared in this scope


So i'm guessing those functions don't exist?

Edit: aha... looking through the q3 source code I see some of these methods... might be able to work this out
Edit2: Yeah.. nah. Do I really have to move over all these methods from the q3 source? Some of them require more methods (Example: "getuserinfo" requires "Q_strncpyz" which requires "strncpy" etc) which is making this a mess for me to understand/work out.

Is it possible for you to supply a precompiled version?

filthy_freak_
29th May 2014, 17:16
Lol i'm dumb I only just realized that your code was for cod1 CodExtended.

Could someone with the skills change the bot names for cod2 using libcod and share the code? Would be a very very very useful feature for me. =D

guiismiti
31st March 2017, 17:36
I'm getting some weird errors when kicking meatbots.

Basically, I created a monitor (code below) to add a bot if team size < 6, and remove a bot if team size > 6 && there is at least one bot in the team.

The problem is:
I join the server and a team, the bot is kicked;
The bot is still in the server, although the slot was freed (first image);
The bot still counts as being in the team I joined, so the server keeps trying to kick it constantly;
When I leave the server, this "ghost" bot rejoins the team (the server shows 11 players only, since its slot was freed);
When I reconnect, I use the slot of the kicked bot. The team score hud is duplicated (second image), and, as a spectator, I keep aiming at the other bots (which is what meatbot's check enemy function does, in an infinite loop);
At this moment, when I join the same team I joined earler, I get disconnected - it seems that I have self.isbot defined (the kicked bot had this it defined), so I count as a bot and the bot monitor tries to kick me to make room for myself, lol;
After I disconnect, the server keeps trying to kick whoever is in the slot I was using, so, in the console, it prints "Client 1 is not active" every time it goes through the monitor function.

1309

1308



botMonitor()
{
self endon("intermission");

currentteam = "allies";

for(;;)
{
// start the monitor a while after map loading
timepassed = (getTime() - level.starttime) / 1000;
delayonstart = 20;

if
(
(timepassed > delayonstart) &&
(getCvar("mod_allow_bots") == "1")
)
{
// get bot count and player count for the current team
botsonteam = 0;
playersonteam = 0;

players = getentarray("player", "classname");

for(i = 0; i < players.size; i++)
{
if(players[i].pers["team"] == currentteam)
{
if
(
(isDefined(players[i].isbot)) ||
(players[i] getIP() == "0")
)
{
botsonteam++;
}
else
{
playersonteam++;
iprintln(players[i].name);
}
}
}

// add a bot to the current team if it is not complete
botmaxnumber = getCvarInt("mod_bots_" + currentteam);

if((playersonteam + botsonteam) < botmaxnumber)
{
reAddBot(currentteam);
}
else
{
// remove a bot from the current team if it has too many
if
(
(botsonteam > 0) &&
((playersonteam + botsonteam) > botmaxnumber)
)
{
iprintln("trying to kick a bot from " + currentteam);

level kickBotFromTeam(currentteam);
}
}

if(currentteam == "allies")
{
currentteam = "axis";
}
else
{
currentteam = "allies";
}
}

wait(0.5);
}
}



kickBotFromTeam(team)
{
players = getentarray("player", "classname");

for(i = 0; i < players.size; i++)
{
if
(
(players[i].pers["team"] == team) &&
(
(isDefined(players[i].isbot)) ||
(players[i] getIP() == "0")
)
)
{
entnum = players[i] getentitynumber();
kick(entnum);
free_slot(entnum);

break;
}
}
}


Any ideas?

voron00
31st March 2017, 17:56
You have to wait a little bit before freeing slot or just use libcod from my repo, has an autofreeslot for bots so you can just normally kick it. Also your isBot definiton seems wrong, just use:

isBot()
{
return self getAddressType() == 0;
}

if (self isBot())
{
bla bla...
}

guiismiti
31st March 2017, 18:06
You have to wait a little bit before freeing slot or just use libcod from my repo, has an autofreeslot for bots so you can just normally kick it. Also your isBot definiton seems wrong, just use:

isBot()
{
return self getAddressType() == 0;
}

if (self isBot())
{
bla bla...
}


1 - I tried using getAddressType() but my version of libcod is a little old :) so, whenever I'm not using .isbot I'm using getIP() == 0.
.isbot works well because it is defined when the test client is added;
2 - Are you serious??? All I had to do was to add a wait before freeing the slot??? I wasted hours last night trying to figure this out, testing and testing and testing, before writing everything in details... lol

Thanks :D