Moved dummyrunner under bin/.
This commit is contained in:
parent
f075d4aec1
commit
8e020bfb62
10 changed files with 415 additions and 377 deletions
31
bin/evennia
31
bin/evennia
|
|
@ -15,7 +15,7 @@ import signal
|
||||||
import shutil
|
import shutil
|
||||||
import importlib
|
import importlib
|
||||||
from argparse import ArgumentParser
|
from argparse import ArgumentParser
|
||||||
from subprocess import Popen, check_output
|
from subprocess import Popen, check_output, call
|
||||||
import django
|
import django
|
||||||
|
|
||||||
# Signal processing
|
# Signal processing
|
||||||
|
|
@ -27,6 +27,8 @@ EVENNIA_BIN = os.path.join(EVENNIA_ROOT, "bin")
|
||||||
EVENNIA_LIB = os.path.join(EVENNIA_ROOT, "evennia")
|
EVENNIA_LIB = os.path.join(EVENNIA_ROOT, "evennia")
|
||||||
EVENNIA_RUNNER = os.path.join(EVENNIA_BIN, "evennia_runner.py")
|
EVENNIA_RUNNER = os.path.join(EVENNIA_BIN, "evennia_runner.py")
|
||||||
EVENNIA_TEMPLATE = os.path.join(EVENNIA_ROOT, "game_template")
|
EVENNIA_TEMPLATE = os.path.join(EVENNIA_ROOT, "game_template")
|
||||||
|
EVENNIA_BINTESTING = os.path.join(EVENNIA_BIN, "testing")
|
||||||
|
EVENNIA_DUMMYRUNNER = os.path.join(EVENNIA_BINTESTING, "dummyrunner.py")
|
||||||
|
|
||||||
TWISTED_BINARY = "twistd"
|
TWISTED_BINARY = "twistd"
|
||||||
|
|
||||||
|
|
@ -675,6 +677,22 @@ def init_game_directory(path):
|
||||||
|
|
||||||
print INFO_WINDOWS_BATFILE.format(twistd_path=twistd_path)
|
print INFO_WINDOWS_BATFILE.format(twistd_path=twistd_path)
|
||||||
|
|
||||||
|
def run_dummyrunner(number_of_dummies):
|
||||||
|
"""
|
||||||
|
Start an instance of the dummyrunner
|
||||||
|
|
||||||
|
The dummy players' behavior can be customized by adding a
|
||||||
|
dummyrunner_settings.py config file in the game's conf directory.
|
||||||
|
"""
|
||||||
|
number_of_dummies = str(int(number_of_dummies)) if number_of_dummies else 1
|
||||||
|
cmdstr = [sys.executable, EVENNIA_DUMMYRUNNER, "-N", number_of_dummies]
|
||||||
|
config_file = os.path.join(SETTINGS_PATH, "dummyrunner_settings.py")
|
||||||
|
if os.path.exists(config_file):
|
||||||
|
cmdstr.extend(["--config", config_file])
|
||||||
|
try:
|
||||||
|
call(cmdstr, env=getenv())
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
pass
|
||||||
|
|
||||||
def run_menu():
|
def run_menu():
|
||||||
"""
|
"""
|
||||||
|
|
@ -834,8 +852,10 @@ def main():
|
||||||
help="Start given processes in interactive mode.")
|
help="Start given processes in interactive mode.")
|
||||||
parser.add_argument('--init', action='store', dest="init", metavar="name",
|
parser.add_argument('--init', action='store', dest="init", metavar="name",
|
||||||
help="Creates a new game directory 'name' at the current location.")
|
help="Creates a new game directory 'name' at the current location.")
|
||||||
parser.add_argument('-p', '--prof', action='store_true', dest='profiler', default=False,
|
parser.add_argument('--profile', action='store_true', dest='profiler', default=False,
|
||||||
help="Start given server component under the Python profiler.")
|
help="Start given server component under the Python profiler.")
|
||||||
|
parser.add_argument('--dummyrunner', nargs=1, action='store', dest='dummyrunner', metavar="N",
|
||||||
|
help="Tests a running server by connecting N dummy players to it.")
|
||||||
parser.add_argument("mode", metavar="option", nargs='?', default="help",
|
parser.add_argument("mode", metavar="option", nargs='?', default="help",
|
||||||
help="Operational mode or management option. Commonly start, stop, reload, migrate, or menu (default).")
|
help="Operational mode or management option. Commonly start, stop, reload, migrate, or menu (default).")
|
||||||
parser.add_argument("service", metavar="component", nargs='?', choices=["all", "server", "portal"], default="all",
|
parser.add_argument("service", metavar="component", nargs='?', choices=["all", "server", "portal"], default="all",
|
||||||
|
|
@ -858,7 +878,7 @@ def main():
|
||||||
if args.show_version:
|
if args.show_version:
|
||||||
print show_version_info(mode=="help")
|
print show_version_info(mode=="help")
|
||||||
sys.exit()
|
sys.exit()
|
||||||
if mode == "help":
|
if mode == "help" and not args.dummyrunner:
|
||||||
print ABOUT_INFO
|
print ABOUT_INFO
|
||||||
sys.exit()
|
sys.exit()
|
||||||
|
|
||||||
|
|
@ -866,7 +886,10 @@ def main():
|
||||||
# and initializes django for the game directory
|
# and initializes django for the game directory
|
||||||
init_game_directory(CURRENT_DIR)
|
init_game_directory(CURRENT_DIR)
|
||||||
|
|
||||||
if mode == 'menu':
|
if args.dummyrunner:
|
||||||
|
# launch the dummy runner
|
||||||
|
run_dummyrunner(args.dummyrunner[0])
|
||||||
|
elif mode == 'menu':
|
||||||
# launch menu for operation
|
# launch menu for operation
|
||||||
run_menu()
|
run_menu()
|
||||||
elif mode in ('start', 'reload', 'stop'):
|
elif mode in ('start', 'reload', 'stop'):
|
||||||
|
|
|
||||||
|
|
@ -31,36 +31,56 @@ for instructions on how to define this module.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import os, sys, time, random
|
import time, random
|
||||||
from optparse import OptionParser
|
from argparse import ArgumentParser
|
||||||
from twisted.conch import telnet
|
from twisted.conch import telnet
|
||||||
from twisted.internet import reactor, protocol
|
from twisted.internet import reactor, protocol
|
||||||
# from twisted.application import internet, service
|
|
||||||
# from twisted.web import client
|
|
||||||
from twisted.internet.task import LoopingCall
|
from twisted.internet.task import LoopingCall
|
||||||
|
|
||||||
# Tack on the root evennia directory to the python path and initialize django settings
|
|
||||||
|
|
||||||
#TODO
|
|
||||||
#sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))))
|
|
||||||
#os.environ["DJANGO_SETTINGS_MODULE"] = "game.settings"
|
|
||||||
|
|
||||||
#from game import settings
|
|
||||||
#try:
|
|
||||||
# from django.conf import settings as settings2
|
|
||||||
# settings2.configure()
|
|
||||||
#except RuntimeError:
|
|
||||||
# pass
|
|
||||||
#finally:
|
|
||||||
# del settings2
|
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from evennia.utils import utils
|
from evennia.utils import mod_import
|
||||||
|
|
||||||
|
# Load the dummyrunner settings module
|
||||||
|
|
||||||
|
DUMMYRUNNER_SETTINGS = mod_import(settings.DUMMYRUNNER_SETTINGS_MODULE)
|
||||||
|
DATESTRING = "%Y%m%d%H%M%S"
|
||||||
|
|
||||||
|
# Settings
|
||||||
|
|
||||||
|
# number of clients to launch if no input is given on command line
|
||||||
|
NCLIENTS = 1
|
||||||
|
# time between each 'tick', in seconds, if not set on command
|
||||||
|
# line. All launched clients will be called upon to possibly do an
|
||||||
|
# action with this frequency.
|
||||||
|
TIMESTEP = DUMMYRUNNER_SETTINGS.TIMESTEP
|
||||||
|
# chance of a client performing an action, per timestep. This helps to
|
||||||
|
# spread out usage randomly, like it would be in reality.
|
||||||
|
CHANCE_OF_ACTION = DUMMYRUNNER_SETTINGS.CHANCE_OF_ACTION
|
||||||
|
# spread out the login action separately, having many players create accounts
|
||||||
|
# and connect simultaneously is generally unlikely.
|
||||||
|
CHANCE_OF_LOGIN = DUMMYRUNNER_SETTINGS.CHANCE_OF_LOGIN
|
||||||
|
# Port to use, if not specified on command line
|
||||||
|
TELNET_PORT = DUMMYRUNNER_SETTINGS.TELNET_PORT or settings.TELNET_PORTS[0]
|
||||||
|
#
|
||||||
|
NLOGGED_IN = 0
|
||||||
|
|
||||||
|
# Messages
|
||||||
|
|
||||||
|
INFO_STARTING = \
|
||||||
|
"""
|
||||||
|
Dummyrunner starting, {N} dummy player(s).
|
||||||
|
|
||||||
|
Use Ctrl-C to stop/disconnect clients.
|
||||||
|
"""
|
||||||
|
|
||||||
|
ERROR_FEW_ACTIONS = \
|
||||||
|
"""
|
||||||
|
Dummyrunner error: The ACTIONS tuple is too short: it must contain at
|
||||||
|
least login- and logout functions.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
HELPTEXT = """
|
HELPTEXT = """
|
||||||
|
|
||||||
Usage: dummyrunner.py [-h][-v][-V] [nclients]
|
|
||||||
|
|
||||||
DO NOT RUN THIS ON A PRODUCTION SERVER! USE A CLEAN/TESTING DATABASE!
|
DO NOT RUN THIS ON A PRODUCTION SERVER! USE A CLEAN/TESTING DATABASE!
|
||||||
|
|
||||||
This stand-alone program launches dummy telnet clients against a
|
This stand-alone program launches dummy telnet clients against a
|
||||||
|
|
@ -81,60 +101,44 @@ Setup:
|
||||||
|
|
||||||
PERMISSION_PLAYER_DEFAULT="Builders"
|
PERMISSION_PLAYER_DEFAULT="Builders"
|
||||||
|
|
||||||
3a) Start Evennia like normal.
|
You can also customize the dummyrunner by modifying
|
||||||
3b) If you want profiling, start Evennia like this instead:
|
a setting file specified by DUMMYRUNNER_SETTINGS_MODULE
|
||||||
|
|
||||||
python runner.py -S start
|
3) Start Evennia like normal, optionally with profiling (--profile)
|
||||||
|
4) run this dummy runner via the evennia launcher:
|
||||||
|
|
||||||
this will start Evennia under cProfiler with output server.prof.
|
evennia --dummyrunner <nr_of_clients>
|
||||||
4) run this dummy runner:
|
|
||||||
|
|
||||||
python dummyclients.py <nr_of_clients> [timestep] [port]
|
|
||||||
|
|
||||||
Default is to connect one client to port 4000, using a 5 second
|
|
||||||
timestep. Increase the number of clients and shorten the
|
|
||||||
timestep (minimum is 1s) to further stress the game.
|
|
||||||
|
|
||||||
You can stop the dummy runner with Ctrl-C.
|
|
||||||
|
|
||||||
5) Log on and determine if game remains responsive despite the
|
5) Log on and determine if game remains responsive despite the
|
||||||
heavier load. Note that if you do profiling, there is an
|
heavier load. Note that if you do profiling, there is an
|
||||||
additional overhead from the profiler too!
|
additional overhead from the profiler too!
|
||||||
6) If you use profiling, let the game run long enough to gather
|
6) If you use profiling, let the game run long enough to gather
|
||||||
data, then stop the server. You can inspect the server.prof file
|
data, then stop the server, ideally from inside it with
|
||||||
from a python prompt (see Python's manual on cProfiler).
|
@shutdown. You can inspect the server.prof file from a python
|
||||||
|
prompt (see Python's manual on cProfiler).
|
||||||
|
|
||||||
"""
|
"""
|
||||||
# number of clients to launch if no input is given on command line
|
|
||||||
DEFAULT_NCLIENTS = 1
|
|
||||||
# time between each 'tick', in seconds, if not set on command
|
|
||||||
# line. All launched clients will be called upon to possibly do an
|
|
||||||
# action with this frequency.
|
|
||||||
DEFAULT_TIMESTEP = 2
|
|
||||||
# chance of a client performing an action, per timestep. This helps to
|
|
||||||
# spread out usage randomly, like it would be in reality.
|
|
||||||
CHANCE_OF_ACTION = 0.05
|
|
||||||
# spread out the login action separately, having many players create accounts
|
|
||||||
# and connect simultaneously is generally unlikely.
|
|
||||||
CHANCE_OF_LOGIN = 0.5
|
|
||||||
# Port to use, if not specified on command line
|
|
||||||
DEFAULT_PORT = settings.TELNET_PORTS[0]
|
|
||||||
#
|
|
||||||
NLOGGED_IN = 0
|
|
||||||
NCLIENTS = 0
|
|
||||||
|
|
||||||
#------------------------------------------------------------
|
#------------------------------------------------------------
|
||||||
# Helper functions
|
# Helper functions
|
||||||
#------------------------------------------------------------
|
#------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
ICOUNT = 0
|
||||||
def idcounter():
|
def idcounter():
|
||||||
"generates subsequent id numbers"
|
"makes unique ids"
|
||||||
idcount = 0
|
global ICOUNT
|
||||||
while True:
|
ICOUNT += 1
|
||||||
idcount += 1
|
return str(ICOUNT)
|
||||||
yield idcount
|
|
||||||
OID = idcounter()
|
|
||||||
CID = idcounter()
|
GCOUNT = 0
|
||||||
|
def gidcounter():
|
||||||
|
"makes globally unique ids"
|
||||||
|
global GCOUNT
|
||||||
|
GCOUNT += 1
|
||||||
|
return "%s-%s" % (time.strftime(DATESTRING), ICOUNT)
|
||||||
|
|
||||||
|
|
||||||
def makeiter(obj):
|
def makeiter(obj):
|
||||||
"makes everything iterable"
|
"makes everything iterable"
|
||||||
|
|
@ -156,35 +160,38 @@ class DummyClient(telnet.StatefulTelnetProtocol):
|
||||||
def connectionMade(self):
|
def connectionMade(self):
|
||||||
|
|
||||||
# public properties
|
# public properties
|
||||||
self.cid = CID.next()
|
self.cid = idcounter()
|
||||||
|
self.key = "Dummy-%s" % self.cid
|
||||||
|
self.gid = "%s-%s" % (time.strftime(DATESTRING), self.cid)
|
||||||
self.istep = 0
|
self.istep = 0
|
||||||
|
self.loggedin = False
|
||||||
self.exits = [] # exit names created
|
self.exits = [] # exit names created
|
||||||
self.objs = [] # obj names created
|
self.objs = [] # obj names created
|
||||||
|
|
||||||
self._report = ""
|
self._report = ""
|
||||||
self._cmdlist = [] # already stepping in a cmd definition
|
self._cmdlist = [] # already stepping in a cmd definition
|
||||||
self._ncmds = 0
|
nactions = len(self.factory.actions) # this has already been normalized
|
||||||
self._actions = self.factory.actions
|
if nactions < 2:
|
||||||
self._echo_brief = self.factory.verbose == 1
|
raise RuntimeError(ERROR_FEW_ACTIONS)
|
||||||
self._echo_all = self.factory.verbose == 2
|
self._login = self.factory.actions[0]
|
||||||
#print " ** client %i connected." % self.cid
|
self._logout = self.factory.actions[1]
|
||||||
|
self._actions = self.factory.actions[2:]
|
||||||
|
|
||||||
reactor.addSystemEventTrigger('before', 'shutdown', self.logout)
|
reactor.addSystemEventTrigger('before', 'shutdown', self.logout)
|
||||||
|
|
||||||
# start client tick
|
# start client tick
|
||||||
d = LoopingCall(self.step)
|
d = LoopingCall(self.step)
|
||||||
# dissipate exact step by up to +/- 0.5 second
|
# dissipate exact step by up to +/- 0.5 second
|
||||||
timestep = self.factory.timestep + (-0.5 + (random.random()*1.0))
|
timestep = TIMESTEP + (-0.5 + (random.random()*1.0))
|
||||||
d.start(timestep, now=True).addErrback(self.error)
|
d.start(timestep, now=True).addErrback(self.error)
|
||||||
|
|
||||||
|
|
||||||
def dataReceived(self, data):
|
def dataReceived(self, data):
|
||||||
"Echo incoming data to stdout"
|
"Echo incoming data to stdout"
|
||||||
if self._echo_all:
|
pass
|
||||||
print data
|
|
||||||
|
|
||||||
def connectionLost(self, reason):
|
def connectionLost(self, reason):
|
||||||
"loosing the connection"
|
"loosing the connection"
|
||||||
#print " ** client %i lost connection." % self.cid
|
|
||||||
|
|
||||||
def error(self, err):
|
def error(self, err):
|
||||||
"error callback"
|
"error callback"
|
||||||
|
|
@ -192,12 +199,12 @@ class DummyClient(telnet.StatefulTelnetProtocol):
|
||||||
|
|
||||||
def counter(self):
|
def counter(self):
|
||||||
"produces a unique id, also between clients"
|
"produces a unique id, also between clients"
|
||||||
return OID.next()
|
return gidcounter()
|
||||||
|
|
||||||
def logout(self):
|
def logout(self):
|
||||||
"Causes the client to log out of the server. Triggered by ctrl-c signal."
|
"Causes the client to log out of the server. Triggered by ctrl-c signal."
|
||||||
cmd, report = self._actions[1](self)
|
cmd = self._logout(self)
|
||||||
print "client %i %s (%s actions)" % (self.cid, report, self.istep)
|
print "client %s(%s) logout (%s actions)" % (self.key, self.cid, self.istep)
|
||||||
self.sendLine(cmd)
|
self.sendLine(cmd)
|
||||||
|
|
||||||
def step(self):
|
def step(self):
|
||||||
|
|
@ -206,52 +213,49 @@ class DummyClient(telnet.StatefulTelnetProtocol):
|
||||||
and causes the client to issue commands to the server.
|
and causes the client to issue commands to the server.
|
||||||
This holds all "intelligence" of the dummy client.
|
This holds all "intelligence" of the dummy client.
|
||||||
"""
|
"""
|
||||||
if self.istep == 0 and random.random() > CHANCE_OF_LOGIN:
|
|
||||||
return
|
|
||||||
elif random.random() > CHANCE_OF_ACTION:
|
|
||||||
return
|
|
||||||
|
|
||||||
global NLOGGED_IN
|
global NLOGGED_IN
|
||||||
|
|
||||||
|
rand = random.random()
|
||||||
|
|
||||||
if not self._cmdlist:
|
if not self._cmdlist:
|
||||||
# no cmdlist in store, get a new one
|
# no commands ready. Load some.
|
||||||
if self.istep == 0:
|
|
||||||
NLOGGED_IN += 1
|
if not self.loggedin:
|
||||||
cfunc = self._actions[0]
|
if rand < CHANCE_OF_LOGIN:
|
||||||
else: # random selection using cumulative probabilities
|
# get the login commands
|
||||||
rand = random.random()
|
self._cmdlist = list(makeiter(self._login(self)))
|
||||||
cfunc = [func for cprob, func in self._actions[2] if cprob >= rand][0]
|
NLOGGED_IN += 1 # this is for book-keeping
|
||||||
# assign to internal cmdlist
|
print "connecting client %s (%i/%i)..." % (self.key, NLOGGED_IN, NCLIENTS)
|
||||||
cmd, self._report = cfunc(self)
|
self.loggedin = True
|
||||||
self._cmdlist = list(makeiter(cmd))
|
else:
|
||||||
self._ncmds = len(self._cmdlist)
|
# we always pick a cumulatively random function
|
||||||
# output
|
crand = random.random()
|
||||||
if self.istep == 0 and not (self._echo_brief or self._echo_all):
|
cfunc = [func for cprob, func in self._actions if cprob >= crand][0]
|
||||||
# only print login
|
self._cmdlist = list(makeiter(cfunc(self)))
|
||||||
print "client %i %s (%i/%i)" % (self.cid, self._report, NLOGGED_IN, NCLIENTS)
|
|
||||||
elif self.istep == 0 or self._echo_brief or self._echo_all:
|
# at this point we always have a list of commands
|
||||||
print "client %i %s (%i/%i)" % (self.cid, self._report, self._ncmds-(len(self._cmdlist)-1), self._ncmds)
|
if rand < CHANCE_OF_ACTION:
|
||||||
# launch the action by popping the first element from cmdlist (don't hide tracebacks)
|
# send to the game
|
||||||
self.sendLine(str(self._cmdlist.pop(0)))
|
self.sendLine(str(self._cmdlist.pop(0)))
|
||||||
self.istep += 1 # only steps up if an action is taken
|
self.istep += 1
|
||||||
|
|
||||||
|
|
||||||
class DummyFactory(protocol.ClientFactory):
|
class DummyFactory(protocol.ClientFactory):
|
||||||
protocol = DummyClient
|
protocol = DummyClient
|
||||||
def __init__(self, actions, timestep, verbose):
|
def __init__(self, actions):
|
||||||
"Setup the factory base (shared by all clients)"
|
"Setup the factory base (shared by all clients)"
|
||||||
self.actions = actions
|
self.actions = actions
|
||||||
self.timestep = timestep
|
|
||||||
self.verbose = verbose
|
|
||||||
|
|
||||||
#------------------------------------------------------------
|
#------------------------------------------------------------
|
||||||
# Access method:
|
# Access method:
|
||||||
# Starts clients and connects them to a running server.
|
# Starts clients and connects them to a running server.
|
||||||
#------------------------------------------------------------
|
#------------------------------------------------------------
|
||||||
|
|
||||||
def start_all_dummy_clients(actions, nclients=1, timestep=5, telnet_port=4000, verbose=0):
|
def start_all_dummy_clients(nclients):
|
||||||
|
|
||||||
# validating and preparing the action tuple
|
|
||||||
global NCLIENTS
|
global NCLIENTS
|
||||||
NCLIENTS = nclients
|
NCLIENTS = int(nclients)
|
||||||
|
actions = DUMMYRUNNER_SETTINGS.ACTIONS
|
||||||
|
|
||||||
# make sure the probabilities add up to 1
|
# make sure the probabilities add up to 1
|
||||||
pratio = 1.0 / sum(tup[0] for tup in actions[2:])
|
pratio = 1.0 / sum(tup[0] for tup in actions[2:])
|
||||||
|
|
@ -262,9 +266,9 @@ def start_all_dummy_clients(actions, nclients=1, timestep=5, telnet_port=4000, v
|
||||||
actions = (flogin, flogout, zip(cprobs, cfuncs))
|
actions = (flogin, flogout, zip(cprobs, cfuncs))
|
||||||
|
|
||||||
# setting up all clients (they are automatically started)
|
# setting up all clients (they are automatically started)
|
||||||
factory = DummyFactory(actions, timestep, verbose)
|
factory = DummyFactory(actions)
|
||||||
for i in range(nclients):
|
for i in range(NCLIENTS):
|
||||||
reactor.connectTCP("localhost", telnet_port, factory)
|
reactor.connectTCP("localhost", TELNET_PORT, factory)
|
||||||
# start reactor
|
# start reactor
|
||||||
reactor.run()
|
reactor.run()
|
||||||
|
|
||||||
|
|
@ -275,39 +279,14 @@ def start_all_dummy_clients(actions, nclients=1, timestep=5, telnet_port=4000, v
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|
||||||
# parsing command line with default vals
|
# parsing command line with default vals
|
||||||
parser = OptionParser(usage="%prog [options] <nclients> [timestep, [port]]",
|
parser = ArgumentParser(description=HELPTEXT)
|
||||||
description="This program requires some preparations to run properly. Start it without any arguments or options for full help.")
|
parser.add_argument("-N", nargs=1, default=1, dest="nclients",
|
||||||
parser.add_option('-v', '--verbose', action='store_const', const=1, dest='verbose',
|
help="Number of clients to start")
|
||||||
default=0,help="echo brief description of what clients do every timestep.")
|
|
||||||
parser.add_option('-V', '--very-verbose', action='store_const',const=2, dest='verbose',
|
|
||||||
default=0,help="echo all client returns to stdout (hint: use only with nclients=1!)")
|
|
||||||
|
|
||||||
options, args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
nargs = len(args)
|
print INFO_STARTING.format(N=args.nclients[0])
|
||||||
nclients = DEFAULT_NCLIENTS
|
|
||||||
timestep = DEFAULT_TIMESTEP
|
|
||||||
port = DEFAULT_PORT
|
|
||||||
try:
|
|
||||||
if not args : raise Exception
|
|
||||||
if nargs > 0: nclients = max(1, int(args[0]))
|
|
||||||
if nargs > 1: timestep = max(1, int(args[1]))
|
|
||||||
if nargs > 2: port = int(args[2])
|
|
||||||
except Exception:
|
|
||||||
print HELPTEXT
|
|
||||||
sys.exit()
|
|
||||||
|
|
||||||
# import the ACTION tuple from a given module
|
|
||||||
try:
|
|
||||||
action_modpath = settings.DUMMYRUNNER_ACTIONS_MODULE
|
|
||||||
except AttributeError:
|
|
||||||
# use default
|
|
||||||
action_modpath = "evennia.utils.dummyrunner.dummyrunner_actions"
|
|
||||||
actions = utils.variable_from_module(action_modpath, "ACTIONS")
|
|
||||||
|
|
||||||
print "Connecting %i dummy client(s) to port %i using a %i second timestep ... " % (nclients, port, timestep)
|
|
||||||
t0 = time.time()
|
t0 = time.time()
|
||||||
start_all_dummy_clients(actions, nclients, timestep, port,
|
start_all_dummy_clients(nclients=args.nclients[0])
|
||||||
verbose=options.verbose)
|
|
||||||
ttot = time.time() - t0
|
ttot = time.time() - t0
|
||||||
print "... dummy client runner finished after %i seconds." % ttot
|
print "... dummy client runner stopped after %i seconds." % ttot
|
||||||
264
bin/testing/dummyrunner_settings.py
Normal file
264
bin/testing/dummyrunner_settings.py
Normal file
|
|
@ -0,0 +1,264 @@
|
||||||
|
"""
|
||||||
|
Settings and actions for the dummyrunner
|
||||||
|
|
||||||
|
This module defines dummyrunner settings and sets up
|
||||||
|
the actions available to dummy players.
|
||||||
|
|
||||||
|
The settings are global variables:
|
||||||
|
|
||||||
|
TIMESTEP - time in seconds between each 'tick'
|
||||||
|
CHANCE_OF_ACTION - chance 0-1 of action happening
|
||||||
|
CHANCE_OF_LOGIN - chance 0-1 of login happening
|
||||||
|
TELNET_PORT - port to use, defaults to settings.TELNET_PORT
|
||||||
|
ACTIONS - see below
|
||||||
|
|
||||||
|
ACTIONS is a tuple
|
||||||
|
|
||||||
|
(login_func, logout_func, (0.3, func1), (0.1, func2) ... )
|
||||||
|
|
||||||
|
where the first entry is the function to call on first connect, with a
|
||||||
|
chance of occurring given by CHANCE_OF_LOGIN. This function is usually
|
||||||
|
responsible for logging in the player. The second entry is always
|
||||||
|
called when the dummyrunner disconnects from the server and should
|
||||||
|
thus issue a logout command. The other entries are tuples (chance,
|
||||||
|
func). They are picked randomly, their commonality based on the
|
||||||
|
cumulative chance given (the chance is normalized between all options
|
||||||
|
so if will still work also if the given chances don't add up to 1).
|
||||||
|
Since each function can return a list of game-command strings, each
|
||||||
|
function may result in multiple operations.
|
||||||
|
|
||||||
|
An action-function is called with a "client" argument which is a
|
||||||
|
reference to the dummy client currently performing the action. It
|
||||||
|
returns a string or a list of command strings to execute. Use the
|
||||||
|
client object for optionally saving data between actions.
|
||||||
|
|
||||||
|
The client object has the following relevant properties and methods:
|
||||||
|
key - an optional client key. This is only used for dummyrunner output.
|
||||||
|
Default is "Dummy-<cid>"
|
||||||
|
cid - client id
|
||||||
|
gid - globally unique id, hashed with time stamp
|
||||||
|
istep - the current step
|
||||||
|
exits - an empty list. Can be used to store exit names
|
||||||
|
objs - an empty list. Can be used to store object names
|
||||||
|
counter() - returns a unique increasing id, hashed with time stamp
|
||||||
|
to make it unique also between dummyrunner instances.
|
||||||
|
|
||||||
|
The return should either be a single command string or a tuple of
|
||||||
|
command strings. This list of commands will always be executed every
|
||||||
|
TIMESTEP with a chance given by CHANCE_OF_ACTION by in the order given
|
||||||
|
(no randomness) and allows for setting up a more complex chain of
|
||||||
|
commands (such as creating an account and logging in).
|
||||||
|
|
||||||
|
"""
|
||||||
|
# Dummy runner settings
|
||||||
|
|
||||||
|
# Time between each dummyrunner "tick", in seconds. Each dummy
|
||||||
|
# will be called with this frequency.
|
||||||
|
TIMESTEP = 2
|
||||||
|
|
||||||
|
# Chance of a dummy actually performing an action on a given tick.
|
||||||
|
# This spreads out usage randomly, like it would be in reality.
|
||||||
|
CHANCE_OF_ACTION = 0.05
|
||||||
|
|
||||||
|
# Chance of a currently unlogged-in dummy performing its login
|
||||||
|
# action every tick. This emulates not all players logging in
|
||||||
|
# at exactly the same time.
|
||||||
|
CHANCE_OF_LOGIN = 0.33
|
||||||
|
|
||||||
|
# Which telnet port to connect to. If set to None, uses the first
|
||||||
|
# default telnet port of the running server.
|
||||||
|
TELNET_PORT = None
|
||||||
|
|
||||||
|
|
||||||
|
# Setup actions tuple
|
||||||
|
|
||||||
|
# some convenient templates
|
||||||
|
|
||||||
|
DUMMY_NAME = "Dummy-%s"
|
||||||
|
DUMMY_PWD = "password-%s"
|
||||||
|
START_ROOM = "testing_room_start_%s"
|
||||||
|
ROOM_TEMPLATE = "testing_room_%s"
|
||||||
|
EXIT_TEMPLATE = "exit_%s"
|
||||||
|
OBJ_TEMPLATE = "testing_obj_%s"
|
||||||
|
TOBJ_TEMPLATE = "testing_button_%s"
|
||||||
|
TOBJ_TYPECLASS = "contrib.tutorial_examples.red_button.RedButton"
|
||||||
|
|
||||||
|
|
||||||
|
# action function definitions (pick and choose from
|
||||||
|
# these to build a client "usage profile"
|
||||||
|
|
||||||
|
# login/logout
|
||||||
|
|
||||||
|
def c_login(client):
|
||||||
|
"logins to the game"
|
||||||
|
# we always use a new client name
|
||||||
|
cname = DUMMY_NAME % client.gid
|
||||||
|
cpwd = DUMMY_PWD % client.gid
|
||||||
|
|
||||||
|
# set up for digging a first room (to move to and keep the
|
||||||
|
# login room clean)
|
||||||
|
roomname = ROOM_TEMPLATE % client.counter()
|
||||||
|
exitname1 = EXIT_TEMPLATE % client.counter()
|
||||||
|
exitname2 = EXIT_TEMPLATE % client.counter()
|
||||||
|
client.exits.extend([exitname1, exitname2])
|
||||||
|
|
||||||
|
cmds = ('create %s %s' % (cname, cpwd),
|
||||||
|
'connect %s %s' % (cname, cpwd),
|
||||||
|
'@dig %s' % START_ROOM % client.cid,
|
||||||
|
'@teleport %s' % START_ROOM % client.cid,
|
||||||
|
'@dig %s = %s, %s' % (roomname, exitname1, exitname2)
|
||||||
|
)
|
||||||
|
return cmds
|
||||||
|
|
||||||
|
def c_login_nodig(client):
|
||||||
|
"logins, don't dig its own room"
|
||||||
|
cname = DUMMY_NAME % client.gid
|
||||||
|
cpwd = DUMMY_PWD % client.gid
|
||||||
|
|
||||||
|
cmds = ('create %s %s' % (cname, cpwd),
|
||||||
|
'connect %s %s' % (cname, cpwd))
|
||||||
|
return cmds
|
||||||
|
|
||||||
|
def c_logout(client):
|
||||||
|
"logouts of the game"
|
||||||
|
return "@quit"
|
||||||
|
|
||||||
|
# random commands
|
||||||
|
|
||||||
|
def c_looks(client):
|
||||||
|
"looks at various objects"
|
||||||
|
cmds = ["look %s" % obj for obj in client.objs]
|
||||||
|
if not cmds:
|
||||||
|
cmds = ["look %s" % exi for exi in client.exits]
|
||||||
|
if not cmds:
|
||||||
|
cmds = "look"
|
||||||
|
return cmds
|
||||||
|
|
||||||
|
def c_examines(client):
|
||||||
|
"examines various objects"
|
||||||
|
cmds = ["examine %s" % obj for obj in client.objs]
|
||||||
|
if not cmds:
|
||||||
|
cmds = ["examine %s" % exi for exi in client.exits]
|
||||||
|
if not cmds:
|
||||||
|
cmds = "examine me"
|
||||||
|
return cmds
|
||||||
|
|
||||||
|
def c_help(client):
|
||||||
|
"reads help files"
|
||||||
|
cmds = ('help',
|
||||||
|
'help @teleport',
|
||||||
|
'help look',
|
||||||
|
'help @tunnel',
|
||||||
|
'help @dig')
|
||||||
|
return cmds
|
||||||
|
|
||||||
|
def c_digs(client):
|
||||||
|
"digs a new room, storing exit names on client"
|
||||||
|
roomname = ROOM_TEMPLATE % client.counter()
|
||||||
|
exitname1 = EXIT_TEMPLATE % client.counter()
|
||||||
|
exitname2 = EXIT_TEMPLATE % client.counter()
|
||||||
|
client.exits.extend([exitname1, exitname2])
|
||||||
|
return '@dig/tel %s = %s, %s' % (roomname, exitname1, exitname2)
|
||||||
|
|
||||||
|
def c_creates_obj(client):
|
||||||
|
"creates normal objects, storing their name on client"
|
||||||
|
objname = OBJ_TEMPLATE % client.counter()
|
||||||
|
client.objs.append(objname)
|
||||||
|
cmds = ('@create %s' % objname,
|
||||||
|
'@desc %s = "this is a test object' % objname,
|
||||||
|
'@set %s/testattr = this is a test attribute value.' % objname,
|
||||||
|
'@set %s/testattr2 = this is a second test attribute.' % objname)
|
||||||
|
return cmds
|
||||||
|
|
||||||
|
def c_creates_button(client):
|
||||||
|
"creates example button, storing name on client"
|
||||||
|
objname = TOBJ_TEMPLATE % client.counter()
|
||||||
|
client.objs.append(objname)
|
||||||
|
cmds = ('@create %s:%s' % (objname, TOBJ_TYPECLASS),
|
||||||
|
'@desc %s = test red button!' % objname)
|
||||||
|
return cmds
|
||||||
|
|
||||||
|
def c_socialize(client):
|
||||||
|
"socializechats on channel"
|
||||||
|
cmds = ('ooc Hello!',
|
||||||
|
'ooc Testing ...',
|
||||||
|
'ooc Testing ... times 2',
|
||||||
|
'say Yo!',
|
||||||
|
'emote stands looking around.')
|
||||||
|
return cmds
|
||||||
|
|
||||||
|
def c_moves(client):
|
||||||
|
"moves to a previously created room, using the stored exits"
|
||||||
|
cmds = client.exits # try all exits - finally one will work
|
||||||
|
return "look" if not cmds else cmds
|
||||||
|
|
||||||
|
def c_moves_n(client):
|
||||||
|
"move through north exit if available"
|
||||||
|
return "north"
|
||||||
|
|
||||||
|
def c_moves_s(client):
|
||||||
|
"move through south exit if available"
|
||||||
|
return "south"
|
||||||
|
|
||||||
|
# Action tuple (required)
|
||||||
|
#
|
||||||
|
# This is a tuple of client action functions. The first element is the
|
||||||
|
# function the client should use to log into the game and move to
|
||||||
|
# STARTROOM . The second element is the logout command, for cleanly
|
||||||
|
# exiting the mud. The following elements are 2-tuples of (probability,
|
||||||
|
# action_function). The probablities should normally sum up to 1,
|
||||||
|
# otherwise the system will normalize them.
|
||||||
|
#
|
||||||
|
|
||||||
|
## "normal builder" definitionj
|
||||||
|
#ACTIONS = ( c_login,
|
||||||
|
# c_logout,
|
||||||
|
# (0.5, c_looks),
|
||||||
|
# (0.08, c_examines),
|
||||||
|
# (0.1, c_help),
|
||||||
|
# (0.01, c_digs),
|
||||||
|
# (0.01, c_creates_obj),
|
||||||
|
# (0.3, c_moves))
|
||||||
|
## "heavy" builder definition
|
||||||
|
#ACTIONS = ( c_login,
|
||||||
|
# c_logout,
|
||||||
|
# (0.2, c_looks),
|
||||||
|
# (0.1, c_examines),
|
||||||
|
# (0.2, c_help),
|
||||||
|
# (0.1, c_digs),
|
||||||
|
# (0.1, c_creates_obj),
|
||||||
|
# #(0.01, c_creates_button),
|
||||||
|
# (0.2, c_moves))
|
||||||
|
## "passive player" definition
|
||||||
|
#ACTIONS = ( c_login,
|
||||||
|
# c_logout,
|
||||||
|
# (0.7, c_looks),
|
||||||
|
# #(0.1, c_examines),
|
||||||
|
# (0.3, c_help))
|
||||||
|
# #(0.1, c_digs),
|
||||||
|
# #(0.1, c_creates_obj),
|
||||||
|
# #(0.1, c_creates_button),
|
||||||
|
# #(0.4, c_moves))
|
||||||
|
## "normal player" definition
|
||||||
|
ACTIONS = ( c_login,
|
||||||
|
c_logout,
|
||||||
|
(0.01, c_digs),
|
||||||
|
(0.39, c_looks),
|
||||||
|
(0.2, c_help),
|
||||||
|
(0.4, c_moves))
|
||||||
|
#ACTIONS = (c_login_nodig,
|
||||||
|
# c_logout,
|
||||||
|
# (1.0, c_moves_n))
|
||||||
|
## "socializing heavy builder" definition
|
||||||
|
#ACTIONS = (c_login,
|
||||||
|
# c_logout,
|
||||||
|
# (0.1, c_socialize),
|
||||||
|
# (0.1, c_looks),
|
||||||
|
# (0.2, c_help),
|
||||||
|
# (0.1, c_creates_obj),
|
||||||
|
# (0.2, c_digs),
|
||||||
|
# (0.3, c_moves))
|
||||||
|
## "heavy digger memory tester" definition
|
||||||
|
#ACTIONS = (c_login,
|
||||||
|
# c_logout,
|
||||||
|
# (1.0, c_digs))
|
||||||
|
|
@ -243,6 +243,9 @@ LOCK_FUNC_MODULES = ("evennia.locks.lockfuncs", "server.conf.lockfuncs",)
|
||||||
# and expansion of which hooks OOB protocols are allowed to call on the server
|
# and expansion of which hooks OOB protocols are allowed to call on the server
|
||||||
# protocols for attaching tracker hooks for when various object field change
|
# protocols for attaching tracker hooks for when various object field change
|
||||||
OOB_PLUGIN_MODULES = ["evennia.server.oob_cmds", "server.conf.oobfuncs"]
|
OOB_PLUGIN_MODULES = ["evennia.server.oob_cmds", "server.conf.oobfuncs"]
|
||||||
|
# Module holding settings/actions for the dummyrunner program (see the
|
||||||
|
# dummyrunner for more information)
|
||||||
|
DUMMYRUNNER_SETTINGS_MODULE = os.path.join(ROOT_DIR, "bin/testing/dummyrunner_settings")
|
||||||
|
|
||||||
######################################################################
|
######################################################################
|
||||||
# Default command sets
|
# Default command sets
|
||||||
|
|
|
||||||
|
|
@ -1,231 +0,0 @@
|
||||||
"""
|
|
||||||
These are actions for the dummy client runner, using
|
|
||||||
the default command set and intended for unmodified Evennia.
|
|
||||||
|
|
||||||
Each client action is defined as a function. The clients
|
|
||||||
will perform these actions randomly (except the login action).
|
|
||||||
|
|
||||||
Each action-definition function should take one argument- "client",
|
|
||||||
which is a reference to the client currently performing the action
|
|
||||||
Use the client object for saving data between actions.
|
|
||||||
|
|
||||||
The client object has the following relevant properties and methods:
|
|
||||||
cid - unique client id
|
|
||||||
istep - the current step
|
|
||||||
exits - an empty list. Can be used to store exit names
|
|
||||||
objs - an empty list. Can be used to store object names
|
|
||||||
counter() - get an integer value. This counts up for every call and
|
|
||||||
is always unique between clients.
|
|
||||||
|
|
||||||
The action-definition function should return the command that the
|
|
||||||
client should send to the server (as if it was input in a mud client).
|
|
||||||
It should also return a string detailing the action taken. This string is
|
|
||||||
used by the "brief verbose" mode of the runner and is prepended by
|
|
||||||
"Client N " to produce output like "Client 3 is creating objects ..."
|
|
||||||
|
|
||||||
This module *must* also define a variable named ACTIONS. This is a tuple
|
|
||||||
where the first element is the function object for the action function
|
|
||||||
to call when the client logs onto the server. The following elements
|
|
||||||
are 2-tuples (probability, action_func), where probability defines how
|
|
||||||
common it is for that particular action to happen. The runner will
|
|
||||||
randomly pick between those functions based on the probability.
|
|
||||||
|
|
||||||
ACTIONS = (login_func, (0.3, func1), (0.1, func2) ... )
|
|
||||||
|
|
||||||
To change the runner to use your custom ACTION and/or action
|
|
||||||
definitions, edit settings.py and add
|
|
||||||
|
|
||||||
DUMMYRUNNER_ACTIONS_MODULE = "path.to.your.module"
|
|
||||||
|
|
||||||
"""
|
|
||||||
|
|
||||||
# it's very useful to have a unique id for this run to avoid any risk
|
|
||||||
# of clashes
|
|
||||||
|
|
||||||
import time
|
|
||||||
RUNID = time.time()
|
|
||||||
|
|
||||||
# some convenient templates
|
|
||||||
|
|
||||||
START_ROOM = "testing_room_start-%s-%s" % (RUNID, "%i")
|
|
||||||
ROOM_TEMPLATE = "testing_room_%s-%s" % (RUNID, "%i")
|
|
||||||
EXIT_TEMPLATE = "exit_%s-%s" % (RUNID, "%i")
|
|
||||||
OBJ_TEMPLATE = "testing_obj_%s-%s" % (RUNID, "%i")
|
|
||||||
TOBJ_TEMPLATE = "testing_button_%s-%s" % (RUNID, "%i")
|
|
||||||
TOBJ_TYPECLASS = "examples.red_button.RedButton"
|
|
||||||
|
|
||||||
# action function definitions
|
|
||||||
|
|
||||||
def c_login(client):
|
|
||||||
"logins to the game"
|
|
||||||
cname = "Dummy-%s-%i" % (RUNID, client.cid)
|
|
||||||
#cemail = "%s@dummy.com" % (cname.lower())
|
|
||||||
cpwd = "%s-%s" % (RUNID, client.cid)
|
|
||||||
# set up for digging a first room (to move to)
|
|
||||||
roomname = ROOM_TEMPLATE % client.counter()
|
|
||||||
exitname1 = EXIT_TEMPLATE % client.counter()
|
|
||||||
exitname2 = EXIT_TEMPLATE % client.counter()
|
|
||||||
client.exits.extend([exitname1, exitname2])
|
|
||||||
#cmd = '@dig %s = %s, %s' % (roomname, exitname1, exitname2)
|
|
||||||
cmd = ('create %s %s' % (cname, cpwd),
|
|
||||||
'connect %s %s' % (cname, cpwd),
|
|
||||||
'@dig %s' % START_ROOM % client.cid,
|
|
||||||
'@teleport %s' % START_ROOM % client.cid,
|
|
||||||
'@dig %s = %s, %s' % (roomname, exitname1, exitname2)
|
|
||||||
)
|
|
||||||
|
|
||||||
return cmd, "logs in as %s ..." % cname
|
|
||||||
|
|
||||||
def c_login_nodig(client):
|
|
||||||
"logins, don't dig its own room"
|
|
||||||
cname = "Dummy-%s-%i" % (RUNID, client.cid)
|
|
||||||
cpwd = "%s-%s" % (RUNID, client.cid)
|
|
||||||
cmd = ('create %s %s' % (cname, cpwd),
|
|
||||||
'connect %s %s' % (cname, cpwd))
|
|
||||||
return cmd, "logs in as %s ..." % cname
|
|
||||||
|
|
||||||
def c_logout(client):
|
|
||||||
"logouts of the game"
|
|
||||||
return "@quit", "logs out"
|
|
||||||
|
|
||||||
def c_looks(client):
|
|
||||||
"looks at various objects"
|
|
||||||
cmd = ["look %s" % obj for obj in client.objs]
|
|
||||||
if not cmd:
|
|
||||||
cmd = ["look %s" % exi for exi in client.exits]
|
|
||||||
if not cmd:
|
|
||||||
cmd = "look"
|
|
||||||
return cmd, "looks ..."
|
|
||||||
|
|
||||||
def c_examines(client):
|
|
||||||
"examines various objects"
|
|
||||||
cmd = ["examine %s" % obj for obj in client.objs]
|
|
||||||
if not cmd:
|
|
||||||
cmd = ["examine %s" % exi for exi in client.exits]
|
|
||||||
if not cmd:
|
|
||||||
cmd = "examine me"
|
|
||||||
return cmd, "examines objs ..."
|
|
||||||
|
|
||||||
def c_help(client):
|
|
||||||
"reads help files"
|
|
||||||
cmd = ('help',
|
|
||||||
'help @teleport',
|
|
||||||
'help look',
|
|
||||||
'help @tunnel',
|
|
||||||
'help @dig')
|
|
||||||
return cmd, "reads help ..."
|
|
||||||
|
|
||||||
def c_digs(client):
|
|
||||||
"digs a new room, storing exit names on client"
|
|
||||||
roomname = ROOM_TEMPLATE % client.counter()
|
|
||||||
exitname1 = EXIT_TEMPLATE % client.counter()
|
|
||||||
exitname2 = EXIT_TEMPLATE % client.counter()
|
|
||||||
client.exits.extend([exitname1, exitname2])
|
|
||||||
cmd = '@dig/tel %s = %s, %s' % (roomname, exitname1, exitname2)
|
|
||||||
return cmd, "digs ..."
|
|
||||||
|
|
||||||
def c_creates_obj(client):
|
|
||||||
"creates normal objects, storing their name on client"
|
|
||||||
objname = OBJ_TEMPLATE % client.counter()
|
|
||||||
client.objs.append(objname)
|
|
||||||
cmd = ('@create %s' % objname,
|
|
||||||
'@desc %s = "this is a test object' % objname,
|
|
||||||
'@set %s/testattr = this is a test attribute value.' % objname,
|
|
||||||
'@set %s/testattr2 = this is a second test attribute.' % objname)
|
|
||||||
return cmd, "creates obj ..."
|
|
||||||
|
|
||||||
def c_creates_button(client):
|
|
||||||
"creates example button, storing name on client"
|
|
||||||
objname = TOBJ_TEMPLATE % client.counter()
|
|
||||||
client.objs.append(objname)
|
|
||||||
cmd = ('@create %s:%s' % (objname, TOBJ_TYPECLASS),
|
|
||||||
'@desc %s = test red button!' % objname)
|
|
||||||
return cmd, "creates button ..."
|
|
||||||
|
|
||||||
def c_socialize(client):
|
|
||||||
"socializechats on channel"
|
|
||||||
cmd = ('ooc Hello!',
|
|
||||||
'ooc Testing ...',
|
|
||||||
'ooc Testing ... times 2',
|
|
||||||
'say Yo!',
|
|
||||||
'emote stands looking around.')
|
|
||||||
return cmd, "socializes ..."
|
|
||||||
|
|
||||||
def c_moves(client):
|
|
||||||
"moves to a previously created room, using the stored exits"
|
|
||||||
cmd = client.exits # try all exits - finally one will work
|
|
||||||
if not cmd: cmd = "look"
|
|
||||||
return cmd, "moves ..."
|
|
||||||
|
|
||||||
def c_moves_n(client):
|
|
||||||
"move through north exit if available"
|
|
||||||
cmd = ("north",)
|
|
||||||
return cmd, "moves n..."
|
|
||||||
|
|
||||||
def c_moves_s(client):
|
|
||||||
"move through north exit if available"
|
|
||||||
cmd = ("north",)
|
|
||||||
return cmd, "moves s..."
|
|
||||||
|
|
||||||
# Action tuple (required)
|
|
||||||
#
|
|
||||||
# This is a tuple of client action functions. The first element is the
|
|
||||||
# function the client should use to log into the game and move to
|
|
||||||
# STARTROOM . The second element is the logout command, for cleanly
|
|
||||||
# exiting the mud. The following elements are 2-tuples of (probability,
|
|
||||||
# action_function). The probablities should normally sum up to 1,
|
|
||||||
# otherwise the system will normalize them.
|
|
||||||
#
|
|
||||||
|
|
||||||
## "normal builder" definitionj
|
|
||||||
#ACTIONS = ( c_login,
|
|
||||||
# c_logout,
|
|
||||||
# (0.5, c_looks),
|
|
||||||
# (0.08, c_examines),
|
|
||||||
# (0.1, c_help),
|
|
||||||
# (0.01, c_digs),
|
|
||||||
# (0.01, c_creates_obj),
|
|
||||||
# (0.3, c_moves))
|
|
||||||
## "heavy" builder definition
|
|
||||||
#ACTIONS = ( c_login,
|
|
||||||
# c_logout,
|
|
||||||
# (0.2, c_looks),
|
|
||||||
# (0.1, c_examines),
|
|
||||||
# (0.2, c_help),
|
|
||||||
# (0.1, c_digs),
|
|
||||||
# (0.1, c_creates_obj),
|
|
||||||
# #(0.01, c_creates_button),
|
|
||||||
# (0.2, c_moves))
|
|
||||||
## "passive player" definition
|
|
||||||
#ACTIONS = ( c_login,
|
|
||||||
# c_logout,
|
|
||||||
# (0.7, c_looks),
|
|
||||||
# #(0.1, c_examines),
|
|
||||||
# (0.3, c_help))
|
|
||||||
# #(0.1, c_digs),
|
|
||||||
# #(0.1, c_creates_obj),
|
|
||||||
# #(0.1, c_creates_button),
|
|
||||||
# #(0.4, c_moves))
|
|
||||||
## "normal player" definition
|
|
||||||
ACTIONS = ( c_login,
|
|
||||||
c_logout,
|
|
||||||
(0.01, c_digs),
|
|
||||||
(0.39, c_looks),
|
|
||||||
(0.2, c_help),
|
|
||||||
(0.4, c_moves))
|
|
||||||
#ACTIONS = (c_login_nodig,
|
|
||||||
# c_logout,
|
|
||||||
# (1.0, c_moves_n))
|
|
||||||
## "socializing heavy builder" definition
|
|
||||||
#ACTIONS = (c_login,
|
|
||||||
# c_logout,
|
|
||||||
# (0.1, c_socialize),
|
|
||||||
# (0.1, c_looks),
|
|
||||||
# (0.2, c_help),
|
|
||||||
# (0.1, c_creates_obj),
|
|
||||||
# (0.2, c_digs),
|
|
||||||
# (0.3, c_moves))
|
|
||||||
## "heavy digger memory tester" definition
|
|
||||||
#ACTIONS = (c_login,
|
|
||||||
# c_logout,
|
|
||||||
# (1.0, c_digs))
|
|
||||||
|
|
@ -765,7 +765,7 @@ def mod_import(module):
|
||||||
module - this can be either a Python path (dot-notation like
|
module - this can be either a Python path (dot-notation like
|
||||||
evennia.objects.models), an absolute path
|
evennia.objects.models), an absolute path
|
||||||
(e.g. /home/eve/evennia/evennia/objects.models.py)
|
(e.g. /home/eve/evennia/evennia/objects.models.py)
|
||||||
or an already import module object (e.g. models)
|
or an already imported module object (e.g. models)
|
||||||
Returns:
|
Returns:
|
||||||
an imported module. If the input argument was already a model,
|
an imported module. If the input argument was already a model,
|
||||||
this is returned as-is, otherwise the path is parsed and imported.
|
this is returned as-is, otherwise the path is parsed and imported.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue