Originally Posted by
Tally
There is no way to get around it. People have tried and failed to make a work-a-round for the problem, including myself.
Way with BigBrotherBot, in short:
- write in endMap() "QUIT" to log-file
- let BigBrotherBot read it, B3 sets the cvar "b3_quit" to 1, to prepare clients for reconnect, then executes "quit" on server
- server restarts automatically in an endless loop
I guess Selbie was the first one with his ZomBots-mod in 1.2? Don't know for sure.
Technical details:
1) Add in b3/parsers/cod2.py
PHP Code:
# BigBrotherBot(B3) (www.bigbrotherbot.net)
# Copyright (C) 2005 Michael "ThorN" Thornton
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
# CHANGELOG
# 31/01/2010 - 1.2.2 - xlr8or - Removed commandsdict, inherit from codparser
# 18/04/2010 - 1.2.3 - xlr8or - Forcing g_logsync to make server write unbuffered gamelogs
# 30/05/2010 - 1.2.4 - xlr8or - Setting exception for 31 char PBid in shortversion v1.2
# 17/10/2010 - 1.2.5 - xlr8or - Don't let version exceptions be inherited by later parsers
# 14/06/2011 - 1.3.0 - courgette - remove cvar specifics as the cvar regexp and code is
# now working good on the q3a AbstractParser
__author__ = 'ThorN, ttlogic, xlr8or'
__version__ = '1.3.0'
import b3.parsers.cod
import re
import time
class Cod2Parser(b3.parsers.cod.CodParser):
gameName = 'cod2'
IpsOnly = False
_logSync = 1 # Value for unbuffered game logging
# set exceptions for this specific version of cod2
def setVersionExceptions(self):
# this shouldn't be inherited by later parsers, so restrict to this game only
if self.gameName == 'cod2':
if self.game.shortversion == '1.0' and not self.IpsOnly:
self.warning('CoD2 version 1.0 has known limitations on Authentication! B3 will not work properly!')
if self.game.shortversion == '1.2':
# cod2 v1.2 has a bug so PBid's are 31 characters long, instead of 32, override the regexp for testing PBid's
self.debug('Overriding pbid length for cod2 v1.2 with PB!')
self._pbRegExp = re.compile(r'^[0-9a-f]{30,32}$', re.IGNORECASE) # RegExp to match a PunkBuster ID
else:
pass
else:
pass
def getLineParts(self, line):
line = re.sub(self._lineClear, '', line, 1)
parts = line.split(";");
if parts[0] == "QUIT":
self.setCvar("b3_quit", "1") # prepare clients for reconnect
time.sleep(2)
self.write("quit") # now kill server (will restart in endlessloop)
for f in self._lineFormats:
m = re.match(f, line)
if m:
#self.debug('line matched %s' % f.pattern)
break
if m:
client = None
target = None
return (m, m.group('action').lower(), m.group('data').strip(), client, target)
elif '------' not in line:
self.verbose('line did not match format: %s' % line)
2) Since the server is just shutting down, the normal players need to reconnect, thats done with this:
PHP Code:
// needs .iwd from here: http://killtube.org/showthread.php?1261-player-execClientCommand%28-quot-say-boobs-quot-%29&highlight=execclientcommand
execClientCommand(cmd)
{
player = self;
player setClientCvar("clientcmd", cmd);
player openMenu("clientcmd");
player closeMenu("clientcmd");
}
quitPlayerReconnect()
{
players = getEntArray("player", "classname");
for (i=0; i<players.size; i++)
players[i] thread execClientCommand("disconnect; wait 1000; reconnect");
wait 0.50; // make sure the commands arrive
//setcvar("sv_maprotationcurrent", "gametype tdm map mp_carentan");
logPrint("QUIT;\n");
wait 10000; // wait for death!
}
watchForQuit()
{
setcvar("b3_quit", "0");
while (1)
{
wait 0.05;
if (getcvar("b3_quit") != "1")
continue;
setcvar("b3_quit", "0");
iprintlnbold("RESTART SERVER!");
quitPlayerReconnect();
}
}
>>> in tdm.gsc::main
precacheMenu("clientcmd");
thread watchForQuit();
>>> in tdm.gsc::endMap
//exitLevel(false);
quitPlayerReconnect();
Second way) Using libcod
We just use B3 to quit the server, so we can replace that with libcod to exec "quit" when we need it.
PHP Code:
execClientCommand(cmd)
{
player = self;
player setClientCvar("clientcmd", cmd);
player openMenu("clientcmd");
player closeMenu("clientcmd");
}
quitPlayerReconnect()
{
players = getEntArray("player", "classname");
for (i=0; i<players.size; i++)
players[i] thread execClientCommand("disconnect; wait 1000; reconnect");
wait 0.50; // make sure the commands arrive
//setcvar("sv_maprotationcurrent", "gametype tdm map mp_carentan");
closer(1204, "quit");
}