def create_table(model): if model.db_table_name in EXISTING_TABLES: return # check for dependencies dependencies = [ col.foreign_key for col in model.db_columns if col.foreign_key and col.foreign_key[0] != model.db_table_name ] for mod, col in dependencies: M = model_list.get(mod) if not M: raise Exception("Dependency on unknown model: %s" % str(mod)) if M.db_table_name not in EXISTING_TABLES: create_table(M) elif col not in EXISTING_TABLES[M.db_table_name]: add_column(M, col) # generate create table string table_string = [] table_string.append("CREATE TABLE IF NOT EXISTS %s (" % model.db_table_name) columns_string = [] for col in model.db_columns: columns_string.append(str(col)) for extra in model.db_extras: columns_string.append(unicode(extra)) table_string.append(",".join(columns_string)) table_string.append(")") create_stmt = "".join(table_string) cursor = World.get_world().db.conn.cursor() cursor.execute(create_stmt) EXISTING_TABLES[model.db_table_name] = [col.name for col in model.db_columns]
def create_table(model): if model.db_table_name in EXISTING_TABLES: return # check for dependencies dependencies = [ col.foreign_key for col in model.db_columns if col.foreign_key and col.foreign_key[0] != model.db_table_name ] for mod, col in dependencies: M = model_list.get(mod) if not M: raise Exception('Dependency on unknown model: %s' % str(mod)) if M.db_table_name not in EXISTING_TABLES: create_table(M) elif col not in EXISTING_TABLES[M.db_table_name]: add_column(M, col) # generate create table string table_string = [] table_string.append('CREATE TABLE IF NOT EXISTS %s (' % model.db_table_name) columns_string = [] for col in model.db_columns: columns_string.append(str(col)) for extra in model.db_extras: columns_string.append(unicode(extra)) table_string.append(','.join(columns_string)) table_string.append(')') create_stmt = "".join(table_string) cursor = World.get_world().db.conn.cursor() cursor.execute(create_stmt) EXISTING_TABLES[model.db_table_name] = [ col.name for col in model.db_columns ]
def add_column(mod, col): # check for dependencies if mod.db_table_name not in EXISTING_TABLES: create_table(mod) else: if col in EXISTING_TABLES[mod.db_table_name]: return # Column already exists!? column = None for c in mod.db_columns: if c.name == col: column = c break if not column: raise Exception('Trying to create undefined column!') if column.foreign_key: m, c = column.foreign_key M = model_list.get(m) if M.db_table_name not in EXISTING_TABLES: create_table(M) elif c not in EXISTING_TABLES[M.db_table_name]: add_column(M, c) alter_stmt = 'ALTER TABLE %s ADD COLUMN %s' % (mod.db_table_name, str(column)) cursor = World.get_world().db.conn.cursor() cursor.execute(alter_stmt) EXISTING_TABLES[mod.db_table_name].append(col)
def inport_dir(obj_type, format=None, source_path=AREAS_IMPORT_DIR): """Import a batch of area files from a directory. import_list can either be a list of area-names to be imported, or the string 'all'. If the string 'all' is given, import_list will attempt to import all areas in the default import directory. """ world = World.get_world() import_list = [] for filename in os.listdir(source_path): match = NAME_REG.match(filename) if match: fname, ftype, fformat = match.group('name', 'type', 'format') # filter by obj_type if ftype == obj_type: # filter by format (only if format is not None) if format and (format == fformat): import_list.append({'name': fname, 'format': fformat}) elif not format: import_list.append({'name': fname, 'format': fformat}) if not import_list: return "I couldn't find any %ss in %s." % (obj_type, source_path) results = '' for thing in import_list: results += 'Importing %s %s... ' % (obj_type, thing['name']) try: status = inport(obj_type, thing['name'], thing['format'], 'file', source_path) except SportError as e: results += 'Failed: ' + str(e) + '\n' else: results += status + '\n' if not results: return 'No areas were found in %s.\n' % source_path return results
def inport(obj_type, obj_name, format=None, transport=None, source_path=AREAS_IMPORT_DIR): """Import an object (area, player character, etc.) from an outside source into the MUD. obj_type - the type of the object to be imported (area, player, etc.) obj_name - the name of the object to be imported format - the format that the object data is saved in and that should be used decode it transport - the transport that should be used to retrieve the data source_path - extra information for locating an import object """ format = format or DEFAULT_FORMAT transport = transport or DEFAULT_TRANSPORT world = World.get_world() if not hasattr(world, '%s_exists' % obj_type): return 'Invalid type "%s". See "help export".' % obj_type if getattr(world, '%s_exists' % obj_type)(obj_name): return '%s "%s" already exists in your game.' % (obj_type.capitalize(), obj_name) try: #Find format formatter = get_formatter('%s_read_%s' % (obj_type, format)) #find source source = get_transport('load_%s' % transport) # all source-transports take world, the name of the target, and the source path # all read-formaters take the world and shiny_data fname = obj_name + '_' + obj_type + '.' + format message = formatter(world, source(world, fname, source_path)) except SportError as e: message = str(e) return message
def add_column(mod, col): # check for dependencies if mod.db_table_name not in EXISTING_TABLES: create_table(mod) else: if col in EXISTING_TABLES[mod.db_table_name]: return # Column already exists!? column = None for c in mod.db_columns: if c.name == col: column = c break if not column: raise Exception("Trying to create undefined column!") if column.foreign_key: m, c = column.foreign_key M = model_list.get(m) if M.db_table_name not in EXISTING_TABLES: create_table(M) elif c not in EXISTING_TABLES[M.db_table_name]: add_column(M, c) alter_stmt = "ALTER TABLE %s ADD COLUMN %s" % (mod.db_table_name, str(column)) cursor = World.get_world().db.conn.cursor() cursor.execute(alter_stmt) EXISTING_TABLES[mod.db_table_name].append(col)
def export(obj_type, shiny_obj, format=None, transport=None, dest_path=AREAS_EXPORT_DIR): """Export an object from the MUD to an outside source. obj_type - the type of the object to be imported (area, player, etc.) shiny_obj - the shiny object being exported format - the format that the object data should be exported in transport - the transport that should be used to save the data dest_path - extra information for sending/saving the object """ format = format or DEFAULT_FORMAT transport = transport or DEFAULT_TRANSPORT world = World.get_world() try: formatter = get_formatter('%s_write_%s' % (obj_type, format)) #find source dest = get_transport('save_%s' % transport) # all destination transports take world, shiny_data, filename, and destination_path # all write-formatters take a shiny object. fname = shiny_obj.name + '_' + obj_type + '.' + format message = dest(world, formatter(shiny_obj), fname, dest_path) except SportError as e: message = str(e) return message
def build_set_replace(self, replace, player=None): world = World.get_world() if not replace or (replace.strip().lower() == 'none'): self.replace_obj = None self.save() return 'Replace item reset to none.' exp = r'((to)|(with)[ ]?)?(item[ ]+)?(?P<id>\d+)([ ]+from)?([ ]+area)?([ ]+(?P<area_name>\w+))?' match = re.match(exp, replace, re.I) if not match: return 'Try "help food" for help on setting food attributes.' item_id, area_name = match.group('id', 'area_name') if area_name: area = world.get_area(area_name) if not area: return 'Area %s doesn\'t exist.' % area_name elif player: area = player.mode.edit_area else: return 'You need to specify the area that the item is from.' item = area.get_item(item_id) if not item: 'Item %s doesn\'t exist.' % item_id self.replace_obj = item self.save() return '%s will be replaced with %s when consumed.' %\ (self.build_item.name.capitalize(), item.name)
def setUp(self): import sys remove = [m for m in sys.modules.keys() if 'shinymud' in m] for r in remove: del sys.modules[r] from shinymud.lib.world import World self.world = World(':memory:') from shinymud.lib.setup import initialize_database initialize_database()
def roll_to_hit(self): if randint(0,3): loc = self.attacker.location world = World.get_world() self.attacker.go(world.get_location(self.target[0], self.target[1])) self.battle.tell_all(self.attacker.fancy_name() + " ran away!", [self.attacker.name]) self.attacker.mode.active = False self.battle.remove_character(self.attacker) self.attacker.battle = None else: self.attacker.update_output("You try to run, but can't get away!")
def create(cls, area_dict={}): """Create a new area instance and add it to the world's area list.""" world = World.get_world() name = area_dict.get('name') if not name: return "Invalid area name. Areas must have a name." if world.get_area(name): return "This area already exists." new_area = cls(area_dict) new_area.save() world.area_add(new_area) return new_area
def roll_to_hit(self): if randint(0, 3): loc = self.attacker.location world = World.get_world() self.attacker.go(world.get_location(self.target[0], self.target[1])) self.battle.tell_all(self.attacker.fancy_name() + " ran away!", [self.attacker.name]) self.attacker.mode.active = False self.battle.remove_character(self.attacker) self.attacker.battle = None else: self.attacker.update_output("You try to run, but can't get away!")
def __init__(self, args={}): self.obj = args.get('obj') self.script = args.get('script') self.script_text = self.script.body self.probability = args.get('probability') self.args = args self.log = World.get_world().log self.script_cmds = {'record': self.record_player } self.conditions = {'remember': self.remember_player, 'equal': self.equal, 'target_has': self.has_item }
def __init__(self, player): """ player - a Player object that has yet to be playerized (player-initialized) newbie - a new player, which is designated by creating a new player name """ self.player = player self.newbie = False self.state = self.intro self.active = True self.name = 'InitMode' self.world = World.get_world() self.log = self.world.log self.save = {}
class NpcAiPack(Model): log = World.get_world().log """The base class that must be inherited by all ai packs. If you're going to build a new ai pack, the first stop is to inherit from this class and implement its required functions (explained below!). Remember to add your new ai pack to the registry, or else it won't exist in game! Do so by adding this after the ai class: NPC_AI_PACKS = {'<in-game_ai_pack_name>': <class_name>} And this to register it as a model: model_list.register(<class_name>) """ def __init__(self, args={}): """ An AiPack's __init__ function should take a dictionary of keyword arguments which could be empty (if this is a brand new instance), or hold the saved values of your attributes loaded from the database. Your init function should look something like the following: You will probably want your ai pack inherit from a model, which allows for automatic saving and loading of basic attributes. You do this by passing a single line to the Model: Model.__init__(self, args) Now, if your ai has any columns they will be automatically loaded with your ai pack. (See Modles in __init__.py for how to use columns to load data.) """ raise NpcAiTypeInterfaceError( 'You need to implement the init function.') def __str__(self): """Return a string representation of this ai pack to be displayed during BuildMode. To be consistent throughout BuildMode, It should have a heading in all caps, and each of its attributes labeled and indented by two spaces beneath it. The string returned should look something like the following: ITEMTYPE ATTRIBUTES: foo: The value of the foo attribute bar: The value of the bar attribute """ raise NpcAiTypeInterfaceError( 'You need to implement the str function.')
def initialize_database(): world = World.get_world() world.db.conn.cursor().execute("PRAGMA foreign_keys = true") db_table_names = [x["name"] for x in world.db.select("name from sqlite_master where type='table'")] for table_name in db_table_names: columns = world.db.select("* from %s limit 1" % table_name) if columns and len(columns): EXISTING_TABLES[table_name] = columns[0].keys() for mod in model_list.values(): if mod.db_table_name not in EXISTING_TABLES: create_table(mod) for mod in model_list.values(): for col in mod.db_columns: if col.name not in EXISTING_TABLES[mod.db_table_name]: add_column(mod, col.name)
def initialize_database(): world = World.get_world() world.db.conn.cursor().execute('PRAGMA foreign_keys = true') db_table_names = [ x['name'] for x in world.db.select("name from sqlite_master where type='table'") ] for table_name in db_table_names: columns = world.db.select("* from %s limit 1" % table_name) if columns and len(columns): EXISTING_TABLES[table_name] = columns[0].keys() for mod in model_list.values(): if mod.db_table_name not in EXISTING_TABLES: create_table(mod) for mod in model_list.values(): for col in mod.db_columns: if col.name not in EXISTING_TABLES[mod.db_table_name]: add_column(mod, col.name)
def build_set_portal(self, args, player=None): """Set the location of the room this portal should go to.""" if not args: return 'Usage: set portal to room <room-id> in area <area-name>\n' exp = r'([ ]+)?(to)?([ ]+)?(room)?([ ]+)?(?P<room_id>\d+)([ ]+in)?([ ]+area)?([ ]+(?P<area_name>\w+))' match = re.match(exp, args, re.I) if not match: return 'Usage: set portal to room <room-id> in area <area-name>\n' room_id, area_name = match.group('room_id', 'area_name') area = World.get_world().get_area(area_name) if not area: return 'That area doesn\'t exist.\n' room = area.get_room(room_id) if not room: return 'That room doesn\'t exist.\n' #Set location so we don't have to resolve it (for as long as the game runs) self.location = room #Also set these two, so we can resolve the room next time the game starts self.to_room = room_id self.to_area = area_name self.save() return 'This portal now connects to room %s in area %s.\n' % (self.location.id, self.location.area.name)
def build_set_portal(self, args, player=None): """Set the location of the room this portal should go to.""" if not args: return 'Usage: set portal to room <room-id> in area <area-name>\n' exp = r'([ ]+)?(to)?([ ]+)?(room)?([ ]+)?(?P<room_id>\d+)([ ]+in)?([ ]+area)?([ ]+(?P<area_name>\w+))' match = re.match(exp, args, re.I) if not match: return 'Usage: set portal to room <room-id> in area <area-name>\n' room_id, area_name = match.group('room_id', 'area_name') area = World.get_world().get_area(area_name) if not area: return 'That area doesn\'t exist.\n' room = area.get_room(room_id) if not room: return 'That room doesn\'t exist.\n' #Set location so we don't have to resolve it (for as long as the game runs) self.location = room #Also set these two, so we can resolve the room next time the game starts self.to_room = room_id self.to_area = area_name self.save() return 'This portal now connects to room %s in area %s.\n' % ( self.location.id, self.location.area.name)
def setup_stub_world(): world = World() from shinymud.lib.setup import initialize_database initialize_database() return world
from shinymud.lib.world import World # Initialize the World world = World() from shinymud.lib.setup import initialize_database from shinymud.models.area import Area from shinymud.data.config import * from shinymud.lib.connection_handlers import con_handlers import traceback import datetime initialize_database() world.db.delete( 'from game_item where (owner is null or owner=\'None\') and container is null' ) # load the entities in the world from the database # This should probably happen inside the world itself... for area in world.db.select("* from area"): world.area_add(Area.create(area)) for area in world.areas.values(): area.load() world.default_location = world.get_location(DEFAULT_LOCATION[0], DEFAULT_LOCATION[1]) # Start up all of our connection handlers for port, conn_handler in CONNECTIONS: handler_class = getattr(con_handlers, conn_handler) handler_obj = handler_class(port, HOST, world) handler_obj.start()
class ItemType(Model): db_columns = Model.db_columns + [ Column('build_item', type="INTEGER", write=write_model, foreign_key=('build_item', 'dbid'), cascade="ON DELETE"), Column('game_item', type="INTEGER", write=write_model, foreign_key=('game_item', 'dbid'), cascade="ON DELETE") ] log = World.get_world().log """The base class that must be inherited by all item types. If you're going to build a new item type, the first stop is to inherit from this class and implement its required functions (explained below!). """ def load(self, game_item): """The load function makes a copy of a ItemType instance so that it can be attached to a GameItem and loaded in-game. Your load function should look something like the following: # The easiest way to copy the data from this instance is to use the # to_dict function to get a dictionary of all of this item type's # attributes d = self.to_dict() # Delete the previous instance's dbid from the dictionary - we don't # want to save over the old one! if 'dbid' in d: del d['dbid'] # Remove the old build_item reference -- this copy belongs to a game # item if 'build_item' in d: del d['build_item'] d['game_item'] = game_item return Furniture(d) """ raise ItemTypeInterfaceError( 'You need to implement the load function.') def __str__(self): """Return a string representation of this item type to be displayed during BuildMode. To be consistent throughout BuildMode, It should have a heading in all caps, and each of its attributes labeled and indented by two spaces beneath it. The string returned should look something like the following: ITEMTYPE ATTRIBUTES: foo: The value of the foo attribute bar: The value of the bar attribute """ raise ItemTypeInterfaceError('You need to implement the str function.') # **************************************************************************** # THE FUNCTIONS BELOW THIS POINT ARE NOT MEANT TO BE IMPLEMENTED BY SUBCLASSES # **************************************************************************** def _set_build_item(self, val): """This handles setting the build_item attribute. Because bad things happen when an ItemType has both its build_item and its game_item set, we won't allow on to be set if the other exists. THIS FUNCTION SHOULD NOT BE IMPLEMENTED/OVERLOADED BY THE CHILD CLASS. """ if self.game_item: self.log.critical( 'Trying to set build_item when game_item is set!') # raise Exception('Cannot set build_item AND game_item') else: self._build_item = val def _set_game_item(self, val): """This handles setting the game_item attribute. Because bad things happen when an ItemType has both its build_item and its game_item set, we won't allow on to be set if the other exists. THIS FUNCTION SHOULD NOT BE IMPLEMENTED/OVERLOADED BY THE CHILD CLASS. """ if self.build_item: self.log.critical( 'Trying to set game_item when build_item is set!') # raise Exception('Cannot set game_item AND build_item') else: self._game_item = val build_item = property((lambda self: getattr(self, '_build_item', None)), _set_build_item) game_item = property((lambda self: getattr(self, '_game_item', None)), _set_game_item)
def __init__(self, attacker, target, battle): self.attacker = attacker self.target = target self.bonuses = 0 self.battle = battle self.log = World.get_world().log
from shinymud.lib.world import World import json world = World.get_world() def to_bool(val): """Take a string representation of true or false and convert it to a boolean value. Returns a boolean value or None, if no corresponding boolean value exists. """ bool_states = {"true": True, "false": False, "0": False, "1": True} if not val: return None if isinstance(val, bool): return val val = str(val) val = val.strip().lower() return bool_states.get(val) def read_dict(val): # val is a string like "foo=bar,name=fred" # return {'foo':'bar', 'name':'fred'} return dict([thing.split("=") for thing in val.split(",")]) def write_dict(val): return ",".join("=".join([str(k), str(v)]) for k, v in val.items())
class Model(object): """Models are used for saving and loading in-game objects. How you use models: Saving: The first thing you need to do is specify a table name. This tells the database where to put all of the data for this kind of class. Use the statement "db_table_name = <my_model>". Table names MUST be unique to all other model table names, or else bad things will happen. Next, models save data using columns (defined above). Any class attribute you want to save needs to have its own column. The name given to the column will be the name of the attribute when the class is initialized (loaded). If the attribute is anything more complex than a string, you will need to override the read and write functions (some basic ones in shiny_types; you can also write your own). Add the columns to the db list and your objects will save! Example: db_table_name = "sack_of_gold" db_columns.append( Column("owner", primary_key=true), Column("ammount", type="INTEGER", default=20, read=read_int), Column("weight", type="INTEGER", read=read_int) ) NOTE: Many values such as 'read' and 'write' are left out above. You can do this for anything except for the column name, and it will default to the values shown in the Column class. Loading: Dependent models in shinymud load in a parent-child system. That is, an area loads all of its rooms, a room loads all of its npcs, an npc loads its inventory. When a parent model loads a dependent model, it hands the child a huge lump of raw slq data, which the child parses through models. To activate a models super powers of parsing, simply add this line to the init function of your class: Model.__init__(self, args) Where 'args' is a dictionary from the parent. """ world = World.get_world() db_table_name = None db_columns = [ Column('dbid', primary_key=True, null=False, type='INTEGER', read=int, write=int ) ] db_extras = [] def __init__(self, args={}): """Go through each of the columns in our decendent model, and set them as real attributes in our class. If a column doesn't have a name, check if it has default data or a default function. Lastly, if it was loaded (has dbid), load the extras. """ for col in self.db_columns: if args.get(col.name): setattr(self, col.name, col.read(args[col.name])) else: if hasattr(col.default, '__call__'): setattr(self, col.name, col.default()) else: setattr(self, col.name, col.default) if hasattr(self, 'dbid'): if self.dbid: self.load_extras() def load_extras(self): """(For decendent Model) If a Model has anything it needs to load after the columns, it does so here. This is usually to load child models, or anything else which needs to be loaded after the init() stage. This function olny gets called if it is loaded from the database""" pass def copy_save_attrs(self): """ Copy all data in a model, according to its column 'copy' function, and return it. """ copy_dict = {} for col in self.db_columns: val = getattr(self, col.name, col.default) copy_dict[col.name] = col.copy(val) if val else None return copy_dict def create_save_dict(self): """Grab all current data from the current model, getting it ready to be written. This probably never needs to be used anywhere but here.""" save_dict = {} for col in self.db_columns: val = getattr(self, col.name, col.default) save_dict[col.name] = col.write(val) if val else None return save_dict def save(self): """Save model data to the database. This function should be freely used by decendent models to save changes.""" save_dict = self.create_save_dict() if self.dbid: self.world.db.update_from_dict(self.db_table_name, save_dict) else: if 'dbid' in save_dict: del save_dict['dbid'] self.dbid = self.world.db.insert_from_dict(self.db_table_name, save_dict) def destruct(self): if self.dbid: self.world.db.delete('FROM %s WHERE dbid=?' % self.db_table_name, [self.dbid])
from shinymud.lib.world import World # Initialize the World world = World() from shinymud.lib.setup import initialize_database from shinymud.models.area import Area from shinymud.data.config import * from shinymud.lib.connection_handlers import con_handlers import traceback import datetime initialize_database() world.db.delete('from game_item where (owner is null or owner=\'None\') and container is null') # load the entities in the world from the database # This should probably happen inside the world itself... for area in world.db.select("* from area"): world.area_add(Area.create(area)) for area in world.areas.values(): area.load() world.default_location = world.get_location(DEFAULT_LOCATION[0], DEFAULT_LOCATION[1]) # Start up all of our connection handlers for port, conn_handler in CONNECTIONS: handler_class = getattr(con_handlers, conn_handler) handler_obj = handler_class(port, HOST, world) handler_obj.start() world.log.info('Started the connection handlers. Now listening for Players.')
def __init__(self): self.teamA = [] self.teamB = [] self.remove_list = [] self.id = None self.world = World.get_world()