Updated the game template, renaming subdir typeclasses rather than types since the latter collides with the python library module of the same name.
|
|
@ -16,7 +16,7 @@ import shutil
|
||||||
import importlib
|
import importlib
|
||||||
from argparse import ArgumentParser
|
from argparse import ArgumentParser
|
||||||
from subprocess import Popen
|
from subprocess import Popen
|
||||||
from django.core import management
|
import django
|
||||||
|
|
||||||
# Signal processing
|
# Signal processing
|
||||||
SIG = signal.SIGINT
|
SIG = signal.SIGINT
|
||||||
|
|
@ -87,9 +87,9 @@ CREATED_NEW_GAMEDIR = \
|
||||||
"""
|
"""
|
||||||
... Created new Evennia game directory '{gamedir}'.
|
... Created new Evennia game directory '{gamedir}'.
|
||||||
|
|
||||||
Inside your new game directory, edit {settings_path} to suit your
|
Inside your new game directory, you can now optionally edit
|
||||||
setup, then run this command again from inside the game directory
|
{settings_path} to suit your setup. Then run this command again
|
||||||
to start the server.
|
from inside the game directory to start the server.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
ERROR_NO_GAMEDIR = \
|
ERROR_NO_GAMEDIR = \
|
||||||
|
|
@ -433,13 +433,12 @@ def init_game_directory(path):
|
||||||
# Prepare django; set the settings location
|
# Prepare django; set the settings location
|
||||||
os.environ['DJANGO_SETTINGS_MODULE'] = SETTINGS_DOTPATH
|
os.environ['DJANGO_SETTINGS_MODULE'] = SETTINGS_DOTPATH
|
||||||
|
|
||||||
# testing the main library import. If there are errors in importing
|
# required since django1.7
|
||||||
# the main library, it should show here.
|
django.setup()
|
||||||
importlib.import_module("evennia")
|
|
||||||
|
|
||||||
# test existence of the settings module
|
# test existence of the settings module
|
||||||
try:
|
try:
|
||||||
settings = importlib.import_module(SETTINGS_DOTPATH)
|
from django.conf import settings
|
||||||
except Exception, ex:
|
except Exception, ex:
|
||||||
if not str(ex).startswith("No module named"):
|
if not str(ex).startswith("No module named"):
|
||||||
import traceback
|
import traceback
|
||||||
|
|
@ -447,16 +446,15 @@ def init_game_directory(path):
|
||||||
print ERROR_SETTINGS
|
print ERROR_SETTINGS
|
||||||
sys.exit()
|
sys.exit()
|
||||||
|
|
||||||
import django
|
# testing the main library import. If there are errors in importing
|
||||||
# required since django1.7.
|
# the main library, it should show here.
|
||||||
django.setup()
|
importlib.import_module("evennia")
|
||||||
|
|
||||||
# check all dependencies
|
# check all dependencies
|
||||||
from evennia.utils.utils import check_evennia_dependencies
|
from evennia.utils.utils import check_evennia_dependencies
|
||||||
if not check_evennia_dependencies:
|
if not check_evennia_dependencies:
|
||||||
sys.exit()
|
sys.exit()
|
||||||
|
|
||||||
|
|
||||||
# set up the Evennia executables and log file locations
|
# set up the Evennia executables and log file locations
|
||||||
global SERVER_PY_FILE, PORTAL_PY_FILE
|
global SERVER_PY_FILE, PORTAL_PY_FILE
|
||||||
global SERVER_LOGFILE, PORTAL_LOGFILE, HTTP_LOGFILE
|
global SERVER_LOGFILE, PORTAL_LOGFILE, HTTP_LOGFILE
|
||||||
|
|
@ -523,16 +521,14 @@ def init_game_directory(path):
|
||||||
|
|
||||||
|
|
||||||
def create_database():
|
def create_database():
|
||||||
from django.core.management import call_command
|
|
||||||
print "\nCreating a database ...\n"
|
print "\nCreating a database ...\n"
|
||||||
call_command("migrate", interactive=False)
|
django.core.management.call_command("migrate", interactive=False)
|
||||||
print "\n ... database initialized.\n"
|
print "\n ... database initialized.\n"
|
||||||
|
|
||||||
|
|
||||||
def create_superuser():
|
def create_superuser():
|
||||||
from django.core.management import call_command
|
|
||||||
print "\nCreate a superuser below. The superuser is Player #1, the 'owner' account of the server.\n"
|
print "\nCreate a superuser below. The superuser is Player #1, the 'owner' account of the server.\n"
|
||||||
call_command("createsuperuser", interactive=True)
|
django.core.management.call_command("createsuperuser", interactive=True)
|
||||||
|
|
||||||
|
|
||||||
def check_database(automigrate=False):
|
def check_database(automigrate=False):
|
||||||
|
|
@ -589,7 +585,7 @@ def kill(pidfile, signal=SIG, succmsg="", errmsg="", restart_file=SERVER_RESTART
|
||||||
os.remove(pidfile)
|
os.remove(pidfile)
|
||||||
# set restart/norestart flag
|
# set restart/norestart flag
|
||||||
if restart == 'reload':
|
if restart == 'reload':
|
||||||
management.call_command('collectstatic', interactive=False, verbosity=0)
|
django.core.management.call_command('collectstatic', interactive=False, verbosity=0)
|
||||||
f = open(restart_file, 'w')
|
f = open(restart_file, 'w')
|
||||||
f.write(str(restart))
|
f.write(str(restart))
|
||||||
f.close()
|
f.close()
|
||||||
|
|
@ -715,7 +711,7 @@ def server_operation(mode, service, interactive, profiler):
|
||||||
if interactive:
|
if interactive:
|
||||||
cmdstr.append('--iportal')
|
cmdstr.append('--iportal')
|
||||||
cmdstr.append('--noserver')
|
cmdstr.append('--noserver')
|
||||||
management.call_command('collectstatic', verbosity=1, interactive=False)
|
django.core.management.call_command('collectstatic', verbosity=1, interactive=False)
|
||||||
else: # all
|
else: # all
|
||||||
# for convenience we don't start logging of
|
# for convenience we don't start logging of
|
||||||
# portal, only of server with this command.
|
# portal, only of server with this command.
|
||||||
|
|
@ -723,7 +719,7 @@ def server_operation(mode, service, interactive, profiler):
|
||||||
cmdstr.append('--profile-server') # this is the common case
|
cmdstr.append('--profile-server') # this is the common case
|
||||||
if interactive:
|
if interactive:
|
||||||
cmdstr.append('--iserver')
|
cmdstr.append('--iserver')
|
||||||
management.call_command('collectstatic', verbosity=1, interactive=False)
|
django.core.management.call_command('collectstatic', verbosity=1, interactive=False)
|
||||||
cmdstr.extend([GAMEDIR, TWISTED_BINARY, SERVER_LOGFILE, PORTAL_LOGFILE, HTTP_LOGFILE])
|
cmdstr.extend([GAMEDIR, TWISTED_BINARY, SERVER_LOGFILE, PORTAL_LOGFILE, HTTP_LOGFILE])
|
||||||
# start the server
|
# start the server
|
||||||
Popen(cmdstr)
|
Popen(cmdstr)
|
||||||
|
|
@ -766,15 +762,20 @@ def error_check_python_modules():
|
||||||
before we get any further.
|
before we get any further.
|
||||||
"""
|
"""
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
def imp(path, split=True):
|
||||||
|
mod, fromlist = path, "None"
|
||||||
|
if split:
|
||||||
|
mod, fromlist = path.rsplit('.', 1)
|
||||||
|
__import__(mod, fromlist=[fromlist])
|
||||||
|
|
||||||
# core modules
|
# core modules
|
||||||
importlib.import_module(settings.COMMAND_PARSER)
|
imp(settings.COMMAND_PARSER)
|
||||||
importlib.import_module(settings.SEARCH_AT_RESULT)
|
imp(settings.SEARCH_AT_RESULT)
|
||||||
importlib.import_module(settings.SEARCH_AT_MULTIMATCH_INPUT)
|
imp(settings.SEARCH_AT_MULTIMATCH_INPUT)
|
||||||
importlib.import_module(settings.CONNECTION_SCREEN_MODULE, split=False)
|
imp(settings.CONNECTION_SCREEN_MODULE, split=False)
|
||||||
#imp(settings.AT_INITIAL_SETUP_HOOK_MODULE, split=False)
|
#imp(settings.AT_INITIAL_SETUP_HOOK_MODULE, split=False)
|
||||||
for path in settings.LOCK_FUNC_MODULES:
|
for path in settings.LOCK_FUNC_MODULES:
|
||||||
importlib.import_module(path, split=False)
|
imp(path, split=False)
|
||||||
# cmdsets
|
# cmdsets
|
||||||
|
|
||||||
deprstring = "settings.%s should be renamed to %s. If defaults are used, " \
|
deprstring = "settings.%s should be renamed to %s. If defaults are used, " \
|
||||||
|
|
@ -798,12 +799,12 @@ def error_check_python_modules():
|
||||||
if not cmdsethandler.import_cmdset(settings.CMDSET_CHARACTER, None): print "Warning: CMDSET_CHARACTER failed to load"
|
if not cmdsethandler.import_cmdset(settings.CMDSET_CHARACTER, None): print "Warning: CMDSET_CHARACTER failed to load"
|
||||||
if not cmdsethandler.import_cmdset(settings.CMDSET_PLAYER, None): print "Warning: CMDSET_PLAYER failed to load"
|
if not cmdsethandler.import_cmdset(settings.CMDSET_PLAYER, None): print "Warning: CMDSET_PLAYER failed to load"
|
||||||
# typeclasses
|
# typeclasses
|
||||||
importlib.import_module(settings.BASE_PLAYER_TYPECLASS)
|
imp(settings.BASE_PLAYER_TYPECLASS)
|
||||||
importlib.import_module(settings.BASE_OBJECT_TYPECLASS)
|
imp(settings.BASE_OBJECT_TYPECLASS)
|
||||||
importlib.import_module(settings.BASE_CHARACTER_TYPECLASS)
|
imp(settings.BASE_CHARACTER_TYPECLASS)
|
||||||
importlib.import_module(settings.BASE_ROOM_TYPECLASS)
|
imp(settings.BASE_ROOM_TYPECLASS)
|
||||||
importlib.import_module(settings.BASE_EXIT_TYPECLASS)
|
imp(settings.BASE_EXIT_TYPECLASS)
|
||||||
importlib.import_module(settings.BASE_SCRIPT_TYPECLASS)
|
imp(settings.BASE_SCRIPT_TYPECLASS)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -864,8 +865,7 @@ def main():
|
||||||
# pass-through to django manager
|
# pass-through to django manager
|
||||||
if mode in ('runserver', 'testserver'):
|
if mode in ('runserver', 'testserver'):
|
||||||
print WARNING_RUNSERVER
|
print WARNING_RUNSERVER
|
||||||
from django.core.management import call_command
|
django.core.management.call_command(mode)
|
||||||
call_command(mode)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|
|
||||||
|
|
@ -12,202 +12,204 @@ See www.evennia.com for full documentation.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
######################################################################
|
if False:
|
||||||
# set Evennia version in __version__ property
|
|
||||||
######################################################################
|
|
||||||
import os
|
|
||||||
try:
|
|
||||||
__version__ = "Evennia"
|
|
||||||
with os.path.join(open(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))), "VERSION.txt", 'r') as f:
|
|
||||||
__version__ += " %s" % f.read().strip()
|
|
||||||
except IOError:
|
|
||||||
__version__ += " (unknown version)"
|
|
||||||
del os
|
|
||||||
|
|
||||||
######################################################################
|
######################################################################
|
||||||
# Start Evennia API
|
# set Evennia version in __version__ property
|
||||||
# (easiest is to import this module interactively to explore it)
|
######################################################################
|
||||||
######################################################################
|
import os
|
||||||
|
try:
|
||||||
|
__version__ = "Evennia"
|
||||||
|
with os.path.join(open(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))), "VERSION.txt", 'r') as f:
|
||||||
|
__version__ += " %s" % f.read().strip()
|
||||||
|
except IOError:
|
||||||
|
__version__ += " (unknown version)"
|
||||||
|
del os
|
||||||
|
|
||||||
# help entries
|
######################################################################
|
||||||
from help.models import HelpEntry
|
# Start Evennia API
|
||||||
|
# (easiest is to import this module interactively to explore it)
|
||||||
|
######################################################################
|
||||||
|
|
||||||
# players
|
# help entries
|
||||||
from players.player import DefaultPlayer
|
|
||||||
from players.models import PlayerDB
|
|
||||||
|
|
||||||
# commands
|
|
||||||
from commands.command import Command
|
|
||||||
from commands.cmdset import CmdSet
|
|
||||||
# (default_cmds is created below)
|
|
||||||
|
|
||||||
# locks
|
|
||||||
from locks import lockfuncs
|
|
||||||
|
|
||||||
# scripts
|
|
||||||
from scripts.scripts import Script
|
|
||||||
|
|
||||||
# comms
|
|
||||||
from comms.models import Msg, ChannelDB
|
|
||||||
from comms.comms import Channel
|
|
||||||
|
|
||||||
# objects
|
|
||||||
from objects.objects import DefaultObject, DefaultCharacter, DefaultRoom, DefaultExit
|
|
||||||
|
|
||||||
# utils
|
|
||||||
|
|
||||||
from utils.search import *
|
|
||||||
from utils.create import *
|
|
||||||
from scripts.tickerhandler import TICKER_HANDLER as tickerhandler
|
|
||||||
from utils import logger
|
|
||||||
from utils import utils
|
|
||||||
from utils import gametime
|
|
||||||
from utils import ansi
|
|
||||||
from utils.spawner import spawn
|
|
||||||
|
|
||||||
######################################################################
|
|
||||||
# API containers and helper functions
|
|
||||||
######################################################################
|
|
||||||
|
|
||||||
def help(header=False):
|
|
||||||
"""
|
|
||||||
Main Evennia API.
|
|
||||||
ev.help() views API contents
|
|
||||||
ev.help(True) or ev.README shows module instructions
|
|
||||||
|
|
||||||
See www.evennia.com for the full documentation.
|
|
||||||
"""
|
|
||||||
if header:
|
|
||||||
return __doc__
|
|
||||||
else:
|
|
||||||
import ev
|
|
||||||
names = [str(var) for var in ev.__dict__ if not var.startswith('_')]
|
|
||||||
return ", ".join(names)
|
|
||||||
|
|
||||||
|
|
||||||
class _EvContainer(object):
|
|
||||||
"""
|
|
||||||
Parent for other containers
|
|
||||||
|
|
||||||
"""
|
|
||||||
def _help(self):
|
|
||||||
"Returns list of contents"
|
|
||||||
names = [name for name in self.__class__.__dict__ if not name.startswith('_')]
|
|
||||||
names += [name for name in self.__dict__ if not name.startswith('_')]
|
|
||||||
print self.__doc__ + "-" * 60 + "\n" + ", ".join(names)
|
|
||||||
help = property(_help)
|
|
||||||
|
|
||||||
|
|
||||||
class DBmanagers(_EvContainer):
|
|
||||||
"""
|
|
||||||
Links to instantiated database managers.
|
|
||||||
|
|
||||||
helpentry - HelpEntry.objects
|
|
||||||
players - PlayerDB.objects
|
|
||||||
scripts - ScriptDB.objects
|
|
||||||
msgs - Msg.objects
|
|
||||||
channels - Channel.objects
|
|
||||||
objects - ObjectDB.objects
|
|
||||||
serverconfigs = ServerConfig.objects
|
|
||||||
tags - Tags.objects
|
|
||||||
attributes - Attributes.objects
|
|
||||||
|
|
||||||
"""
|
|
||||||
from help.models import HelpEntry
|
from help.models import HelpEntry
|
||||||
|
|
||||||
|
# players
|
||||||
|
from players.player import DefaultPlayer
|
||||||
from players.models import PlayerDB
|
from players.models import PlayerDB
|
||||||
from scripts.models import ScriptDB
|
|
||||||
|
# commands
|
||||||
|
from commands.command import Command
|
||||||
|
from commands.cmdset import CmdSet
|
||||||
|
# (default_cmds is created below)
|
||||||
|
|
||||||
|
# locks
|
||||||
|
from locks import lockfuncs
|
||||||
|
|
||||||
|
# scripts
|
||||||
|
from scripts.scripts import Script
|
||||||
|
|
||||||
|
# comms
|
||||||
from comms.models import Msg, ChannelDB
|
from comms.models import Msg, ChannelDB
|
||||||
from objects.models import ObjectDB
|
from comms.comms import Channel
|
||||||
from server.models import ServerConfig
|
|
||||||
from typeclasses.attributes import Attribute
|
|
||||||
from typeclasses.tags import Tag
|
|
||||||
|
|
||||||
# create container's properties
|
# objects
|
||||||
helpentries = HelpEntry.objects
|
from objects.objects import DefaultObject, DefaultCharacter, DefaultRoom, DefaultExit
|
||||||
players = PlayerDB.objects
|
|
||||||
scripts = ScriptDB.objects
|
|
||||||
msgs = Msg.objects
|
|
||||||
channels = ChannelDB.objects
|
|
||||||
objects = ObjectDB.objects
|
|
||||||
serverconfigs = ServerConfig.objects
|
|
||||||
attributes = Attribute.objects
|
|
||||||
tags = Tag.objects
|
|
||||||
# remove these so they are not visible as properties
|
|
||||||
del HelpEntry, PlayerDB, ScriptDB, Msg, ChannelDB
|
|
||||||
#del ExternalChannelConnection
|
|
||||||
del ObjectDB, ServerConfig, Tag, Attribute
|
|
||||||
|
|
||||||
managers = DBmanagers()
|
# utils
|
||||||
del DBmanagers
|
|
||||||
|
from utils.search import *
|
||||||
|
from utils.create import *
|
||||||
|
from scripts.tickerhandler import TICKER_HANDLER as tickerhandler
|
||||||
|
from utils import logger
|
||||||
|
from utils import utils
|
||||||
|
from utils import gametime
|
||||||
|
from utils import ansi
|
||||||
|
from utils.spawner import spawn
|
||||||
|
|
||||||
|
######################################################################
|
||||||
|
# API containers and helper functions
|
||||||
|
######################################################################
|
||||||
|
|
||||||
|
def help(header=False):
|
||||||
|
"""
|
||||||
|
Main Evennia API.
|
||||||
|
ev.help() views API contents
|
||||||
|
ev.help(True) or ev.README shows module instructions
|
||||||
|
|
||||||
|
See www.evennia.com for the full documentation.
|
||||||
|
"""
|
||||||
|
if header:
|
||||||
|
return __doc__
|
||||||
|
else:
|
||||||
|
import ev
|
||||||
|
names = [str(var) for var in ev.__dict__ if not var.startswith('_')]
|
||||||
|
return ", ".join(names)
|
||||||
|
|
||||||
|
|
||||||
class DefaultCmds(_EvContainer):
|
class _EvContainer(object):
|
||||||
"""
|
"""
|
||||||
This container holds direct shortcuts to all default commands in Evennia.
|
Parent for other containers
|
||||||
|
|
||||||
To access in code, do 'from evennia import default_cmds' then
|
"""
|
||||||
access the properties on the imported default_cmds object.
|
def _help(self):
|
||||||
|
"Returns list of contents"
|
||||||
"""
|
names = [name for name in self.__class__.__dict__ if not name.startswith('_')]
|
||||||
|
names += [name for name in self.__dict__ if not name.startswith('_')]
|
||||||
from commands.default.cmdset_character import CharacterCmdSet
|
print self.__doc__ + "-" * 60 + "\n" + ", ".join(names)
|
||||||
from commands.default.cmdset_player import PlayerCmdSet
|
help = property(_help)
|
||||||
from commands.default.cmdset_unloggedin import UnloggedinCmdSet
|
|
||||||
from commands.default.cmdset_session import SessionCmdSet
|
|
||||||
from commands.default.muxcommand import MuxCommand, MuxPlayerCommand
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
"populate the object with commands"
|
|
||||||
|
|
||||||
def add_cmds(module):
|
|
||||||
"helper method for populating this object with cmds"
|
|
||||||
cmdlist = utils.variable_from_module(module, module.__all__)
|
|
||||||
self.__dict__.update(dict([(c.__name__, c) for c in cmdlist]))
|
|
||||||
|
|
||||||
from commands.default import (admin, batchprocess,
|
|
||||||
building, comms, general,
|
|
||||||
player, help, system, unloggedin)
|
|
||||||
add_cmds(admin)
|
|
||||||
add_cmds(building)
|
|
||||||
add_cmds(batchprocess)
|
|
||||||
add_cmds(building)
|
|
||||||
add_cmds(comms)
|
|
||||||
add_cmds(general)
|
|
||||||
add_cmds(player)
|
|
||||||
add_cmds(help)
|
|
||||||
add_cmds(system)
|
|
||||||
add_cmds(unloggedin)
|
|
||||||
default_cmds = DefaultCmds()
|
|
||||||
del DefaultCmds
|
|
||||||
|
|
||||||
|
|
||||||
class SystemCmds(_EvContainer):
|
class DBmanagers(_EvContainer):
|
||||||
"""
|
"""
|
||||||
Creating commands with keys set to these constants will make
|
Links to instantiated database managers.
|
||||||
them system commands called as a replacement by the parser when
|
|
||||||
special situations occur. If not defined, the hard-coded
|
|
||||||
responses in the server are used.
|
|
||||||
|
|
||||||
CMD_NOINPUT - no input was given on command line
|
helpentry - HelpEntry.objects
|
||||||
CMD_NOMATCH - no valid command key was found
|
players - PlayerDB.objects
|
||||||
CMD_MULTIMATCH - multiple command matches were found
|
scripts - ScriptDB.objects
|
||||||
CMD_CHANNEL - the command name is a channel name
|
msgs - Msg.objects
|
||||||
CMD_LOGINSTART - this command will be called as the very
|
channels - Channel.objects
|
||||||
first command when a player connects to
|
objects - ObjectDB.objects
|
||||||
the server.
|
serverconfigs = ServerConfig.objects
|
||||||
|
tags - Tags.objects
|
||||||
|
attributes - Attributes.objects
|
||||||
|
|
||||||
To access in code, do 'from evennia import syscmdkeys' then
|
"""
|
||||||
access the properties on the imported syscmdkeys object.
|
from help.models import HelpEntry
|
||||||
|
from players.models import PlayerDB
|
||||||
|
from scripts.models import ScriptDB
|
||||||
|
from comms.models import Msg, ChannelDB
|
||||||
|
from objects.models import ObjectDB
|
||||||
|
from server.models import ServerConfig
|
||||||
|
from typeclasses.attributes import Attribute
|
||||||
|
from typeclasses.tags import Tag
|
||||||
|
|
||||||
"""
|
# create container's properties
|
||||||
from commands import cmdhandler
|
helpentries = HelpEntry.objects
|
||||||
CMD_NOINPUT = cmdhandler.CMD_NOINPUT
|
players = PlayerDB.objects
|
||||||
CMD_NOMATCH = cmdhandler.CMD_NOMATCH
|
scripts = ScriptDB.objects
|
||||||
CMD_MULTIMATCH = cmdhandler.CMD_MULTIMATCH
|
msgs = Msg.objects
|
||||||
CMD_CHANNEL = cmdhandler.CMD_CHANNEL
|
channels = ChannelDB.objects
|
||||||
CMD_LOGINSTART = cmdhandler.CMD_LOGINSTART
|
objects = ObjectDB.objects
|
||||||
del cmdhandler
|
serverconfigs = ServerConfig.objects
|
||||||
syscmdkeys = SystemCmds()
|
attributes = Attribute.objects
|
||||||
del SystemCmds
|
tags = Tag.objects
|
||||||
del _EvContainer
|
# remove these so they are not visible as properties
|
||||||
|
del HelpEntry, PlayerDB, ScriptDB, Msg, ChannelDB
|
||||||
|
#del ExternalChannelConnection
|
||||||
|
del ObjectDB, ServerConfig, Tag, Attribute
|
||||||
|
|
||||||
|
managers = DBmanagers()
|
||||||
|
del DBmanagers
|
||||||
|
|
||||||
|
|
||||||
|
class DefaultCmds(_EvContainer):
|
||||||
|
"""
|
||||||
|
This container holds direct shortcuts to all default commands in Evennia.
|
||||||
|
|
||||||
|
To access in code, do 'from evennia import default_cmds' then
|
||||||
|
access the properties on the imported default_cmds object.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
from commands.default.cmdset_character import CharacterCmdSet
|
||||||
|
from commands.default.cmdset_player import PlayerCmdSet
|
||||||
|
from commands.default.cmdset_unloggedin import UnloggedinCmdSet
|
||||||
|
from commands.default.cmdset_session import SessionCmdSet
|
||||||
|
from commands.default.muxcommand import MuxCommand, MuxPlayerCommand
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
"populate the object with commands"
|
||||||
|
|
||||||
|
def add_cmds(module):
|
||||||
|
"helper method for populating this object with cmds"
|
||||||
|
cmdlist = utils.variable_from_module(module, module.__all__)
|
||||||
|
self.__dict__.update(dict([(c.__name__, c) for c in cmdlist]))
|
||||||
|
|
||||||
|
from commands.default import (admin, batchprocess,
|
||||||
|
building, comms, general,
|
||||||
|
player, help, system, unloggedin)
|
||||||
|
add_cmds(admin)
|
||||||
|
add_cmds(building)
|
||||||
|
add_cmds(batchprocess)
|
||||||
|
add_cmds(building)
|
||||||
|
add_cmds(comms)
|
||||||
|
add_cmds(general)
|
||||||
|
add_cmds(player)
|
||||||
|
add_cmds(help)
|
||||||
|
add_cmds(system)
|
||||||
|
add_cmds(unloggedin)
|
||||||
|
default_cmds = DefaultCmds()
|
||||||
|
del DefaultCmds
|
||||||
|
|
||||||
|
|
||||||
|
class SystemCmds(_EvContainer):
|
||||||
|
"""
|
||||||
|
Creating commands with keys set to these constants will make
|
||||||
|
them system commands called as a replacement by the parser when
|
||||||
|
special situations occur. If not defined, the hard-coded
|
||||||
|
responses in the server are used.
|
||||||
|
|
||||||
|
CMD_NOINPUT - no input was given on command line
|
||||||
|
CMD_NOMATCH - no valid command key was found
|
||||||
|
CMD_MULTIMATCH - multiple command matches were found
|
||||||
|
CMD_CHANNEL - the command name is a channel name
|
||||||
|
CMD_LOGINSTART - this command will be called as the very
|
||||||
|
first command when a player connects to
|
||||||
|
the server.
|
||||||
|
|
||||||
|
To access in code, do 'from evennia import syscmdkeys' then
|
||||||
|
access the properties on the imported syscmdkeys object.
|
||||||
|
|
||||||
|
"""
|
||||||
|
from commands import cmdhandler
|
||||||
|
CMD_NOINPUT = cmdhandler.CMD_NOINPUT
|
||||||
|
CMD_NOMATCH = cmdhandler.CMD_NOMATCH
|
||||||
|
CMD_MULTIMATCH = cmdhandler.CMD_MULTIMATCH
|
||||||
|
CMD_CHANNEL = cmdhandler.CMD_CHANNEL
|
||||||
|
CMD_LOGINSTART = cmdhandler.CMD_LOGINSTART
|
||||||
|
del cmdhandler
|
||||||
|
syscmdkeys = SystemCmds()
|
||||||
|
del SystemCmds
|
||||||
|
del _EvContainer
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -274,26 +274,26 @@ SERVER_SESSION_CLASS = "evennia.server.serversession.ServerSession"
|
||||||
# Base paths for typeclassed object classes. These paths must be
|
# Base paths for typeclassed object classes. These paths must be
|
||||||
# defined relative evennia's root directory. They will be searched in
|
# defined relative evennia's root directory. They will be searched in
|
||||||
# order to find relative typeclass paths.
|
# order to find relative typeclass paths.
|
||||||
OBJECT_TYPECLASS_PATHS = ["types", "contrib"]
|
OBJECT_TYPECLASS_PATHS = ["typeclasses", "contrib"]
|
||||||
SCRIPT_TYPECLASS_PATHS = ["types" "contrib"]
|
SCRIPT_TYPECLASS_PATHS = ["typeclasses" "contrib"]
|
||||||
PLAYER_TYPECLASS_PATHS = ["types", "contrib"]
|
PLAYER_TYPECLASS_PATHS = ["typeclasses", "contrib"]
|
||||||
CHANNEL_TYPECLASS_PATHS = ["types", "contrib"]
|
CHANNEL_TYPECLASS_PATHS = ["typeclasses", "contrib"]
|
||||||
|
|
||||||
# Typeclass for player objects (linked to a character) (fallback)
|
# Typeclass for player objects (linked to a character) (fallback)
|
||||||
BASE_PLAYER_TYPECLASS = "types.player.Player"
|
BASE_PLAYER_TYPECLASS = "typeclasses.player.Player"
|
||||||
# Typeclass and base for all objects (fallback)
|
# Typeclass and base for all objects (fallback)
|
||||||
BASE_OBJECT_TYPECLASS = "types.object.Object"
|
BASE_OBJECT_TYPECLASS = "typeclasses.object.Object"
|
||||||
# Typeclass for character objects linked to a player (fallback)
|
# Typeclass for character objects linked to a player (fallback)
|
||||||
BASE_CHARACTER_TYPECLASS = "types.character.Character"
|
BASE_CHARACTER_TYPECLASS = "typeclasses.character.Character"
|
||||||
# Typeclass for rooms (fallback)
|
# Typeclass for rooms (fallback)
|
||||||
BASE_ROOM_TYPECLASS = "types.room.Room"
|
BASE_ROOM_TYPECLASS = "typeclasses.room.Room"
|
||||||
# Typeclass for Exit objects (fallback).
|
# Typeclass for Exit objects (fallback).
|
||||||
BASE_EXIT_TYPECLASS = "types.exit.Exit"
|
BASE_EXIT_TYPECLASS = "typeclasses.exit.Exit"
|
||||||
# Typeclass for Channel (fallback).
|
# Typeclass for Channel (fallback).
|
||||||
BASE_CHANNEL_TYPECLASS = "type.channel.Channel"
|
BASE_CHANNEL_TYPECLASS = "typeclasses.channel.Channel"
|
||||||
# Typeclass for Scripts (fallback). You usually don't need to change this
|
# Typeclass for Scripts (fallback). You usually don't need to change this
|
||||||
# but create custom variations of scripts on a per-case basis instead.
|
# but create custom variations of scripts on a per-case basis instead.
|
||||||
BASE_SCRIPT_TYPECLASS = "type.scripts.Script"
|
BASE_SCRIPT_TYPECLASS = "typeclasses.scripts.Script"
|
||||||
# The default home location used for all objects. This is used as a
|
# The default home location used for all objects. This is used as a
|
||||||
# fallback if an object's normal home location is deleted. Default
|
# fallback if an object's normal home location is deleted. Default
|
||||||
# is Limbo (#2).
|
# is Limbo (#2).
|
||||||
|
|
@ -399,7 +399,7 @@ CLIENT_DEFAULT_HEIGHT = 45 # telnet standard is 24 but does anyone use such
|
||||||
# This enables guest logins, by default via "connect guest"
|
# This enables guest logins, by default via "connect guest"
|
||||||
GUEST_ENABLED = False
|
GUEST_ENABLED = False
|
||||||
# Typeclass for guest player objects (linked to a character)
|
# Typeclass for guest player objects (linked to a character)
|
||||||
BASE_GUEST_TYPECLASS = "types.player.Guest"
|
BASE_GUEST_TYPECLASS = "typeclasses.player.Guest"
|
||||||
# The permission given to guests
|
# The permission given to guests
|
||||||
PERMISSION_GUEST_DEFAULT = "Guests"
|
PERMISSION_GUEST_DEFAULT = "Guests"
|
||||||
# The default home location used for guests.
|
# The default home location used for guests.
|
||||||
|
|
|
||||||
|
|
@ -308,7 +308,7 @@ def get_evennia_version():
|
||||||
Check for the evennia version info.
|
Check for the evennia version info.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
f = open(settings.BASE_PATH + os.sep + "VERSION.txt", 'r')
|
f = open(settings.ROOT_DIR + os.sep + "VERSION.txt", 'r')
|
||||||
return "%s-%s" % (f.read().strip(), os.popen("git rev-parse --short HEAD").read().strip())
|
return "%s-%s" % (f.read().strip(), os.popen("git rev-parse --short HEAD").read().strip())
|
||||||
except IOError:
|
except IOError:
|
||||||
return "Unknown version"
|
return "Unknown version"
|
||||||
|
|
@ -317,7 +317,7 @@ def get_evennia_version():
|
||||||
def pypath_to_realpath(python_path, file_ending='.py'):
|
def pypath_to_realpath(python_path, file_ending='.py'):
|
||||||
"""
|
"""
|
||||||
Converts a path on dot python form (e.g. 'evennia.objects.models') to
|
Converts a path on dot python form (e.g. 'evennia.objects.models') to
|
||||||
a system path ($BASE_PATH/evennia/objects/models.py). Calculates all
|
a system path ($ROOT_DIR/evennia/objects/models.py). Calculates all
|
||||||
paths as absoulte paths starting from the evennia main directory.
|
paths as absoulte paths starting from the evennia main directory.
|
||||||
|
|
||||||
Since it seems to be a common mistake to include the file ending
|
Since it seems to be a common mistake to include the file ending
|
||||||
|
|
@ -330,7 +330,7 @@ def pypath_to_realpath(python_path, file_ending='.py'):
|
||||||
pathsplit = pathsplit[:-1]
|
pathsplit = pathsplit[:-1]
|
||||||
if not pathsplit:
|
if not pathsplit:
|
||||||
return python_path
|
return python_path
|
||||||
path = settings.BASE_PATH
|
path = settings.ROOT_DIR
|
||||||
for directory in pathsplit:
|
for directory in pathsplit:
|
||||||
path = os.path.join(path, directory)
|
path = os.path.join(path, directory)
|
||||||
if file_ending:
|
if file_ending:
|
||||||
|
|
|
||||||
91
game_template/commands/default_cmdsets.py
Normal file
|
|
@ -0,0 +1,91 @@
|
||||||
|
"""
|
||||||
|
Command sets
|
||||||
|
|
||||||
|
All commands in the game must be grouped in a cmdset. A given command
|
||||||
|
can be part of any number of cmdsets and cmdsets can be added/removed
|
||||||
|
and merged onto entities at runtime.
|
||||||
|
|
||||||
|
To create new commands to populate the cmdset, see
|
||||||
|
commands/command.py.
|
||||||
|
|
||||||
|
This module wrap the default command sets of Evennia; overload them
|
||||||
|
to add/remove commands from the default lineup. You can create your
|
||||||
|
own cmdsets by inheriting from them or directly from evennia.CmdSet.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
from evennia import default_cmds
|
||||||
|
|
||||||
|
class CharacterCmdSet(default_cmds.CharacterCmdSet):
|
||||||
|
"""
|
||||||
|
The CharacterCmdSet contains general in-game commands like look,
|
||||||
|
get etc available on in-game Character objects. It is merged with
|
||||||
|
the PlayerCmdSet when a Player puppets a Character.
|
||||||
|
"""
|
||||||
|
key = "DefaultCharacter"
|
||||||
|
|
||||||
|
def at_cmdset_creation(self):
|
||||||
|
"""
|
||||||
|
Populates the cmdset
|
||||||
|
"""
|
||||||
|
super(CharacterCmdSet, self).at_cmdset_creation()
|
||||||
|
#
|
||||||
|
# any commands you add below will overload the default ones.
|
||||||
|
#
|
||||||
|
|
||||||
|
|
||||||
|
class PlayerCmdSet(default_cmds.PlayerCmdSet):
|
||||||
|
"""
|
||||||
|
This is the cmdset available to the Player at all times. It is
|
||||||
|
combined with the CharacterCmdSet when the Player puppets a
|
||||||
|
Character. It holds game-account-specific commands, channel
|
||||||
|
commands etc.
|
||||||
|
"""
|
||||||
|
key = "DefaultPlayer"
|
||||||
|
|
||||||
|
def at_cmdset_creation(self):
|
||||||
|
"""
|
||||||
|
Populates the cmdset
|
||||||
|
"""
|
||||||
|
super(PlayerCmdSet, self).at_cmdset_creation()
|
||||||
|
#
|
||||||
|
# any commands you add below will overload the default ones.
|
||||||
|
#
|
||||||
|
|
||||||
|
|
||||||
|
class UnloggedinCmdSet(default_cmds.UnloggedinCmdSet):
|
||||||
|
"""
|
||||||
|
Command set available to the Session before being logged in. This
|
||||||
|
holds commands like creating a new account, logging in etc.
|
||||||
|
"""
|
||||||
|
key = "DefaultUnloggedin"
|
||||||
|
|
||||||
|
def at_cmdset_creation(self):
|
||||||
|
"""
|
||||||
|
Populates the cmdset
|
||||||
|
"""
|
||||||
|
super(UnloggedinCmdSet, self).at_cmdset_creation()
|
||||||
|
#
|
||||||
|
# any commands you add below will overload the default ones.
|
||||||
|
#
|
||||||
|
|
||||||
|
|
||||||
|
class SessionCmdSet(default_cmds.SessionCmdSet):
|
||||||
|
"""
|
||||||
|
This cmdset is made available on Session level once logged in. It
|
||||||
|
is empty by default.
|
||||||
|
"""
|
||||||
|
key = "DefaultSession"
|
||||||
|
|
||||||
|
def at_cmdset_creation(self):
|
||||||
|
"""
|
||||||
|
This is the only method defined in a cmdset, called during
|
||||||
|
its creation. It should populate the set with command instances.
|
||||||
|
|
||||||
|
As and example we just add the empty base Command object.
|
||||||
|
It prints some info.
|
||||||
|
"""
|
||||||
|
super(SessionCmdSet, self).at_cmdset_creation()
|
||||||
|
#
|
||||||
|
# any commands you add below will overload the default ones.
|
||||||
|
#
|
||||||
42
game_template/server/conf/inlinefunc.py
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
"""
|
||||||
|
Inlinefunc
|
||||||
|
|
||||||
|
Inline functions allow for direct conversion of text users mark in a
|
||||||
|
special way. Inlinefuncs are deactivated by default. To activate, add
|
||||||
|
|
||||||
|
INLINEFUNC_ENABLED = True
|
||||||
|
|
||||||
|
to your settings file. The default inlinefuncs are found in
|
||||||
|
evennia.utils.inlinefunc.
|
||||||
|
|
||||||
|
In text, usage is straightforward:
|
||||||
|
|
||||||
|
{funcname([arg1,arg2,...]) text {/funcname
|
||||||
|
|
||||||
|
Example 1 (using the "pad" inlinefunc):
|
||||||
|
"This is {pad(50,c,-) a center-padded text{/pad of width 50."
|
||||||
|
->
|
||||||
|
"This is -------------- a center-padded text--------------- of width 50."
|
||||||
|
|
||||||
|
Example 2 (using "pad" and "time" inlinefuncs):
|
||||||
|
"The time is {pad(30){time(){/time{/padright now."
|
||||||
|
->
|
||||||
|
"The time is Oct 25, 11:09 right now."
|
||||||
|
|
||||||
|
To add more inline functions, add them to this module, using
|
||||||
|
the following call signature:
|
||||||
|
|
||||||
|
def funcname(text, *args)
|
||||||
|
|
||||||
|
where the text is always the part between {funcname(args) and
|
||||||
|
{/funcname and the *args are taken from the appropriate part of the
|
||||||
|
call. It is important that the inline function properly clean the
|
||||||
|
incoming args, checking their type and replacing them with sane
|
||||||
|
defaults if needed. If impossible to resolve, the unmodified text
|
||||||
|
should be returned. The inlinefunc should never cause a traceback.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
#def capitalize(text, *args):
|
||||||
|
# "Silly capitalize example"
|
||||||
|
# return text.capitalize()
|
||||||
92
game_template/server/conf/settings.py
Normal file
|
|
@ -0,0 +1,92 @@
|
||||||
|
"""
|
||||||
|
Evennia settings file.
|
||||||
|
|
||||||
|
The full options are found in the default settings file found here:
|
||||||
|
|
||||||
|
{settings_default}
|
||||||
|
|
||||||
|
Note: Don't copy more from the default file than you actually intend to
|
||||||
|
change; this will make sure that you don't overload upstream updates
|
||||||
|
unnecessarily.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Use the defaults from Evennia unless explicitly overridden
|
||||||
|
import os
|
||||||
|
from evennia.settings_default import *
|
||||||
|
|
||||||
|
######################################################################
|
||||||
|
# Evennia base server config
|
||||||
|
######################################################################
|
||||||
|
|
||||||
|
# This is the name of your game. Make it catchy!
|
||||||
|
SERVERNAME = {servername}
|
||||||
|
|
||||||
|
# Path to the game directory (use EVENNIA_DIR to refer to the
|
||||||
|
# core evennia library)
|
||||||
|
GAME_DIR = {game_dir}
|
||||||
|
|
||||||
|
# Place to put log files
|
||||||
|
LOG_DIR = os.path.join(GAME_DIR, "server", "logs")
|
||||||
|
SERVER_LOG_FILE = os.path.join(LOG_DIR, 'server.log')
|
||||||
|
PORTAL_LOG_FILE = os.path.join(LOG_DIR, 'portal.log')
|
||||||
|
HTTP_LOG_FILE = os.path.join(LOG_DIR, 'http_requests.log')
|
||||||
|
|
||||||
|
######################################################################
|
||||||
|
# Evennia Database config
|
||||||
|
######################################################################
|
||||||
|
|
||||||
|
# Database config syntax:
|
||||||
|
# ENGINE - path to the the database backend. Possible choices are:
|
||||||
|
# 'django.db.backends.sqlite3', (default)
|
||||||
|
# 'django.db.backends.mysql',
|
||||||
|
# 'django.db.backends.'postgresql_psycopg2' (see Issue 241),
|
||||||
|
# 'django.db.backends.oracle' (untested).
|
||||||
|
# NAME - database name, or path to the db file for sqlite3
|
||||||
|
# USER - db admin (unused in sqlite3)
|
||||||
|
# PASSWORD - db admin password (unused in sqlite3)
|
||||||
|
# HOST - empty string is localhost (unused in sqlite3)
|
||||||
|
# PORT - empty string defaults to localhost (unused in sqlite3)
|
||||||
|
DATABASES = {{
|
||||||
|
'default': {{
|
||||||
|
'ENGINE': 'django.db.backends.sqlite3',
|
||||||
|
'NAME': os.path.join(GAME_DIR, "server", "evennia.db3"),
|
||||||
|
'USER': '',
|
||||||
|
'PASSWORD': '',
|
||||||
|
'HOST': '',
|
||||||
|
'PORT': ''
|
||||||
|
}}}}
|
||||||
|
|
||||||
|
######################################################################
|
||||||
|
# Django web features
|
||||||
|
######################################################################
|
||||||
|
|
||||||
|
# Absolute path to the directory that holds file uploads from web apps.
|
||||||
|
# Example: "/home/media/media.lawrence.com"
|
||||||
|
MEDIA_ROOT = os.path.join(GAME_DIR, "gamesrc", "web", "media")
|
||||||
|
|
||||||
|
# The master urlconf file that contains all of the sub-branches to the
|
||||||
|
# applications. Change this to add your own URLs to the website.
|
||||||
|
ROOT_URLCONF = 'web.urls'
|
||||||
|
|
||||||
|
# URL prefix for admin media -- CSS, JavaScript and images. Make sure
|
||||||
|
# to use a trailing slash. Django1.4+ will look for admin files under
|
||||||
|
# STATIC_URL/admin.
|
||||||
|
STATIC_URL = '/static/'
|
||||||
|
STATIC_ROOT = os.path.join(GAME_DIR, "web", "static")
|
||||||
|
|
||||||
|
# Directories from which static files will be gathered from.
|
||||||
|
STATICFILES_DIRS = (
|
||||||
|
os.path.join(GAME_DIR, "web", "static_overrides"),
|
||||||
|
os.path.join(EVENNIA_DIR, "web", "static"),)
|
||||||
|
|
||||||
|
# We setup the location of the website template as well as the admin site.
|
||||||
|
TEMPLATE_DIRS = (
|
||||||
|
os.path.join(GAME_DIR, "web", "template_overrides"),
|
||||||
|
os.path.join(EVENNIA_DIR, "web", "templates", ACTIVE_TEMPLATE),
|
||||||
|
os.path.join(EVENNIA_DIR, "web", "templates"),)
|
||||||
|
|
||||||
|
# The secret key is randomly seeded upon creation. It is used to
|
||||||
|
# salt cryptographic keys. Don't change this once you have created users
|
||||||
|
# and don't share it with anyone.
|
||||||
|
SECRET_KEY = {secret_key}
|
||||||
|
Before Width: | Height: | Size: 50 B After Width: | Height: | Size: 50 B |
|
Before Width: | Height: | Size: 75 B After Width: | Height: | Size: 75 B |
|
Before Width: | Height: | Size: 199 B After Width: | Height: | Size: 199 B |
|
Before Width: | Height: | Size: 212 B After Width: | Height: | Size: 212 B |
|
Before Width: | Height: | Size: 835 B After Width: | Height: | Size: 835 B |
|
Before Width: | Height: | Size: 836 B After Width: | Height: | Size: 836 B |
|
Before Width: | Height: | Size: 45 B After Width: | Height: | Size: 45 B |
|
Before Width: | Height: | Size: 711 B After Width: | Height: | Size: 711 B |
|
Before Width: | Height: | Size: 506 B After Width: | Height: | Size: 506 B |
|
Before Width: | Height: | Size: 176 B After Width: | Height: | Size: 176 B |
|
Before Width: | Height: | Size: 130 B After Width: | Height: | Size: 130 B |
|
Before Width: | Height: | Size: 299 B After Width: | Height: | Size: 299 B |
|
Before Width: | Height: | Size: 119 B After Width: | Height: | Size: 119 B |
|
Before Width: | Height: | Size: 145 B After Width: | Height: | Size: 145 B |
|
Before Width: | Height: | Size: 192 B After Width: | Height: | Size: 192 B |
|
Before Width: | Height: | Size: 119 B After Width: | Height: | Size: 119 B |
|
Before Width: | Height: | Size: 390 B After Width: | Height: | Size: 390 B |
|
Before Width: | Height: | Size: 181 B After Width: | Height: | Size: 181 B |
|
Before Width: | Height: | Size: 319 B After Width: | Height: | Size: 319 B |
|
Before Width: | Height: | Size: 368 B After Width: | Height: | Size: 368 B |
|
Before Width: | Height: | Size: 341 B After Width: | Height: | Size: 341 B |
|
Before Width: | Height: | Size: 395 B After Width: | Height: | Size: 395 B |
|
Before Width: | Height: | Size: 707 B After Width: | Height: | Size: 707 B |
|
Before Width: | Height: | Size: 363 B After Width: | Height: | Size: 363 B |
|
Before Width: | Height: | Size: 557 B After Width: | Height: | Size: 557 B |
|
Before Width: | Height: | Size: 94 B After Width: | Height: | Size: 94 B |
|
Before Width: | Height: | Size: 116 B After Width: | Height: | Size: 116 B |
|
Before Width: | Height: | Size: 178 B After Width: | Height: | Size: 178 B |
|
Before Width: | Height: | Size: 265 B After Width: | Height: | Size: 265 B |
|
Before Width: | Height: | Size: 265 B After Width: | Height: | Size: 265 B |
|
Before Width: | Height: | Size: 2.7 KiB After Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 552 B After Width: | Height: | Size: 552 B |
|
Before Width: | Height: | Size: 369 B After Width: | Height: | Size: 369 B |
|
Before Width: | Height: | Size: 197 B After Width: | Height: | Size: 197 B |
|
Before Width: | Height: | Size: 203 B After Width: | Height: | Size: 203 B |
|
Before Width: | Height: | Size: 198 B After Width: | Height: | Size: 198 B |
|
Before Width: | Height: | Size: 200 B After Width: | Height: | Size: 200 B |
|
Before Width: | Height: | Size: 932 B After Width: | Height: | Size: 932 B |
|
Before Width: | Height: | Size: 119 B After Width: | Height: | Size: 119 B |
|
Before Width: | Height: | Size: 336 B After Width: | Height: | Size: 336 B |
|
Before Width: | Height: | Size: 351 B After Width: | Height: | Size: 351 B |
|
Before Width: | Height: | Size: 200 B After Width: | Height: | Size: 200 B |
|
Before Width: | Height: | Size: 354 B After Width: | Height: | Size: 354 B |
|
Before Width: | Height: | Size: 678 KiB After Width: | Height: | Size: 678 KiB |
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
|
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.4 KiB |