From 24961db152099a050486be79f053d90e2fc3f2c7 Mon Sep 17 00:00:00 2001 From: jodhus Date: Wed, 19 Jun 2024 21:00:38 -0400 Subject: [PATCH] Initial commit, again --- .gitignore | 2 + cwopamud/.gitignore | 56 ++++++ cwopamud/README.md | 40 ++++ cwopamud/commands/README.md | 14 ++ cwopamud/commands/__init__.py | 0 cwopamud/commands/command.py | 187 ++++++++++++++++++ cwopamud/commands/default_cmdsets.py | 96 +++++++++ cwopamud/server/README.md | 38 ++++ cwopamud/server/__init__.py | 1 + cwopamud/server/conf/__init__.py | 1 + cwopamud/server/conf/at_initial_setup.py | 19 ++ cwopamud/server/conf/at_search.py | 54 +++++ cwopamud/server/conf/at_server_startstop.py | 71 +++++++ cwopamud/server/conf/cmdparser.py | 55 ++++++ cwopamud/server/conf/connection_screens.py | 40 ++++ cwopamud/server/conf/inlinefuncs.py | 39 ++++ cwopamud/server/conf/inputfuncs.py | 52 +++++ cwopamud/server/conf/lockfuncs.py | 30 +++ cwopamud/server/conf/mssp.py | 105 ++++++++++ .../server/conf/portal_services_plugins.py | 24 +++ .../server/conf/server_services_plugins.py | 24 +++ cwopamud/server/conf/serversession.py | 37 ++++ cwopamud/server/conf/settings.py | 44 +++++ cwopamud/server/conf/web_plugins.py | 41 ++++ cwopamud/server/logs/README.md | 15 ++ cwopamud/typeclasses/README.md | 16 ++ cwopamud/typeclasses/__init__.py | 0 cwopamud/typeclasses/accounts.py | 104 ++++++++++ cwopamud/typeclasses/channels.py | 62 ++++++ cwopamud/typeclasses/characters.py | 37 ++++ cwopamud/typeclasses/exits.py | 41 ++++ cwopamud/typeclasses/objects.py | 175 ++++++++++++++++ cwopamud/typeclasses/rooms.py | 24 +++ cwopamud/typeclasses/scripts.py | 92 +++++++++ cwopamud/web/README.md | 51 +++++ cwopamud/web/__init__.py | 0 cwopamud/web/admin/README.md | 5 + cwopamud/web/admin/__init__.py | 0 cwopamud/web/admin/urls.py | 20 ++ cwopamud/web/api/__init__.py | 0 cwopamud/web/static/README.md | 17 ++ .../web/static/rest_framework/css/README.md | 3 + .../static/rest_framework/images/README.md | 3 + cwopamud/web/static/webclient/css/README.md | 3 + cwopamud/web/static/webclient/js/README.md | 3 + cwopamud/web/static/website/css/README.md | 3 + cwopamud/web/static/website/images/README.md | 3 + cwopamud/web/templates/README.md | 14 ++ .../web/templates/rest_framework/README.md | 3 + cwopamud/web/templates/webclient/README.md | 4 + cwopamud/web/templates/website/README.md | 5 + .../web/templates/website/flatpages/README.md | 3 + .../templates/website/registration/README.md | 3 + cwopamud/web/urls.py | 34 ++++ cwopamud/web/webclient/README.md | 23 +++ cwopamud/web/webclient/__init__.py | 0 cwopamud/web/webclient/urls.py | 20 ++ cwopamud/web/website/README.md | 24 +++ cwopamud/web/website/__init__.py | 0 cwopamud/web/website/urls.py | 20 ++ cwopamud/web/website/views/__init__.py | 0 cwopamud/world/README.md | 10 + cwopamud/world/__init__.py | 0 cwopamud/world/batch_cmds.ev | 26 +++ cwopamud/world/help_entries.py | 58 ++++++ cwopamud/world/prototypes.py | 90 +++++++++ 66 files changed, 2084 insertions(+) create mode 100644 .gitignore create mode 100644 cwopamud/.gitignore create mode 100644 cwopamud/README.md create mode 100644 cwopamud/commands/README.md create mode 100644 cwopamud/commands/__init__.py create mode 100644 cwopamud/commands/command.py create mode 100644 cwopamud/commands/default_cmdsets.py create mode 100644 cwopamud/server/README.md create mode 100644 cwopamud/server/__init__.py create mode 100644 cwopamud/server/conf/__init__.py create mode 100644 cwopamud/server/conf/at_initial_setup.py create mode 100644 cwopamud/server/conf/at_search.py create mode 100644 cwopamud/server/conf/at_server_startstop.py create mode 100644 cwopamud/server/conf/cmdparser.py create mode 100644 cwopamud/server/conf/connection_screens.py create mode 100644 cwopamud/server/conf/inlinefuncs.py create mode 100644 cwopamud/server/conf/inputfuncs.py create mode 100644 cwopamud/server/conf/lockfuncs.py create mode 100644 cwopamud/server/conf/mssp.py create mode 100644 cwopamud/server/conf/portal_services_plugins.py create mode 100644 cwopamud/server/conf/server_services_plugins.py create mode 100644 cwopamud/server/conf/serversession.py create mode 100644 cwopamud/server/conf/settings.py create mode 100644 cwopamud/server/conf/web_plugins.py create mode 100644 cwopamud/server/logs/README.md create mode 100644 cwopamud/typeclasses/README.md create mode 100644 cwopamud/typeclasses/__init__.py create mode 100644 cwopamud/typeclasses/accounts.py create mode 100644 cwopamud/typeclasses/channels.py create mode 100644 cwopamud/typeclasses/characters.py create mode 100644 cwopamud/typeclasses/exits.py create mode 100644 cwopamud/typeclasses/objects.py create mode 100644 cwopamud/typeclasses/rooms.py create mode 100644 cwopamud/typeclasses/scripts.py create mode 100644 cwopamud/web/README.md create mode 100644 cwopamud/web/__init__.py create mode 100644 cwopamud/web/admin/README.md create mode 100644 cwopamud/web/admin/__init__.py create mode 100644 cwopamud/web/admin/urls.py create mode 100644 cwopamud/web/api/__init__.py create mode 100644 cwopamud/web/static/README.md create mode 100644 cwopamud/web/static/rest_framework/css/README.md create mode 100644 cwopamud/web/static/rest_framework/images/README.md create mode 100644 cwopamud/web/static/webclient/css/README.md create mode 100644 cwopamud/web/static/webclient/js/README.md create mode 100644 cwopamud/web/static/website/css/README.md create mode 100644 cwopamud/web/static/website/images/README.md create mode 100644 cwopamud/web/templates/README.md create mode 100644 cwopamud/web/templates/rest_framework/README.md create mode 100644 cwopamud/web/templates/webclient/README.md create mode 100644 cwopamud/web/templates/website/README.md create mode 100644 cwopamud/web/templates/website/flatpages/README.md create mode 100644 cwopamud/web/templates/website/registration/README.md create mode 100644 cwopamud/web/urls.py create mode 100644 cwopamud/web/webclient/README.md create mode 100644 cwopamud/web/webclient/__init__.py create mode 100644 cwopamud/web/webclient/urls.py create mode 100644 cwopamud/web/website/README.md create mode 100644 cwopamud/web/website/__init__.py create mode 100644 cwopamud/web/website/urls.py create mode 100644 cwopamud/web/website/views/__init__.py create mode 100644 cwopamud/world/README.md create mode 100644 cwopamud/world/__init__.py create mode 100644 cwopamud/world/batch_cmds.ev create mode 100644 cwopamud/world/help_entries.py create mode 100644 cwopamud/world/prototypes.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..35008af --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.python-version +.venv/ diff --git a/cwopamud/.gitignore b/cwopamud/.gitignore new file mode 100644 index 0000000..add8d97 --- /dev/null +++ b/cwopamud/.gitignore @@ -0,0 +1,56 @@ +*.py[cod] + +# C extensions +*.so + +# Packages +*.egg +*.egg-info +dist +build +eggs +parts +var +sdist +develop-eggs +.installed.cfg +lib +lib64 +__pycache__ + +# Other +*.swp +*.log +*.log.* +*.pid +*.restart +*.db3 + +# Installation-specific. +# For group efforts, comment out some or all of these. +server/conf/secret_settings.py +server/logs/*.log.* +server/.static/* +server/.media/* + +# Installer logs +pip-log.txt + +# Unit test / coverage reports +.coverage +.tox +nosetests.xml + +# Translations +*.mo + +# Mr Developer +.mr.developer.cfg +.project +.pydevproject + +# PyCharm config +.idea + +# VSCode config +.vscode diff --git a/cwopamud/README.md b/cwopamud/README.md new file mode 100644 index 0000000..fe62bd3 --- /dev/null +++ b/cwopamud/README.md @@ -0,0 +1,40 @@ +# Welcome to Evennia! + +This is your game directory, set up to let you start with +your new game right away. An overview of this directory is found here: +https://github.com/evennia/evennia/wiki/Directory-Overview#the-game-directory + +You can delete this readme file when you've read it and you can +re-arrange things in this game-directory to suit your own sense of +organisation (the only exception is the directory structure of the +`server/` directory, which Evennia expects). If you change the structure +you must however also edit/add to your settings file to tell Evennia +where to look for things. + +Your game's main configuration file is found in +`server/conf/settings.py` (but you don't need to change it to get +started). If you just created this directory (which means you'll already +have a `virtualenv` running if you followed the default instructions), +`cd` to this directory then initialize a new database using + + evennia migrate + +To start the server, stand in this directory and run + + evennia start + +This will start the server, logging output to the console. Make +sure to create a superuser when asked. By default you can now connect +to your new game using a MUD client on `localhost`, port `4000`. You can +also log into the web client by pointing a browser to +`http://localhost:4001`. + +# Getting started + +From here on you might want to look at one of the beginner tutorials: +http://github.com/evennia/evennia/wiki/Tutorials. + +Evennia's documentation is here: +https://github.com/evennia/evennia/wiki. + +Enjoy! diff --git a/cwopamud/commands/README.md b/cwopamud/commands/README.md new file mode 100644 index 0000000..0425ce6 --- /dev/null +++ b/cwopamud/commands/README.md @@ -0,0 +1,14 @@ +# commands/ + +This folder holds modules for implementing one's own commands and +command sets. All the modules' classes are essentially empty and just +imports the default implementations from Evennia; so adding anything +to them will start overloading the defaults. + +You can change the organisation of this directory as you see fit, just +remember that if you change any of the default command set classes' +locations, you need to add the appropriate paths to +`server/conf/settings.py` so that Evennia knows where to find them. +Also remember that if you create new sub directories you must put +(optionally empty) `__init__.py` files in there so that Python can +find your modules. diff --git a/cwopamud/commands/__init__.py b/cwopamud/commands/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/cwopamud/commands/command.py b/cwopamud/commands/command.py new file mode 100644 index 0000000..f7b4c15 --- /dev/null +++ b/cwopamud/commands/command.py @@ -0,0 +1,187 @@ +""" +Commands + +Commands describe the input the account can do to the game. + +""" + +from evennia.commands.command import Command as BaseCommand + +# from evennia import default_cmds + + +class Command(BaseCommand): + """ + Base command (you may see this if a child command had no help text defined) + + Note that the class's `__doc__` string is used by Evennia to create the + automatic help entry for the command, so make sure to document consistently + here. Without setting one, the parent's docstring will show (like now). + + """ + + # Each Command class implements the following methods, called in this order + # (only func() is actually required): + # + # - at_pre_cmd(): If this returns anything truthy, execution is aborted. + # - parse(): Should perform any extra parsing needed on self.args + # and store the result on self. + # - func(): Performs the actual work. + # - at_post_cmd(): Extra actions, often things done after + # every command, like prompts. + # + pass + + +# ------------------------------------------------------------- +# +# The default commands inherit from +# +# evennia.commands.default.muxcommand.MuxCommand. +# +# If you want to make sweeping changes to default commands you can +# uncomment this copy of the MuxCommand parent and add +# +# COMMAND_DEFAULT_CLASS = "commands.command.MuxCommand" +# +# to your settings file. Be warned that the default commands expect +# the functionality implemented in the parse() method, so be +# careful with what you change. +# +# ------------------------------------------------------------- + +# from evennia.utils import utils +# +# +# class MuxCommand(Command): +# """ +# This sets up the basis for a MUX command. The idea +# is that most other Mux-related commands should just +# inherit from this and don't have to implement much +# parsing of their own unless they do something particularly +# advanced. +# +# Note that the class's __doc__ string (this text) is +# used by Evennia to create the automatic help entry for +# the command, so make sure to document consistently here. +# """ +# def has_perm(self, srcobj): +# """ +# This is called by the cmdhandler to determine +# if srcobj is allowed to execute this command. +# We just show it here for completeness - we +# are satisfied using the default check in Command. +# """ +# return super().has_perm(srcobj) +# +# def at_pre_cmd(self): +# """ +# This hook is called before self.parse() on all commands +# """ +# pass +# +# def at_post_cmd(self): +# """ +# This hook is called after the command has finished executing +# (after self.func()). +# """ +# pass +# +# def parse(self): +# """ +# This method is called by the cmdhandler once the command name +# has been identified. It creates a new set of member variables +# that can be later accessed from self.func() (see below) +# +# The following variables are available for our use when entering this +# method (from the command definition, and assigned on the fly by the +# cmdhandler): +# self.key - the name of this command ('look') +# self.aliases - the aliases of this cmd ('l') +# self.permissions - permission string for this command +# self.help_category - overall category of command +# +# self.caller - the object calling this command +# self.cmdstring - the actual command name used to call this +# (this allows you to know which alias was used, +# for example) +# self.args - the raw input; everything following self.cmdstring. +# self.cmdset - the cmdset from which this command was picked. Not +# often used (useful for commands like 'help' or to +# list all available commands etc) +# self.obj - the object on which this command was defined. It is often +# the same as self.caller. +# +# A MUX command has the following possible syntax: +# +# name[ with several words][/switch[/switch..]] arg1[,arg2,...] [[=|,] arg[,..]] +# +# The 'name[ with several words]' part is already dealt with by the +# cmdhandler at this point, and stored in self.cmdname (we don't use +# it here). The rest of the command is stored in self.args, which can +# start with the switch indicator /. +# +# This parser breaks self.args into its constituents and stores them in the +# following variables: +# self.switches = [list of /switches (without the /)] +# self.raw = This is the raw argument input, including switches +# self.args = This is re-defined to be everything *except* the switches +# self.lhs = Everything to the left of = (lhs:'left-hand side'). If +# no = is found, this is identical to self.args. +# self.rhs: Everything to the right of = (rhs:'right-hand side'). +# If no '=' is found, this is None. +# self.lhslist - [self.lhs split into a list by comma] +# self.rhslist - [list of self.rhs split into a list by comma] +# self.arglist = [list of space-separated args (stripped, including '=' if it exists)] +# +# All args and list members are stripped of excess whitespace around the +# strings, but case is preserved. +# """ +# raw = self.args +# args = raw.strip() +# +# # split out switches +# switches = [] +# if args and len(args) > 1 and args[0] == "/": +# # we have a switch, or a set of switches. These end with a space. +# switches = args[1:].split(None, 1) +# if len(switches) > 1: +# switches, args = switches +# switches = switches.split('/') +# else: +# args = "" +# switches = switches[0].split('/') +# arglist = [arg.strip() for arg in args.split()] +# +# # check for arg1, arg2, ... = argA, argB, ... constructs +# lhs, rhs = args, None +# lhslist, rhslist = [arg.strip() for arg in args.split(',')], [] +# if args and '=' in args: +# lhs, rhs = [arg.strip() for arg in args.split('=', 1)] +# lhslist = [arg.strip() for arg in lhs.split(',')] +# rhslist = [arg.strip() for arg in rhs.split(',')] +# +# # save to object properties: +# self.raw = raw +# self.switches = switches +# self.args = args.strip() +# self.arglist = arglist +# self.lhs = lhs +# self.lhslist = lhslist +# self.rhs = rhs +# self.rhslist = rhslist +# +# # if the class has the account_caller property set on itself, we make +# # sure that self.caller is always the account if possible. We also create +# # a special property "character" for the puppeted object, if any. This +# # is convenient for commands defined on the Account only. +# if hasattr(self, "account_caller") and self.account_caller: +# if utils.inherits_from(self.caller, "evennia.objects.objects.DefaultObject"): +# # caller is an Object/Character +# self.character = self.caller +# self.caller = self.caller.account +# elif utils.inherits_from(self.caller, "evennia.accounts.accounts.DefaultAccount"): +# # caller was already an Account +# self.character = self.caller.get_puppet(self.session) +# else: +# self.character = None diff --git a/cwopamud/commands/default_cmdsets.py b/cwopamud/commands/default_cmdsets.py new file mode 100644 index 0000000..fee80c7 --- /dev/null +++ b/cwopamud/commands/default_cmdsets.py @@ -0,0 +1,96 @@ +""" +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 wraps the default command sets of Evennia; overloads 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 `AccountCmdSet` when an Account puppets a Character. + """ + + key = "DefaultCharacter" + + def at_cmdset_creation(self): + """ + Populates the cmdset + """ + super().at_cmdset_creation() + # + # any commands you add below will overload the default ones. + # + + +class AccountCmdSet(default_cmds.AccountCmdSet): + """ + This is the cmdset available to the Account at all times. It is + combined with the `CharacterCmdSet` when the Account puppets a + Character. It holds game-account-specific commands, channel + commands, etc. + """ + + key = "DefaultAccount" + + def at_cmdset_creation(self): + """ + Populates the cmdset + """ + super().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().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().at_cmdset_creation() + # + # any commands you add below will overload the default ones. + # diff --git a/cwopamud/server/README.md b/cwopamud/server/README.md new file mode 100644 index 0000000..9f530c3 --- /dev/null +++ b/cwopamud/server/README.md @@ -0,0 +1,38 @@ +# server/ + +This directory holds files used by and configuring the Evennia server +itself. + +Out of all the subdirectories in the game directory, Evennia does +expect this directory to exist, so you should normally not delete, +rename or change its folder structure. + +When running you will find four new files appear in this directory: + + - `server.pid` and `portal.pid`: These hold the process IDs of the + Portal and Server, so that they can be managed by the launcher. If + Evennia is shut down uncleanly (e.g. by a crash or via a kill + signal), these files might erroneously remain behind. If so Evennia + will tell you they are "stale" and they can be deleted manually. + - `server.restart` and `portal.restart`: These hold flags to tell the + server processes if it should die or start again. You never need to + modify those files. + - `evennia.db3`: This will only appear if you are using the default + SQLite3 database; it a binary file that holds the entire game + database; deleting this file will effectively reset the game for + you and you can start fresh with `evennia migrate` (useful during + development). + +## server/conf/ + +This subdirectory holds the configuration modules for the server. With +them you can change how Evennia operates and also plug in your own +functionality to replace the default. You usually need to restart the +server to apply changes done here. The most important file is the file +`settings.py` which is the main configuration file of Evennia. + +## server/logs/ + +This subdirectory holds various log files created by the running +Evennia server. It is also the default location for storing any custom +log files you might want to output using Evennia's logging mechanisms. diff --git a/cwopamud/server/__init__.py b/cwopamud/server/__init__.py new file mode 100644 index 0000000..40a96af --- /dev/null +++ b/cwopamud/server/__init__.py @@ -0,0 +1 @@ +# -*- coding: utf-8 -*- diff --git a/cwopamud/server/conf/__init__.py b/cwopamud/server/conf/__init__.py new file mode 100644 index 0000000..40a96af --- /dev/null +++ b/cwopamud/server/conf/__init__.py @@ -0,0 +1 @@ +# -*- coding: utf-8 -*- diff --git a/cwopamud/server/conf/at_initial_setup.py b/cwopamud/server/conf/at_initial_setup.py new file mode 100644 index 0000000..b394a04 --- /dev/null +++ b/cwopamud/server/conf/at_initial_setup.py @@ -0,0 +1,19 @@ +""" +At_initial_setup module template + +Custom at_initial_setup method. This allows you to hook special +modifications to the initial server startup process. Note that this +will only be run once - when the server starts up for the very first +time! It is called last in the startup process and can thus be used to +overload things that happened before it. + +The module must contain a global function at_initial_setup(). This +will be called without arguments. Note that tracebacks in this module +will be QUIETLY ignored, so make sure to check it well to make sure it +does what you expect it to. + +""" + + +def at_initial_setup(): + pass diff --git a/cwopamud/server/conf/at_search.py b/cwopamud/server/conf/at_search.py new file mode 100644 index 0000000..f7f8b6c --- /dev/null +++ b/cwopamud/server/conf/at_search.py @@ -0,0 +1,54 @@ +""" +Search and multimatch handling + +This module allows for overloading two functions used by Evennia's +search functionality: + + at_search_result: + This is called whenever a result is returned from an object + search (a common operation in commands). It should (together + with at_multimatch_input below) define some way to present and + differentiate between multiple matches (by default these are + presented as 1-ball, 2-ball etc) + at_multimatch_input: + This is called with a search term and should be able to + identify if the user wants to separate a multimatch-result + (such as that from a previous search). By default, this + function understands input on the form 1-ball, 2-ball etc as + indicating that the 1st or 2nd match for "ball" should be + used. + +This module is not called by default, to use it, add the following +line to your settings file: + + SEARCH_AT_RESULT = "server.conf.at_search.at_search_result" + +""" + + +def at_search_result(matches, caller, query="", quiet=False, **kwargs): + """ + This is a generic hook for handling all processing of a search + result, including error reporting. + + Args: + matches (list): This is a list of 0, 1 or more typeclass instances, + the matched result of the search. If 0, a nomatch error should + be echoed, and if >1, multimatch errors should be given. Only + if a single match should the result pass through. + caller (Object): The object performing the search and/or which should + receive error messages. + query (str, optional): The search query used to produce `matches`. + quiet (bool, optional): If `True`, no messages will be echoed to caller + on errors. + + Keyword Args: + nofound_string (str): Replacement string to echo on a notfound error. + multimatch_string (str): Replacement string to echo on a multimatch error. + + Returns: + processed_result (Object or None): This is always a single result + or `None`. If `None`, any error reporting/handling should + already have happened. + + """ diff --git a/cwopamud/server/conf/at_server_startstop.py b/cwopamud/server/conf/at_server_startstop.py new file mode 100644 index 0000000..8caf707 --- /dev/null +++ b/cwopamud/server/conf/at_server_startstop.py @@ -0,0 +1,71 @@ +""" +Server startstop hooks + +This module contains functions called by Evennia at various +points during its startup, reload and shutdown sequence. It +allows for customizing the server operation as desired. + +This module must contain at least these global functions: + +at_server_init() +at_server_start() +at_server_stop() +at_server_reload_start() +at_server_reload_stop() +at_server_cold_start() +at_server_cold_stop() + +""" + + +def at_server_init(): + """ + This is called first as the server is starting up, regardless of how. + """ + pass + + +def at_server_start(): + """ + This is called every time the server starts up, regardless of + how it was shut down. + """ + pass + + +def at_server_stop(): + """ + This is called just before the server is shut down, regardless + of it is for a reload, reset or shutdown. + """ + pass + + +def at_server_reload_start(): + """ + This is called only when server starts back up after a reload. + """ + pass + + +def at_server_reload_stop(): + """ + This is called only time the server stops before a reload. + """ + pass + + +def at_server_cold_start(): + """ + This is called only when the server starts "cold", i.e. after a + shutdown or a reset. + """ + pass + + +def at_server_cold_stop(): + """ + This is called only when the server goes down due to a shutdown or + reset. + """ + pass diff --git a/cwopamud/server/conf/cmdparser.py b/cwopamud/server/conf/cmdparser.py new file mode 100644 index 0000000..831990a --- /dev/null +++ b/cwopamud/server/conf/cmdparser.py @@ -0,0 +1,55 @@ +""" +Changing the default command parser + +The cmdparser is responsible for parsing the raw text inserted by the +user, identifying which command/commands match and return one or more +matching command objects. It is called by Evennia's cmdhandler and +must accept input and return results on the same form. The default +handler is very generic so you usually don't need to overload this +unless you have very exotic parsing needs; advanced parsing is best +done at the Command.parse level. + +The default cmdparser understands the following command combinations +(where [] marks optional parts.) + +[cmdname[ cmdname2 cmdname3 ...] [the rest] + +A command may consist of any number of space-separated words of any +length, and contain any character. It may also be empty. + +The parser makes use of the cmdset to find command candidates. The +parser return a list of matches. Each match is a tuple with its first +three elements being the parsed cmdname (lower case), the remaining +arguments, and the matched cmdobject from the cmdset. + + +This module is not accessed by default. To tell Evennia to use it +instead of the default command parser, add the following line to +your settings file: + + COMMAND_PARSER = "server.conf.cmdparser.cmdparser" + +""" + + +def cmdparser(raw_string, cmdset, caller, match_index=None): + """ + This function is called by the cmdhandler once it has + gathered and merged all valid cmdsets valid for this particular parsing. + + raw_string - the unparsed text entered by the caller. + cmdset - the merged, currently valid cmdset + caller - the caller triggering this parsing + match_index - an optional integer index to pick a given match in a + list of same-named command matches. + + Returns: + list of tuples: [(cmdname, args, cmdobj, cmdlen, mratio), ...] + where cmdname is the matching command name and args is + everything not included in the cmdname. Cmdobj is the actual + command instance taken from the cmdset, cmdlen is the length + of the command name and the mratio is some quality value to + (possibly) separate multiple matches. + + """ + # Your implementation here diff --git a/cwopamud/server/conf/connection_screens.py b/cwopamud/server/conf/connection_screens.py new file mode 100644 index 0000000..9ef7d5f --- /dev/null +++ b/cwopamud/server/conf/connection_screens.py @@ -0,0 +1,40 @@ +# -*- coding: utf-8 -*- +""" +Connection screen + +This is the text to show the user when they first connect to the game (before +they log in). + +To change the login screen in this module, do one of the following: + +- Define a function `connection_screen()`, taking no arguments. This will be + called first and must return the full string to act as the connection screen. + This can be used to produce more dynamic screens. +- Alternatively, define a string variable in the outermost scope of this module + with the connection string that should be displayed. If more than one such + variable is given, Evennia will pick one of them at random. + +The commands available to the user when the connection screen is shown +are defined in evennia.default_cmds.UnloggedinCmdSet. The parsing and display +of the screen is done by the unlogged-in "look" command. + +""" + +from django.conf import settings + +from evennia import utils + +CONNECTION_SCREEN = """ +|b==============================================================|n + Welcome to |g{}|n, version {}! + + If you have an existing account, connect to it by typing: + |wconnect |n + If you need to create an account, type (without the <>'s): + |wcreate |n + + If you have spaces in your username, enclose it in quotes. + Enter |whelp|n for more info. |wlook|n will re-show this screen. +|b==============================================================|n""".format( + settings.SERVERNAME, utils.get_evennia_version("short") +) diff --git a/cwopamud/server/conf/inlinefuncs.py b/cwopamud/server/conf/inlinefuncs.py new file mode 100644 index 0000000..c1ba9df --- /dev/null +++ b/cwopamud/server/conf/inlinefuncs.py @@ -0,0 +1,39 @@ +""" +Outgoing callables to apply with the FuncParser on outgoing messages. + +The functions in this module will become available as $funcname(args, kwargs) +in all outgoing strings if you add + + FUNCPARSER_PARSE_OUTGOING_MESSAGES_ENABLED = True + +to your settings file. The default inlinefuncs are found at the bottom of +`evennia.utils.funcparser`. + +In text, usage is straightforward: + +$funcname(arg1, arg2, ..., key=val, key2=val2, ...) + +Example 1 (using the "pad" inlinefunc): + say This is $pad("a center-padded text", 50,c,-) of width 50. + -> + John says, "This is -------------- a center-padded text--------------- of width 50." + +Example 2 (using nested "pad" and "time" inlinefuncs): + say The time is $pad($time(), 30)right now. + -> + John says, "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(*args, **kwargs) + ... + +""" + +# def capitalize(*args, **kwargs): +# "Silly capitalize example. Used as $capitalize +# if not args: +# return '' +# session = kwargs.get("session") +# return args[0].capitalize() diff --git a/cwopamud/server/conf/inputfuncs.py b/cwopamud/server/conf/inputfuncs.py new file mode 100644 index 0000000..6cb226f --- /dev/null +++ b/cwopamud/server/conf/inputfuncs.py @@ -0,0 +1,52 @@ +""" +Input functions + +Input functions are always called from the client (they handle server +input, hence the name). + +This module is loaded by being included in the +`settings.INPUT_FUNC_MODULES` tuple. + +All *global functions* included in this module are considered +input-handler functions and can be called by the client to handle +input. + +An input function must have the following call signature: + + cmdname(session, *args, **kwargs) + +Where session will be the active session and *args, **kwargs are extra +incoming arguments and keyword properties. + +A special command is the "default" command, which is will be called +when no other cmdname matches. It also receives the non-found cmdname +as argument. + + default(session, cmdname, *args, **kwargs) + +""" + +# def oob_echo(session, *args, **kwargs): +# """ +# Example echo function. Echoes args, kwargs sent to it. +# +# Args: +# session (Session): The Session to receive the echo. +# args (list of str): Echo text. +# kwargs (dict of str, optional): Keyed echo text +# +# """ +# session.msg(oob=("echo", args, kwargs)) +# +# +# def default(session, cmdname, *args, **kwargs): +# """ +# Handles commands without a matching inputhandler func. +# +# Args: +# session (Session): The active Session. +# cmdname (str): The (unmatched) command name +# args, kwargs (any): Arguments to function. +# +# """ +# pass diff --git a/cwopamud/server/conf/lockfuncs.py b/cwopamud/server/conf/lockfuncs.py new file mode 100644 index 0000000..8dac0c7 --- /dev/null +++ b/cwopamud/server/conf/lockfuncs.py @@ -0,0 +1,30 @@ +""" + +Lockfuncs + +Lock functions are functions available when defining lock strings, +which in turn limits access to various game systems. + +All functions defined globally in this module are assumed to be +available for use in lockstrings to determine access. See the +Evennia documentation for more info on locks. + +A lock function is always called with two arguments, accessing_obj and +accessed_obj, followed by any number of arguments. All possible +arguments should be handled with *args, **kwargs. The lock function +should handle all eventual tracebacks by logging the error and +returning False. + +Lock functions in this module extend (and will overload same-named) +lock functions from evennia.locks.lockfuncs. + +""" + +# def myfalse(accessing_obj, accessed_obj, *args, **kwargs): +# """ +# called in lockstring with myfalse(). +# A simple logger that always returns false. Prints to stdout +# for simplicity, should use utils.logger for real operation. +# """ +# print "%s tried to access %s. Access denied." % (accessing_obj, accessed_obj) +# return False diff --git a/cwopamud/server/conf/mssp.py b/cwopamud/server/conf/mssp.py new file mode 100644 index 0000000..9472f47 --- /dev/null +++ b/cwopamud/server/conf/mssp.py @@ -0,0 +1,105 @@ +""" + +MSSP (Mud Server Status Protocol) meta information + +Modify this file to specify what MUD listing sites will report about your game. +All fields are static. The number of currently active players and your game's +current uptime will be added automatically by Evennia. + +You don't have to fill in everything (and most fields are not shown/used by all +crawlers anyway); leave the default if so needed. You need to reload the server +before the updated information is made available to crawlers (reloading does +not affect uptime). + +After changing the values in this file, you must register your game with the +MUD website list you want to track you. The listing crawler will then regularly +connect to your server to get the latest info. No further configuration is +needed on the Evennia side. + +""" + +MSSPTable = { + # Required fields + "NAME": "Mygame", # usually the same as SERVERNAME + # Generic + "CRAWL DELAY": "-1", # limit how often crawler may update the listing. -1 for no limit + "HOSTNAME": "", # telnet hostname + "PORT": ["4000"], # telnet port - most important port should be *last* in list! + "CODEBASE": "Evennia", + "CONTACT": "", # email for contacting the mud + "CREATED": "", # year MUD was created + "ICON": "", # url to icon 32x32 or larger; <32kb. + "IP": "", # current or new IP address + "LANGUAGE": "", # name of language used, e.g. English + "LOCATION": "", # full English name of server country + "MINIMUM AGE": "0", # set to 0 if not applicable + "WEBSITE": "", # http:// address to your game website + # Categorisation + "FAMILY": "Evennia", + "GENRE": "None", # Adult, Fantasy, Historical, Horror, Modern, None, or Science Fiction + # Gameplay: Adventure, Educational, Hack and Slash, None, + # Player versus Player, Player versus Environment, + # Roleplaying, Simulation, Social or Strategy + "GAMEPLAY": "", + "STATUS": "Open Beta", # Allowed: Alpha, Closed Beta, Open Beta, Live + "GAMESYSTEM": "Custom", # D&D, d20 System, World of Darkness, etc. Use Custom if homebrew + # Subgenre: LASG, Medieval Fantasy, World War II, Frankenstein, + # Cyberpunk, Dragonlance, etc. Or None if not applicable. + "SUBGENRE": "None", + # World + "AREAS": "0", + "HELPFILES": "0", + "MOBILES": "0", + "OBJECTS": "0", + "ROOMS": "0", # use 0 if room-less + "CLASSES": "0", # use 0 if class-less + "LEVELS": "0", # use 0 if level-less + "RACES": "0", # use 0 if race-less + "SKILLS": "0", # use 0 if skill-less + # Protocols set to 1 or 0; should usually not be changed) + "ANSI": "1", + "GMCP": "1", + "MSDP": "1", + "MXP": "1", + "SSL": "1", + "UTF-8": "1", + "MCCP": "1", + "XTERM 256 COLORS": "1", + "XTERM TRUE COLORS": "0", + "ATCP": "0", + "MCP": "0", + "MSP": "0", + "VT100": "0", + "PUEBLO": "0", + "ZMP": "0", + # Commercial set to 1 or 0) + "PAY TO PLAY": "0", + "PAY FOR PERKS": "0", + # Hiring set to 1 or 0) + "HIRING BUILDERS": "0", + "HIRING CODERS": "0", + # Extended variables + # World + "DBSIZE": "0", + "EXITS": "0", + "EXTRA DESCRIPTIONS": "0", + "MUDPROGS": "0", + "MUDTRIGS": "0", + "RESETS": "0", + # Game (set to 1 or 0, or one of the given alternatives) + "ADULT MATERIAL": "0", + "MULTICLASSING": "0", + "NEWBIE FRIENDLY": "0", + "PLAYER CITIES": "0", + "PLAYER CLANS": "0", + "PLAYER CRAFTING": "0", + "PLAYER GUILDS": "0", + "EQUIPMENT SYSTEM": "None", # "None", "Level", "Skill", "Both" + "MULTIPLAYING": "None", # "None", "Restricted", "Full" + "PLAYERKILLING": "None", # "None", "Restricted", "Full" + "QUEST SYSTEM": "None", # "None", "Immortal Run", "Automated", "Integrated" + "ROLEPLAYING": "None", # "None", "Accepted", "Encouraged", "Enforced" + "TRAINING SYSTEM": "None", # "None", "Level", "Skill", "Both" + # World originality: "All Stock", "Mostly Stock", "Mostly Original", "All Original" + "WORLD ORIGINALITY": "All Original", +} diff --git a/cwopamud/server/conf/portal_services_plugins.py b/cwopamud/server/conf/portal_services_plugins.py new file mode 100644 index 0000000..b536c56 --- /dev/null +++ b/cwopamud/server/conf/portal_services_plugins.py @@ -0,0 +1,24 @@ +""" +Start plugin services + +This plugin module can define user-created services for the Portal to +start. + +This module must handle all imports and setups required to start +twisted services (see examples in evennia.server.portal.portal). It +must also contain a function start_plugin_services(application). +Evennia will call this function with the main Portal application (so +your services can be added to it). The function should not return +anything. Plugin services are started last in the Portal startup +process. + +""" + + +def start_plugin_services(portal): + """ + This hook is called by Evennia, last in the Portal startup process. + + portal - a reference to the main portal application. + """ + pass diff --git a/cwopamud/server/conf/server_services_plugins.py b/cwopamud/server/conf/server_services_plugins.py new file mode 100644 index 0000000..e3d41fe --- /dev/null +++ b/cwopamud/server/conf/server_services_plugins.py @@ -0,0 +1,24 @@ +""" + +Server plugin services + +This plugin module can define user-created services for the Server to +start. + +This module must handle all imports and setups required to start a +twisted service (see examples in evennia.server.server). It must also +contain a function start_plugin_services(application). Evennia will +call this function with the main Server application (so your services +can be added to it). The function should not return anything. Plugin +services are started last in the Server startup process. + +""" + + +def start_plugin_services(server): + """ + This hook is called by Evennia, last in the Server startup process. + + server - a reference to the main server application. + """ + pass diff --git a/cwopamud/server/conf/serversession.py b/cwopamud/server/conf/serversession.py new file mode 100644 index 0000000..13fbf1e --- /dev/null +++ b/cwopamud/server/conf/serversession.py @@ -0,0 +1,37 @@ +""" +ServerSession + +The serversession is the Server-side in-memory representation of a +user connecting to the game. Evennia manages one Session per +connection to the game. So a user logged into the game with multiple +clients (if Evennia is configured to allow that) will have multiple +sessions tied to one Account object. All communication between Evennia +and the real-world user goes through the Session(s) associated with that user. + +It should be noted that modifying the Session object is not usually +necessary except for the most custom and exotic designs - and even +then it might be enough to just add custom session-level commands to +the SessionCmdSet instead. + +This module is not normally called. To tell Evennia to use the class +in this module instead of the default one, add the following to your +settings file: + + SERVER_SESSION_CLASS = "server.conf.serversession.ServerSession" + +""" + +from evennia.server.serversession import ServerSession as BaseServerSession + + +class ServerSession(BaseServerSession): + """ + This class represents a player's session and is a template for + individual protocols to communicate with Evennia. + + Each account gets one or more sessions assigned to them whenever they connect + to the game server. All communication between game and account goes + through their session(s). + """ + + pass diff --git a/cwopamud/server/conf/settings.py b/cwopamud/server/conf/settings.py new file mode 100644 index 0000000..f6da2b9 --- /dev/null +++ b/cwopamud/server/conf/settings.py @@ -0,0 +1,44 @@ +r""" +Evennia settings file. + +The available options are found in the default settings file found +here: + +https://www.evennia.com/docs/latest/Setup/Settings-Default.html + +Remember: + +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. + +When changing a setting requiring a file system path (like +path/to/actual/file.py), use GAME_DIR and EVENNIA_DIR to reference +your game folder and the Evennia library folders respectively. Python +paths (path.to.module) should be given relative to the game's root +folder (typeclasses.foo) whereas paths within the Evennia library +needs to be given explicitly (evennia.foo). + +If you want to share your game dir, including its settings, you can +put secret game- or server-specific settings in secret_settings.py. + +""" + +# Use the defaults from Evennia unless explicitly overridden +from evennia.settings_default import * + +###################################################################### +# Evennia base server config +###################################################################### + +# This is the name of your game. Make it catchy! +SERVERNAME = "cwopamud" + + +###################################################################### +# Settings given in secret_settings.py override those in this file. +###################################################################### +try: + from server.conf.secret_settings import * +except ImportError: + print("secret_settings.py file not found or failed to import.") diff --git a/cwopamud/server/conf/web_plugins.py b/cwopamud/server/conf/web_plugins.py new file mode 100644 index 0000000..ec11ad7 --- /dev/null +++ b/cwopamud/server/conf/web_plugins.py @@ -0,0 +1,41 @@ +""" +Web plugin hooks. +""" + + +def at_webserver_root_creation(web_root): + """ + This is called as the web server has finished building its default + path tree. At this point, the media/ and static/ URIs have already + been added to the web root. + + Args: + web_root (twisted.web.resource.Resource): The root + resource of the URI tree. Use .putChild() to + add new subdomains to the tree. + + Returns: + web_root (twisted.web.resource.Resource): The potentially + modified root structure. + + Example: + from twisted.web import static + my_page = static.File("web/mypage/") + my_page.indexNames = ["index.html"] + web_root.putChild("mypage", my_page) + + """ + return web_root + + +def at_webproxy_root_creation(web_root): + """ + This function can modify the portal proxy service. + Args: + web_root (evennia.server.webserver.Website): The Evennia + Website application. Use .putChild() to add new + subdomains that are Portal-accessible over TCP; + primarily for new protocol development, but suitable + for other shenanigans. + """ + return web_root diff --git a/cwopamud/server/logs/README.md b/cwopamud/server/logs/README.md new file mode 100644 index 0000000..35ad999 --- /dev/null +++ b/cwopamud/server/logs/README.md @@ -0,0 +1,15 @@ +This directory contains Evennia's log files. The existence of this README.md file is also necessary +to correctly include the log directory in git (since log files are ignored by git and you can't +commit an empty directory). + +- `server.log` - log file from the game Server. +- `portal.log` - log file from Portal proxy (internet facing) + +Usually these logs are viewed together with `evennia -l`. They are also rotated every week so as not +to be too big. Older log names will have a name appended by `_month_date`. + +- `lockwarnings.log` - warnings from the lock system. +- `http_requests.log` - this will generally be empty unless turning on debugging inside the server. + +- `channel_.log` - these are channel logs for the in-game channels They are also used + by the `/history` flag in-game to get the latest message history. diff --git a/cwopamud/typeclasses/README.md b/cwopamud/typeclasses/README.md new file mode 100644 index 0000000..e114e59 --- /dev/null +++ b/cwopamud/typeclasses/README.md @@ -0,0 +1,16 @@ +# typeclasses/ + +This directory holds the modules for overloading all the typeclasses +representing the game entities and many systems of the game. Other +server functionality not covered here is usually modified by the +modules in `server/conf/`. + +Each module holds empty classes that just imports Evennia's defaults. +Any modifications done to these classes will overload the defaults. + +You can change the structure of this directory (even rename the +directory itself) as you please, but if you do you must add the +appropriate new paths to your settings.py file so Evennia knows where +to look. Also remember that for Python to find your modules, it +requires you to add an empty `__init__.py` file in any new sub +directories you create. diff --git a/cwopamud/typeclasses/__init__.py b/cwopamud/typeclasses/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/cwopamud/typeclasses/accounts.py b/cwopamud/typeclasses/accounts.py new file mode 100644 index 0000000..89d5e41 --- /dev/null +++ b/cwopamud/typeclasses/accounts.py @@ -0,0 +1,104 @@ +""" +Account + +The Account represents the game "account" and each login has only one +Account object. An Account is what chats on default channels but has no +other in-game-world existence. Rather the Account puppets Objects (such +as Characters) in order to actually participate in the game world. + + +Guest + +Guest accounts are simple low-level accounts that are created/deleted +on the fly and allows users to test the game without the commitment +of a full registration. Guest accounts are deactivated by default; to +activate them, add the following line to your settings file: + + GUEST_ENABLED = True + +You will also need to modify the connection screen to reflect the +possibility to connect with a guest account. The setting file accepts +several more options for customizing the Guest account system. + +""" + +from evennia.accounts.accounts import DefaultAccount, DefaultGuest + + +class Account(DefaultAccount): + """ + This class describes the actual OOC account (i.e. the user connecting + to the MUD). It does NOT have visual appearance in the game world (that + is handled by the character which is connected to this). Comm channels + are attended/joined using this object. + + It can be useful e.g. for storing configuration options for your game, but + should generally not hold any character-related info (that's best handled + on the character level). + + Can be set using BASE_ACCOUNT_TYPECLASS. + + + * available properties + + key (string) - name of account + name (string)- wrapper for user.username + aliases (list of strings) - aliases to the object. Will be saved to database as AliasDB entries but returned as strings. + dbref (int, read-only) - unique #id-number. Also "id" can be used. + date_created (string) - time stamp of object creation + permissions (list of strings) - list of permission strings + + user (User, read-only) - django User authorization object + obj (Object) - game object controlled by account. 'character' can also be used. + sessions (list of Sessions) - sessions connected to this account + is_superuser (bool, read-only) - if the connected user is a superuser + + * Handlers + + locks - lock-handler: use locks.add() to add new lock strings + db - attribute-handler: store/retrieve database attributes on this self.db.myattr=val, val=self.db.myattr + ndb - non-persistent attribute handler: same as db but does not create a database entry when storing data + scripts - script-handler. Add new scripts to object with scripts.add() + cmdset - cmdset-handler. Use cmdset.add() to add new cmdsets to object + nicks - nick-handler. New nicks with nicks.add(). + + * Helper methods + + msg(text=None, **kwargs) + execute_cmd(raw_string, session=None) + search(ostring, global_search=False, attribute_name=None, use_nicks=False, location=None, ignore_errors=False, account=False) + is_typeclass(typeclass, exact=False) + swap_typeclass(new_typeclass, clean_attributes=False, no_default=True) + access(accessing_obj, access_type='read', default=False) + check_permstring(permstring) + + * Hook methods (when re-implementation, remember methods need to have self as first arg) + + basetype_setup() + at_account_creation() + + - note that the following hooks are also found on Objects and are + usually handled on the character level: + + at_init() + at_cmdset_get(**kwargs) + at_first_login() + at_post_login(session=None) + at_disconnect() + at_message_receive() + at_message_send() + at_server_reload() + at_server_shutdown() + + """ + + pass + + +class Guest(DefaultGuest): + """ + This class is used for guest logins. Unlike Accounts, Guests and their + characters are deleted after disconnection. + """ + + pass diff --git a/cwopamud/typeclasses/channels.py b/cwopamud/typeclasses/channels.py new file mode 100644 index 0000000..f16e889 --- /dev/null +++ b/cwopamud/typeclasses/channels.py @@ -0,0 +1,62 @@ +""" +Channel + +The channel class represents the out-of-character chat-room usable by +Accounts in-game. It is mostly overloaded to change its appearance, but +channels can be used to implement many different forms of message +distribution systems. + +Note that sending data to channels are handled via the CMD_CHANNEL +syscommand (see evennia.syscmds). The sending should normally not need +to be modified. + +""" + +from evennia.comms.comms import DefaultChannel + + +class Channel(DefaultChannel): + """ + Working methods: + at_channel_creation() - called once, when the channel is created + has_connection(account) - check if the given account listens to this channel + connect(account) - connect account to this channel + disconnect(account) - disconnect account from channel + access(access_obj, access_type='listen', default=False) - check the + access on this channel (default access_type is listen) + delete() - delete this channel + message_transform(msg, emit=False, prefix=True, + sender_strings=None, external=False) - called by + the comm system and triggers the hooks below + msg(msgobj, header=None, senders=None, sender_strings=None, + persistent=None, online=False, emit=False, external=False) - main + send method, builds and sends a new message to channel. + tempmsg(msg, header=None, senders=None) - wrapper for sending non-persistent + messages. + distribute_message(msg, online=False) - send a message to all + connected accounts on channel, optionally sending only + to accounts that are currently online (optimized for very large sends) + + Useful hooks: + channel_prefix() - how the channel should be + prefixed when returning to user. Returns a string + format_senders(senders) - should return how to display multiple + senders to a channel + pose_transform(msg, sender_string) - should detect if the + sender is posing, and if so, modify the string + format_external(msg, senders, emit=False) - format messages sent + from outside the game, like from IRC + format_message(msg, emit=False) - format the message body before + displaying it to the user. 'emit' generally means that the + message should not be displayed with the sender's name. + + pre_join_channel(joiner) - if returning False, abort join + post_join_channel(joiner) - called right after successful join + pre_leave_channel(leaver) - if returning False, abort leave + post_leave_channel(leaver) - called right after successful leave + pre_send_message(msg) - runs just before a message is sent to channel + post_send_message(msg) - called just after message was sent to channel + + """ + + pass diff --git a/cwopamud/typeclasses/characters.py b/cwopamud/typeclasses/characters.py new file mode 100644 index 0000000..b022c1f --- /dev/null +++ b/cwopamud/typeclasses/characters.py @@ -0,0 +1,37 @@ +""" +Characters + +Characters are (by default) Objects setup to be puppeted by Accounts. +They are what you "see" in game. The Character class in this module +is setup to be the "default" character type created by the default +creation commands. + +""" + +from evennia.objects.objects import DefaultCharacter + +from .objects import ObjectParent + + +class Character(ObjectParent, DefaultCharacter): + """ + The Character defaults to reimplementing some of base Object's hook methods with the + following functionality: + + at_basetype_setup - always assigns the DefaultCmdSet to this object type + (important!)sets locks so character cannot be picked up + and its commands only be called by itself, not anyone else. + (to change things, use at_object_creation() instead). + at_post_move(source_location) - Launches the "look" command after every move. + at_post_unpuppet(account) - when Account disconnects from the Character, we + store the current location in the prelogout_location Attribute and + move it to a None-location so the "unpuppeted" character + object does not need to stay on grid. Echoes "Account has disconnected" + to the room. + at_pre_puppet - Just before Account re-connects, retrieves the character's + prelogout_location Attribute and move it back on the grid. + at_post_puppet - Echoes "AccountName has entered the game" to the room. + + """ + + pass diff --git a/cwopamud/typeclasses/exits.py b/cwopamud/typeclasses/exits.py new file mode 100644 index 0000000..3a53753 --- /dev/null +++ b/cwopamud/typeclasses/exits.py @@ -0,0 +1,41 @@ +""" +Exits + +Exits are connectors between Rooms. An exit always has a destination property +set and has a single command defined on itself with the same name as its key, +for allowing Characters to traverse the exit to its destination. + +""" + +from evennia.objects.objects import DefaultExit + +from .objects import ObjectParent + + +class Exit(ObjectParent, DefaultExit): + """ + Exits are connectors between rooms. Exits are normal Objects except + they defines the `destination` property. It also does work in the + following methods: + + basetype_setup() - sets default exit locks (to change, use `at_object_creation` instead). + at_cmdset_get(**kwargs) - this is called when the cmdset is accessed and should + rebuild the Exit cmdset along with a command matching the name + of the Exit object. Conventionally, a kwarg `force_init` + should force a rebuild of the cmdset, this is triggered + by the `@alias` command when aliases are changed. + at_failed_traverse() - gives a default error message ("You cannot + go there") if exit traversal fails and an + attribute `err_traverse` is not defined. + + Relevant hooks to overload (compared to other types of Objects): + at_traverse(traveller, target_loc) - called to do the actual traversal and calling of the other hooks. + If overloading this, consider using super() to use the default + movement implementation (and hook-calling). + at_post_traverse(traveller, source_loc) - called by at_traverse just after traversing. + at_failed_traverse(traveller) - called by at_traverse if traversal failed for some reason. Will + not be called if the attribute `err_traverse` is + defined, in which case that will simply be echoed. + """ + + pass diff --git a/cwopamud/typeclasses/objects.py b/cwopamud/typeclasses/objects.py new file mode 100644 index 0000000..11b7363 --- /dev/null +++ b/cwopamud/typeclasses/objects.py @@ -0,0 +1,175 @@ +""" +Object + +The Object is the "naked" base class for things in the game world. + +Note that the default Character, Room and Exit does not inherit from +this Object, but from their respective default implementations in the +evennia library. If you want to use this class as a parent to change +the other types, you can do so by adding this as a multiple +inheritance. + +""" + +from evennia.objects.objects import DefaultObject + + +class ObjectParent: + """ + This is a mixin that can be used to override *all* entities inheriting at + some distance from DefaultObject (Objects, Exits, Characters and Rooms). + + Just add any method that exists on `DefaultObject` to this class. If one + of the derived classes has itself defined that same hook already, that will + take precedence. + + """ + + +class Object(ObjectParent, DefaultObject): + """ + This is the root typeclass object, implementing an in-game Evennia + game object, such as having a location, being able to be + manipulated or looked at, etc. If you create a new typeclass, it + must always inherit from this object (or any of the other objects + in this file, since they all actually inherit from BaseObject, as + seen in src.object.objects). + + The BaseObject class implements several hooks tying into the game + engine. By re-implementing these hooks you can control the + system. You should never need to re-implement special Python + methods, such as __init__ and especially never __getattribute__ and + __setattr__ since these are used heavily by the typeclass system + of Evennia and messing with them might well break things for you. + + + * Base properties defined/available on all Objects + + key (string) - name of object + name (string)- same as key + dbref (int, read-only) - unique #id-number. Also "id" can be used. + date_created (string) - time stamp of object creation + + account (Account) - controlling account (if any, only set together with + sessid below) + sessid (int, read-only) - session id (if any, only set together with + account above). Use `sessions` handler to get the + Sessions directly. + location (Object) - current location. Is None if this is a room + home (Object) - safety start-location + has_account (bool, read-only)- will only return *connected* accounts + contents (list of Objects, read-only) - returns all objects inside this + object (including exits) + exits (list of Objects, read-only) - returns all exits from this + object, if any + destination (Object) - only set if this object is an exit. + is_superuser (bool, read-only) - True/False if this user is a superuser + + * Handlers available + + aliases - alias-handler: use aliases.add/remove/get() to use. + permissions - permission-handler: use permissions.add/remove() to + add/remove new perms. + locks - lock-handler: use locks.add() to add new lock strings + scripts - script-handler. Add new scripts to object with scripts.add() + cmdset - cmdset-handler. Use cmdset.add() to add new cmdsets to object + nicks - nick-handler. New nicks with nicks.add(). + sessions - sessions-handler. Get Sessions connected to this + object with sessions.get() + attributes - attribute-handler. Use attributes.add/remove/get. + db - attribute-handler: Shortcut for attribute-handler. Store/retrieve + database attributes using self.db.myattr=val, val=self.db.myattr + ndb - non-persistent attribute handler: same as db but does not create + a database entry when storing data + + * Helper methods (see src.objects.objects.py for full headers) + + search(ostring, global_search=False, attribute_name=None, + use_nicks=False, location=None, ignore_errors=False, account=False) + execute_cmd(raw_string) + msg(text=None, **kwargs) + msg_contents(message, exclude=None, from_obj=None, **kwargs) + move_to(destination, quiet=False, emit_to_obj=None, use_destination=True) + copy(new_key=None) + delete() + is_typeclass(typeclass, exact=False) + swap_typeclass(new_typeclass, clean_attributes=False, no_default=True) + access(accessing_obj, access_type='read', default=False) + check_permstring(permstring) + + * Hooks (these are class methods, so args should start with self): + + basetype_setup() - only called once, used for behind-the-scenes + setup. Normally not modified. + basetype_posthook_setup() - customization in basetype, after the object + has been created; Normally not modified. + + at_object_creation() - only called once, when object is first created. + Object customizations go here. + at_object_delete() - called just before deleting an object. If returning + False, deletion is aborted. Note that all objects + inside a deleted object are automatically moved + to their , they don't need to be removed here. + + at_init() - called whenever typeclass is cached from memory, + at least once every server restart/reload + at_cmdset_get(**kwargs) - this is called just before the command handler + requests a cmdset from this object. The kwargs are + not normally used unless the cmdset is created + dynamically (see e.g. Exits). + at_pre_puppet(account)- (account-controlled objects only) called just + before puppeting + at_post_puppet() - (account-controlled objects only) called just + after completing connection account<->object + at_pre_unpuppet() - (account-controlled objects only) called just + before un-puppeting + at_post_unpuppet(account) - (account-controlled objects only) called just + after disconnecting account<->object link + at_server_reload() - called before server is reloaded + at_server_shutdown() - called just before server is fully shut down + + at_access(result, accessing_obj, access_type) - called with the result + of a lock access check on this object. Return value + does not affect check result. + + at_pre_move(destination) - called just before moving object + to the destination. If returns False, move is cancelled. + announce_move_from(destination) - called in old location, just + before move, if obj.move_to() has quiet=False + announce_move_to(source_location) - called in new location, just + after move, if obj.move_to() has quiet=False + at_post_move(source_location) - always called after a move has + been successfully performed. + at_object_leave(obj, target_location) - called when an object leaves + this object in any fashion + at_object_receive(obj, source_location) - called when this object receives + another object + + at_traverse(traversing_object, source_loc) - (exit-objects only) + handles all moving across the exit, including + calling the other exit hooks. Use super() to retain + the default functionality. + at_post_traverse(traversing_object, source_location) - (exit-objects only) + called just after a traversal has happened. + at_failed_traverse(traversing_object) - (exit-objects only) called if + traversal fails and property err_traverse is not defined. + + at_msg_receive(self, msg, from_obj=None, **kwargs) - called when a message + (via self.msg()) is sent to this obj. + If returns false, aborts send. + at_msg_send(self, msg, to_obj=None, **kwargs) - called when this objects + sends a message to someone via self.msg(). + + return_appearance(looker) - describes this object. Used by "look" + command by default + at_desc(looker=None) - called by 'look' whenever the + appearance is requested. + at_get(getter) - called after object has been picked up. + Does not stop pickup. + at_drop(dropper) - called when this object has been dropped. + at_say(speaker, message) - by default, called if an object inside this + object speaks + + """ + + pass diff --git a/cwopamud/typeclasses/rooms.py b/cwopamud/typeclasses/rooms.py new file mode 100644 index 0000000..71f4aa0 --- /dev/null +++ b/cwopamud/typeclasses/rooms.py @@ -0,0 +1,24 @@ +""" +Room + +Rooms are simple containers that has no location of their own. + +""" + +from evennia.objects.objects import DefaultRoom + +from .objects import ObjectParent + + +class Room(ObjectParent, DefaultRoom): + """ + Rooms are like any Object, except their location is None + (which is default). They also use basetype_setup() to + add locks so they cannot be puppeted or picked up. + (to change that, use at_object_creation instead) + + See mygame/typeclasses/objects.py for a list of + properties and methods available on all Objects. + """ + + pass diff --git a/cwopamud/typeclasses/scripts.py b/cwopamud/typeclasses/scripts.py new file mode 100644 index 0000000..63f3bb8 --- /dev/null +++ b/cwopamud/typeclasses/scripts.py @@ -0,0 +1,92 @@ +""" +Scripts + +Scripts are powerful jacks-of-all-trades. They have no in-game +existence and can be used to represent persistent game systems in some +circumstances. Scripts can also have a time component that allows them +to "fire" regularly or a limited number of times. + +There is generally no "tree" of Scripts inheriting from each other. +Rather, each script tends to inherit from the base Script class and +just overloads its hooks to have it perform its function. + +""" + +from evennia.scripts.scripts import DefaultScript + + +class Script(DefaultScript): + """ + A script type is customized by redefining some or all of its hook + methods and variables. + + * available properties + + key (string) - name of object + name (string)- same as key + aliases (list of strings) - aliases to the object. Will be saved + to database as AliasDB entries but returned as strings. + dbref (int, read-only) - unique #id-number. Also "id" can be used. + date_created (string) - time stamp of object creation + permissions (list of strings) - list of permission strings + + desc (string) - optional description of script, shown in listings + obj (Object) - optional object that this script is connected to + and acts on (set automatically by obj.scripts.add()) + interval (int) - how often script should run, in seconds. <0 turns + off ticker + start_delay (bool) - if the script should start repeating right away or + wait self.interval seconds + repeats (int) - how many times the script should repeat before + stopping. 0 means infinite repeats + persistent (bool) - if script should survive a server shutdown or not + is_active (bool) - if script is currently running + + * Handlers + + locks - lock-handler: use locks.add() to add new lock strings + db - attribute-handler: store/retrieve database attributes on this + self.db.myattr=val, val=self.db.myattr + ndb - non-persistent attribute handler: same as db but does not + create a database entry when storing data + + * Helper methods + + start() - start script (this usually happens automatically at creation + and obj.script.add() etc) + stop() - stop script, and delete it + pause() - put the script on hold, until unpause() is called. If script + is persistent, the pause state will survive a shutdown. + unpause() - restart a previously paused script. The script will continue + from the paused timer (but at_start() will be called). + time_until_next_repeat() - if a timed script (interval>0), returns time + until next tick + + * Hook methods (should also include self as the first argument): + + at_script_creation() - called only once, when an object of this + class is first created. + is_valid() - is called to check if the script is valid to be running + at the current time. If is_valid() returns False, the running + script is stopped and removed from the game. You can use this + to check state changes (i.e. an script tracking some combat + stats at regular intervals is only valid to run while there is + actual combat going on). + at_start() - Called every time the script is started, which for persistent + scripts is at least once every server start. Note that this is + unaffected by self.delay_start, which only delays the first + call to at_repeat(). + at_repeat() - Called every self.interval seconds. It will be called + immediately upon launch unless self.delay_start is True, which + will delay the first call of this method by self.interval + seconds. If self.interval==0, this method will never + be called. + at_stop() - Called as the script object is stopped and is about to be + removed from the game, e.g. because is_valid() returned False. + at_server_reload() - Called when server reloads. Can be used to + save temporary variables you want should survive a reload. + at_server_shutdown() - called at a full server shutdown. + + """ + + pass diff --git a/cwopamud/web/README.md b/cwopamud/web/README.md new file mode 100644 index 0000000..2455bdb --- /dev/null +++ b/cwopamud/web/README.md @@ -0,0 +1,51 @@ +# Web + +This folder contains overriding of web assets - the website and webclient +coming with the game. + +This is the process for serving a new web site (see also the Django docs for +more details): + +1. A user enters an url in their browser (or clicks a button). This leads to + the browser sending a _HTTP request_ to the server, with a specific type + (GET,POST etc) and url-path (like for `https://localhost:4001/`, the part of + the url we need to consider is `/`). +2. Evennia (through Django) will make use of the regular expressions registered + in the `urls.py` file. This acts as a rerouter to _views_, which are + regular Python functions able to process the incoming request (think of + these as similar to the right Evennia Command being selected to handle your + input - views are like Commands in this sense). In the case of `/` we + reroute to a view handling the main index-page of the website. The view is + either a function or a callable class (Evennia tends to have them as + functions). +3. The view-function will prepare all the data needed by the web page. For the default + index page, this means gather the game statistics so you can see how many + are currently connected to the game etc. +4. The view will next fetch a _template_. A template is a HTML-document with special + 'placeholder' tags (written as `{{...}}` or `{% ... %}` usually). These + placeholders allow the view to inject dynamic content into the HTML and make + the page customized to the current situation. For the index page, it means + injecting the current player-count in the right places of the html page. This + is called 'rendering' the template. The result is a complete HTML page. +5. (The view can also pull in a _form_ to customize user-input in a similar way.) +6. The finished HTML page is packed in a _HTTP response_ and is returned to the + web browser, which can now display the page! + +## A note on the webclient + +The web browser can also execute code directly without talking to the Server. +This code must be written/loaded into the web page and is written using the +Javascript programming language (there is no way around this, it is what web +browsers understand). Executing Javascript is something the web browser does, +it operates independently from Evennia. Small snippets of javascript can be +used on a page to have buttons react, make small animations etc that doesn't +require the server. + +In the case of the Webclient, Evennia will load the Webclient page as above, +but the page then contains Javascript code responsible for actually displaying +the client GUI, allows you to resize windows etc. + +After it starts, the webclient 'calls home' and spins up a websocket link to +the Evennia Portal - this is how all data is then exchanged. So after the +initial loading of the webclient page, the above sequence doesn't happen again +until close the tab and come back or you reload it manually in your browser. diff --git a/cwopamud/web/__init__.py b/cwopamud/web/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/cwopamud/web/admin/README.md b/cwopamud/web/admin/README.md new file mode 100644 index 0000000..e5d8b53 --- /dev/null +++ b/cwopamud/web/admin/README.md @@ -0,0 +1,5 @@ +# Admin views + +Evennia makes several customizations to the Django web admin, but you can make +further changes here. Customizing the admin is a big topic and +you are best off reading more about it in the [Django admin site documentation](https://docs.djangoproject.com/en/4.1/ref/contrib/admin/). diff --git a/cwopamud/web/admin/__init__.py b/cwopamud/web/admin/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/cwopamud/web/admin/urls.py b/cwopamud/web/admin/urls.py new file mode 100644 index 0000000..c42f8dc --- /dev/null +++ b/cwopamud/web/admin/urls.py @@ -0,0 +1,20 @@ +""" +This reroutes from an URL to a python view-function/class. + +The main web/urls.py includes these routes for all urls starting with `admin/` +(the `admin/` part should not be included again here). + +""" + +from django.urls import path + +from evennia.web.admin.urls import urlpatterns as evennia_admin_urlpatterns + +# add patterns here +urlpatterns = [ + # path("url-pattern", imported_python_view), + # path("url-pattern", imported_python_view), +] + +# read by Django +urlpatterns = urlpatterns + evennia_admin_urlpatterns diff --git a/cwopamud/web/api/__init__.py b/cwopamud/web/api/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/cwopamud/web/static/README.md b/cwopamud/web/static/README.md new file mode 100644 index 0000000..21ecfab --- /dev/null +++ b/cwopamud/web/static/README.md @@ -0,0 +1,17 @@ +## Static files + +This is the place to put static resources you want to serve from the +Evennia server. This is usually CSS and Javascript files but you _could_ also +serve other media like images, videos and music files from here. + +> If you serve a lot of large files (especially videos) you will see a lot +> better performance doing so from a separate dedicated media host. + +You can also override default Evennia files from here. The original files are +found in `evennia/web/static/`. Copy the original file into the same +corresponding location/sublocation in this folder (such as website CSS files +into `mygame/static/website/css/`) and modify it, then reload the server. + +Note that all static resources will be collected from all over Evennia into +`mygame/server/.static` for serving by the webserver. That folder should not be +modified manually. diff --git a/cwopamud/web/static/rest_framework/css/README.md b/cwopamud/web/static/rest_framework/css/README.md new file mode 100644 index 0000000..39a0904 --- /dev/null +++ b/cwopamud/web/static/rest_framework/css/README.md @@ -0,0 +1,3 @@ +# Evennia API static files + +Overrides for API files. diff --git a/cwopamud/web/static/rest_framework/images/README.md b/cwopamud/web/static/rest_framework/images/README.md new file mode 100644 index 0000000..3447f3f --- /dev/null +++ b/cwopamud/web/static/rest_framework/images/README.md @@ -0,0 +1,3 @@ +# Static files for API + +Override images here. diff --git a/cwopamud/web/static/webclient/css/README.md b/cwopamud/web/static/webclient/css/README.md new file mode 100644 index 0000000..6ab7cbb --- /dev/null +++ b/cwopamud/web/static/webclient/css/README.md @@ -0,0 +1,3 @@ +You can replace the CSS files for Evennia's webclient here. + +You can find the original files in `evennia/web/static/webclient/css/` diff --git a/cwopamud/web/static/webclient/js/README.md b/cwopamud/web/static/webclient/js/README.md new file mode 100644 index 0000000..c785cb1 --- /dev/null +++ b/cwopamud/web/static/webclient/js/README.md @@ -0,0 +1,3 @@ +You can replace the javascript files for Evennia's webclient page here. + +You can find the original files in `evennia/web/static/webclient/js/` diff --git a/cwopamud/web/static/website/css/README.md b/cwopamud/web/static/website/css/README.md new file mode 100644 index 0000000..004fcd8 --- /dev/null +++ b/cwopamud/web/static/website/css/README.md @@ -0,0 +1,3 @@ +You can replace the CSS files for Evennia's homepage here. + +You can find the original files in `evennia/web/static/website/css/` diff --git a/cwopamud/web/static/website/images/README.md b/cwopamud/web/static/website/images/README.md new file mode 100644 index 0000000..2d2060c --- /dev/null +++ b/cwopamud/web/static/website/images/README.md @@ -0,0 +1,3 @@ +You can replace the image files for Evennia's home page here. + +You can find the original files in `evennia/web/static/website/images/` diff --git a/cwopamud/web/templates/README.md b/cwopamud/web/templates/README.md new file mode 100644 index 0000000..44e9d30 --- /dev/null +++ b/cwopamud/web/templates/README.md @@ -0,0 +1,14 @@ +# HTML templates + +Templates are HTML files that (usually) have special `{{ ... }}` template +markers in them to allow Evennia/Django to insert dynamic content in a web +page. An example is listing how many users are currently online in the game. + +Templates are referenced by _views_ - Python functions or callable classes that +prepare the data needed by the template and 'renders' them into a finished +HTML page to return to the user. + +You can replace Evennia's default templates by overriding them in this folder. +The originals are in `evennia/web/templates/` - just copy the template into the +corresponding location here (so the website's `index.html` should be copied to +`website/index.html` where it can be modified). Reload the server to see your changes. diff --git a/cwopamud/web/templates/rest_framework/README.md b/cwopamud/web/templates/rest_framework/README.md new file mode 100644 index 0000000..072d978 --- /dev/null +++ b/cwopamud/web/templates/rest_framework/README.md @@ -0,0 +1,3 @@ +# Templates for the Evennia API + +Override templates here. diff --git a/cwopamud/web/templates/webclient/README.md b/cwopamud/web/templates/webclient/README.md new file mode 100644 index 0000000..b8fc5a5 --- /dev/null +++ b/cwopamud/web/templates/webclient/README.md @@ -0,0 +1,4 @@ +Replace Evennia's webclient django template with your own here. + +You can find the original files in `evennia/web/templates/webclient/`. Just copy +the original here and modify - after a reload the new template will be used. diff --git a/cwopamud/web/templates/website/README.md b/cwopamud/web/templates/website/README.md new file mode 100644 index 0000000..d3de169 --- /dev/null +++ b/cwopamud/web/templates/website/README.md @@ -0,0 +1,5 @@ +You can replace the django templates (html files) for the website +here. + +You can find the original files under `evennia/web/templates/website/`. Just +copy a template here and modify to have it override the default. diff --git a/cwopamud/web/templates/website/flatpages/README.md b/cwopamud/web/templates/website/flatpages/README.md new file mode 100644 index 0000000..9cd8142 --- /dev/null +++ b/cwopamud/web/templates/website/flatpages/README.md @@ -0,0 +1,3 @@ +Flatpages require a default.html template, which can be overwritten by placing it in this folder. + +You can find the original files in `evennia/web/website/templates/website/flatpages/` diff --git a/cwopamud/web/templates/website/registration/README.md b/cwopamud/web/templates/website/registration/README.md new file mode 100644 index 0000000..7c0dfbe --- /dev/null +++ b/cwopamud/web/templates/website/registration/README.md @@ -0,0 +1,3 @@ +The templates involving login/logout can be overwritten here. + +You can find the original files in `evennia/web/website/templates/website/registration/` diff --git a/cwopamud/web/urls.py b/cwopamud/web/urls.py new file mode 100644 index 0000000..3f30640 --- /dev/null +++ b/cwopamud/web/urls.py @@ -0,0 +1,34 @@ +""" +This is the starting point when a user enters a url in their web browser. + +The urls is matched (by regex) and mapped to a 'view' - a Python function or +callable class that in turn (usually) makes use of a 'template' (a html file +with slots that can be replaced by dynamic content) in order to render a HTML +page to show the user. + +This file includes the urls in website, webclient and admin. To override you +should modify urls.py in those sub directories. + +Search the Django documentation for "URL dispatcher" for more help. + +""" + +from django.urls import include, path + +# default evennia patterns +from evennia.web.urls import urlpatterns as evennia_default_urlpatterns + +# add patterns +urlpatterns = [ + # website + path("", include("web.website.urls")), + # webclient + path("webclient/", include("web.webclient.urls")), + # web admin + path("admin/", include("web.admin.urls")), + # add any extra urls here: + # path("mypath/", include("path.to.my.urls.file")), +] + +# 'urlpatterns' must be named such for Django to find it. +urlpatterns = urlpatterns + evennia_default_urlpatterns diff --git a/cwopamud/web/webclient/README.md b/cwopamud/web/webclient/README.md new file mode 100644 index 0000000..b20aa62 --- /dev/null +++ b/cwopamud/web/webclient/README.md @@ -0,0 +1,23 @@ +# Webclient Views + +The webclient is mainly controlled by Javascript directly in the browser, so +you usually customize it via `mygame/web/static/webclient/js/` - files instead. + +There is very little you can change from here, unless you want to implement +your very own client from scratch. + +## On views + +A 'view' is python code (a function or callable class) responsible for +producing a HTML page for a user to view in response for going to a given URL +in their browser. In Evennia lingo, it's similar in function to a Command, with +the input/args being the URL/request and the output being a new web-page. + +The urls.py file contains regular expressions that are run against the provided +URL - when a match is found, the execution is passed to a view which is then +responsible (usually) for producing the web page by filling in a _template_ - a +HTML document that can have special tags in it that are replaced for dynamic +content. It then returns the finished HTML page for the user to view. + +See the [Django docs on Views](https://docs.djangoproject.com/en/4.1/topics/http/views/) for +more information. diff --git a/cwopamud/web/webclient/__init__.py b/cwopamud/web/webclient/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/cwopamud/web/webclient/urls.py b/cwopamud/web/webclient/urls.py new file mode 100644 index 0000000..2ddc509 --- /dev/null +++ b/cwopamud/web/webclient/urls.py @@ -0,0 +1,20 @@ +""" +This reroutes from an URL to a python view-function/class. + +The main web/urls.py includes these routes for all urls starting with `webclient/` +(the `webclient/` part should not be included again here). + +""" + +from django.urls import path + +from evennia.web.webclient.urls import urlpatterns as evennia_webclient_urlpatterns + +# add patterns here +urlpatterns = [ + # path("url-pattern", imported_python_view), + # path("url-pattern", imported_python_view), +] + +# read by Django +urlpatterns = urlpatterns + evennia_webclient_urlpatterns diff --git a/cwopamud/web/website/README.md b/cwopamud/web/website/README.md new file mode 100644 index 0000000..1bbd5de --- /dev/null +++ b/cwopamud/web/website/README.md @@ -0,0 +1,24 @@ +# Website views and other code + +A 'view' is python code (a function or callable class) responsible for +producing a HTML page for a user to view in response for going to a given URL +in their browser. In Evennia lingo, it's similar in function to a Command, with +the input/args being the URL/request and the output being a new web-page. + +The urls.py file contains regular expressions that are run against the provided +URL - when a match is found, the execution is passed to a view which is then +responsible (usually) for producing the web page by filling in a _template_ - a +HTML document that can have special tags in it that are replaced for dynamic +content. It then returns the finished HTML page for the user to view. + +See the [Django docs on Views](https://docs.djangoproject.com/en/4.1/topics/http/views/) for +more information. + +## Overriding a view + +1. Copy the original code you want to change from `evennia/web/website/views/` into +`mygame/web/website/views/` and edit it as you like. +2. Look at `evennia/web/website/urls.py` and find the regex pointing to the view. Add this regex +to your own `mygam/website/urls.pye` but change it to import and point to your +changed version instead. +3. Reload the server and the page now uses your version of the view. diff --git a/cwopamud/web/website/__init__.py b/cwopamud/web/website/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/cwopamud/web/website/urls.py b/cwopamud/web/website/urls.py new file mode 100644 index 0000000..0bffc16 --- /dev/null +++ b/cwopamud/web/website/urls.py @@ -0,0 +1,20 @@ +""" +This reroutes from an URL to a python view-function/class. + +The main web/urls.py includes these routes for all urls (the root of the url) +so it can reroute to all website pages. + +""" + +from django.urls import path + +from evennia.web.website.urls import urlpatterns as evennia_website_urlpatterns + +# add patterns here +urlpatterns = [ + # path("url-pattern", imported_python_view), + # path("url-pattern", imported_python_view), +] + +# read by Django +urlpatterns = urlpatterns + evennia_website_urlpatterns diff --git a/cwopamud/web/website/views/__init__.py b/cwopamud/web/website/views/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/cwopamud/world/README.md b/cwopamud/world/README.md new file mode 100644 index 0000000..0e4a2fe --- /dev/null +++ b/cwopamud/world/README.md @@ -0,0 +1,10 @@ +# world/ + +This folder is meant as a miscellaneous folder for all that other stuff +related to the game. Code which are not commands or typeclasses go +here, like custom economy systems, combat code, batch-files etc. + +You can restructure and even rename this folder as best fits your +sense of organisation. Just remember that if you add new sub +directories, you must add (optionally empty) `__init__.py` files in +them for Python to be able to find the modules within. diff --git a/cwopamud/world/__init__.py b/cwopamud/world/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/cwopamud/world/batch_cmds.ev b/cwopamud/world/batch_cmds.ev new file mode 100644 index 0000000..ff5469e --- /dev/null +++ b/cwopamud/world/batch_cmds.ev @@ -0,0 +1,26 @@ +# +# A batch-command file is a way to build a game world +# in a programmatic way, by placing a sequence of +# build commands after one another. This allows for +# using a real text editor to edit e.g. descriptions +# rather than entering text on the command line. +# +# A batch-command file is loaded with @batchprocess in-game: +# +# @batchprocess[/interactive] tutorial_examples.batch_cmds +# +# A # as the first symbol on a line begins a comment and +# marks the end of a previous command definition. This is important, +# - every command must be separated by at least one line of comment. +# +# All supplied commands are given as normal, on their own line +# and accept arguments in any format up until the first next +# comment line begins. Extra whitespace is removed; an empty +# line in a command definition translates into a newline. +# +# See `evennia/contrib/tutorial_examples/batch_cmds.ev` for +# an example of a batch-command code. See also the batch-code +# system for loading python-code this way. +# + + diff --git a/cwopamud/world/help_entries.py b/cwopamud/world/help_entries.py new file mode 100644 index 0000000..88460b6 --- /dev/null +++ b/cwopamud/world/help_entries.py @@ -0,0 +1,58 @@ +""" +File-based help entries. These complements command-based help and help entries +added in the database using the `sethelp` command in-game. + +Control where Evennia reads these entries with `settings.FILE_HELP_ENTRY_MODULES`, +which is a list of python-paths to modules to read. + +A module like this should hold a global `HELP_ENTRY_DICTS` list, containing +dicts that each represent a help entry. If no `HELP_ENTRY_DICTS` variable is +given, all top-level variables that are dicts in the module are read as help +entries. + +Each dict is on the form +:: + + {'key': , + 'text': }`` # the actual help text. Can contain # subtopic sections + 'category': , # optional, otherwise settings.DEFAULT_HELP_CATEGORY + 'aliases': , # optional + 'locks': # optional, 'view' controls seeing in help index, 'read' + # if the entry can be read. If 'view' is unset, + # 'read' is used for the index. If unset, everyone + # can read/view the entry. + +""" + +HELP_ENTRY_DICTS = [ + { + "key": "evennia", + "aliases": ["ev"], + "category": "General", + "locks": "read:perm(Developer)", + "text": """ + Evennia is a MU-game server and framework written in Python. You can read more + on https://www.evennia.com. + + # subtopics + + ## Installation + + You'll find installation instructions on https://www.evennia.com. + + ## Community + + There are many ways to get help and communicate with other devs! + + ### Discussions + + The Discussions forum is found at https://github.com/evennia/evennia/discussions. + + ### Discord + + There is also a discord channel for chatting - connect using the + following link: https://discord.gg/AJJpcRUhtF + + """, + }, +] diff --git a/cwopamud/world/prototypes.py b/cwopamud/world/prototypes.py new file mode 100644 index 0000000..8a05ed5 --- /dev/null +++ b/cwopamud/world/prototypes.py @@ -0,0 +1,90 @@ +""" +Prototypes + +A prototype is a simple way to create individualized instances of a +given typeclass. It is dictionary with specific key names. + +For example, you might have a Sword typeclass that implements everything a +Sword would need to do. The only difference between different individual Swords +would be their key, description and some Attributes. The Prototype system +allows to create a range of such Swords with only minor variations. Prototypes +can also inherit and combine together to form entire hierarchies (such as +giving all Sabres and all Broadswords some common properties). Note that bigger +variations, such as custom commands or functionality belong in a hierarchy of +typeclasses instead. + +A prototype can either be a dictionary placed into a global variable in a +python module (a 'module-prototype') or stored in the database as a dict on a +special Script (a db-prototype). The former can be created just by adding dicts +to modules Evennia looks at for prototypes, the latter is easiest created +in-game via the `olc` command/menu. + +Prototypes are read and used to create new objects with the `spawn` command +or directly via `evennia.spawn` or the full path `evennia.prototypes.spawner.spawn`. + +A prototype dictionary have the following keywords: + +Possible keywords are: +- `prototype_key` - the name of the prototype. This is required for db-prototypes, + for module-prototypes, the global variable name of the dict is used instead +- `prototype_parent` - string pointing to parent prototype if any. Prototype inherits + in a similar way as classes, with children overriding values in their parents. +- `key` - string, the main object identifier. +- `typeclass` - string, if not set, will use `settings.BASE_OBJECT_TYPECLASS`. +- `location` - this should be a valid object or #dbref. +- `home` - valid object or #dbref. +- `destination` - only valid for exits (object or #dbref). +- `permissions` - string or list of permission strings. +- `locks` - a lock-string to use for the spawned object. +- `aliases` - string or list of strings. +- `attrs` - Attributes, expressed as a list of tuples on the form `(attrname, value)`, + `(attrname, value, category)`, or `(attrname, value, category, locks)`. If using one + of the shorter forms, defaults are used for the rest. +- `tags` - Tags, as a list of tuples `(tag,)`, `(tag, category)` or `(tag, category, data)`. +- Any other keywords are interpreted as Attributes with no category or lock. + These will internally be added to `attrs` (equivalent to `(attrname, value)`. + +See the `spawn` command and `evennia.prototypes.spawner.spawn` for more info. + +""" + +## example of module-based prototypes using +## the variable name as `prototype_key` and +## simple Attributes + +# from random import randint +# +# GOBLIN = { +# "key": "goblin grunt", +# "health": lambda: randint(20,30), +# "resists": ["cold", "poison"], +# "attacks": ["fists"], +# "weaknesses": ["fire", "light"], +# "tags": = [("greenskin", "monster"), ("humanoid", "monster")] +# } +# +# GOBLIN_WIZARD = { +# "prototype_parent": "GOBLIN", +# "key": "goblin wizard", +# "spells": ["fire ball", "lighting bolt"] +# } +# +# GOBLIN_ARCHER = { +# "prototype_parent": "GOBLIN", +# "key": "goblin archer", +# "attacks": ["short bow"] +# } +# +# This is an example of a prototype without a prototype +# (nor key) of its own, so it should normally only be +# used as a mix-in, as in the example of the goblin +# archwizard below. +# ARCHWIZARD_MIXIN = { +# "attacks": ["archwizard staff"], +# "spells": ["greater fire ball", "greater lighting"] +# } +# +# GOBLIN_ARCHWIZARD = { +# "key": "goblin archwizard", +# "prototype_parent" : ("GOBLIN_WIZARD", "ARCHWIZARD_MIXIN") +# }