Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- # x is rank x/x with x points. x/x with x% (x/x) tricks completed
- # x completed x in x.6d seconds going x mph!
- import es
- import os
- import time
- import psyco
- import cfglib
- import sqlite3
- import vecmath
- import usermsg
- import langlib
- import popuplib
- import effectlib
- import playerlib
- import gamethread
- import collections
- class SQLiteManager(object):
- """
- This class manages all database connections. The main idea of this object
- is to create an easy interface so we can easilly and safely query values
- from a database witout worrying about convulent and complex sqlite syntax.
- This interface allows us to safely call and remove objects from the database
- so that users do not have to access the database directly, but through
- a simple API structure.
- We should only have one database instance so it is unnecesarry to create
- another object to hold the instances of this object.
- """
- players = []
- def __init__(self, path):
- """
- Default Constructor
- Initialize all the default values and open a connection with the SQLite
- database. Create the tables if they don't exist.
- @PARAM path - the absolute path of the database
- """
- self.path = path
- self.connection = sqlite3.connect(path)
- self.connection.text_factory = str
- self.cursor = self.connection.cursor()
- self.cursor.execute('PRAGMA journal_mode=OFF')
- self.cursor.execute('PRAGMA locking_mode=EXCLUSIVE')
- self.cursor.execute('PRAGMA synchronous=OFF')
- self.cursor.execute("""\CREATE TABLE IF NOT EXISTS Player (...)""")
- def __del__(self):
- """
- Default deconstructor.
- Executed when a database instance is destroyed. Ensure that the database
- is saved and closed.
- """
- self.save()
- self.close()
- def __contains__(self, key):
- """
- Executed automatically when we attempt to test to see if an element exists
- within the database.
- @PARAM key - The value to test for validity
- @RETURN boolean - Whether or not the value exists
- """
- key = str(key)
- if key in self.players:
- return True
- self.execute('SELECT UserID FROM Player WHERE steamid=?', key)
- result = self.cursor.fetchone()
- if bool(result):
- self.players.append(key)
- return True
- return False
- def __iter__(self):
- """
- Executed automatically when we attempt to iterate through an instance
- of this class. Query all the steamids from the playerstats table and
- yield each steamid as a seperate object.
- @RETURN yield object - string objects which represent player's steamids
- """
- self.execute('SELECT ... FROM Player')
- self.cursor.fetchall().itervalues()
- def execute(self, parseString, *args):
- """
- A wrapper function to simulate the execute() method of a cursor object.
- @PARAM parseString - the string query line of a SQLite statement
- """
- self.cursor.execute(parseString, args)
- def addPlayer(self, steamid, name):
- """
- Add a player to the database and ensure that they exist within the
- playerstats table as well as the playerskills table.
- @PARAM steamid - the string value of a players steamid
- @PARAM name - the string value of a players name
- """
- self.execute('INSERT INTO Player (...) VALUES (...)',)
- return self.cursor.lastrowid
- def getUserIdFromSteamId(self, steamId):
- """
- Return the UserID auto increment value from a given steamid
- @PARAM steamId - the steamid of the player
- @RETURN INTEGER - the row, if the user doesn't exist, then return None
- """
- self.execute('SELECT UserID FROM Player WHERE steamid=?', steamId)
- value = self.cursor.fetchone()
- if value is None:
- return None
- return value[0]
- def getPlayerInfo(self, userid, infoType):
- """
- Returns a players attribute from the playerstats table.
- @PARAM userid - the integer userid of the player your wish to check
- @PARAM infoType - the column name of the value you wish to return
- @RETURN object - returns an object type of the value to which statType returns
- """
- if not isinstance(userid, int):
- userid = self.getUserIdFromSteamId(userid)
- infoType = str(infoType).replace("'", "''")
- if hasattr(infoType, "__len__"):
- query = "SELECT " + ",".join(map(str, infoType)) + " FROM Player WHERE UserID=?"
- else:
- query = "SELECT " + str(infoType) + " FROM Player WHERE UserID=?"
- self.execute(query, userid)
- return self.fetchone()
- def update(self, table, primaryKeyName, primaryKeyValue, options):
- """
- Sets certain values to a new amount referenced by a table, primary key
- and primary key value
- @PARAM table - the table of which this should take place
- @PARAM primaryKeyName - the name of the key you wish to test for equality
- @PARAM primaryKeyValue - the options to update where the primaryKeyName's value equates to this value
- @PARAM option - dictionary of values, the key is the row to update, the value is the new amount to set the value to
- """
- keys = ""
- if not isinstance(options, dict):
- raise ValueError, "Expected 'options' argument to be a dictionary, instead received: %s" % type(options).__name__
- if options:
- for key, value in options.iteritems():
- if isinstance(key, str):
- key = key.replace("'", "''")
- if isinstance(value, str):
- value = value.replace("'", "''")
- keys += "%s='%s'," % (key, value)
- keys = keys[:-1]
- query = "UPDATE " + str(table) + " SET " + keys + " WHERE " + str(primaryKeyName) + "='" + str(primaryKeyValue) + "'"
- self.execute(query)
- def increment(self, table, primaryKeyName, primaryKeyValue, options):
- """
- Increments certain values by a positive amount referenced by a
- table, primary key and primary key value
- @PARAM table - the table of which this increment should take place
- @PARAM primaryKeyName - the name of the key you wish to test for equality
- @PARAM primaryKeyValue - the options to update where the primaryKeyName's value equates to this value
- @PARAM option - dictionary of values, the key is the row to update, the value is the amount to increment the current value by
- """
- keys = ''
- if not isinstance(options, dict):
- raise ValueError, "Expected 'options' argument to be a dictionary, instead received: %s" % type(options).__name__
- for key, value in options.iteritems():
- if isinstance(key, str):
- key = key.replace("'", "''")
- if isinstance(value, str):
- value = value.replace("'", "''")
- keys += "%s=%s+%i," % (key, key, value)
- keys = keys[:-1]
- self.execute('UPDATE ? SET %s WHERE ?=?+?' % keys, table, primaryKeyName, primaryKeyName, primaryKeyValue)
- def query(self, table, primaryKeyName, primaryKeyValue, options):
- """
- Queries results from the table for one person and returns either a
- tuple or a single value depending on the amount of values passed.
- @PARAM table - the table of which this query should take place
- @PARAM primaryKeyName - the name of the key you wish to test for equality
- @PARAM primaryKeyValue - the options to update where the primaryKeyName's value equates to this value
- @PARAM options - either a single value or a tuple which we will get the values of
- """
- if hasattr(options, '__len__'):
- query = "SELECT " + ",".join(map(lambda x: str(x).replace("'", "''"), options)) + " FROM " + table \
- + " WHERE " + primaryKeyName + "='" + primaryKeyValue + "'"
- else:
- query = "SELECT " + str(options).replace("'", "''") + " FROM " + table + \
- " WHERE " + primaryKeyName + "='" + primaryKeyValue + "'"
- self.execute(query)
- return self.fetchone()
- def fetchall(self):
- """
- Mimics the sqlite fetchall method which recides within a cursor object.
- Ensures that the true values are added to a list so that we don't need
- to index it if the value is only one item in length (e.g. item instead
- of (item,)...)
- @RETURN list - attributes from which the query returned
- """
- trueValues = []
- for value in self.cursor.fetchall():
- if isinstance(value, tuple):
- if len(value) > 1:
- tempValues = []
- for tempValue in value:
- if isinstance(tempValue, long):
- tempValue = int(tempValue)
- tempValues.append(tempValue)
- trueValues.append(tempValues)
- else:
- if isinstance(value[0], long):
- trueValues.append(int(value[0]))
- else:
- trueValues.append(value[0])
- else:
- if isinstance(value, long):
- value = int(value)
- trueValues.append(value)
- return trueValues
- def fetchone(self):
- """
- Mimics the sqlite fetchone method which recides within a cursor object.
- Ensures that a single value is returned from the cursor object if only
- one object exists within the tuple from the query, otherwise it returns
- the query result
- @RETURN Object - the result from the query command
- """
- result = self.cursor.fetchone()
- if hasattr(result, '__iter__'):
- if len(result) == 1:
- trueResults = result[0]
- if isinstance(trueResults, long):
- trueResults = int(trueResults)
- return trueResults
- else:
- trueResults = []
- for trueResult in result:
- if isinstance(trueResult, long):
- trueResult = int(trueResult)
- trueResults.append(trueResult)
- return trueResults
- if isinstance(result, long):
- result = int(result)
- return result
- def save(self):
- """
- Commits the database to harddrive so that we can load it if the server
- closes.
- """
- if self.path != ':memory:':
- self.connection.commit()
- def close(self):
- """
- Closes the connections so that no further queries can be made.
- """
- self.cursor.close()
- self.connection.close()
- class PlayerManager(object):
- """
- This class is used to manage players. This class itself simulates a
- dictionary but gives additional functions which allow us to modify the way
- the singelton is perceived. This will store individual Player objects by a
- tag name and allows us to reference the singleton object by dictionary item
- assignment / retrieval to retrieve the retrespective player object.
- """
- def __init__(self):
- """ Default constructor, initialize variables """
- self.players = {}
- def __getitem__(self, userid):
- """
- Executed when object[x] is executed on the singleton. As we wish to
- simulate dictionary attributes, we want to return the player object
- referenced by their userid
- @PARAM int|str userid - The ID of the user we wish to return the Player object
- @RETURN Player - The Player object referenced by ID
- """
- return self.players[userid]
- def __iter__(self):
- """
- This function executes automatically when "for x in object" is executed.
- We want to return all the player objects inside the player dictionary.
- @RETURN generator - A generator to a list of all the player objects
- """
- return self.players.itervalues()
- def __contains__(self, userid):
- """
- Executed automatically when we use the syntax "x in object". We will
- test if the userid in question exists within the players dictionary.
- @PARAM int|str userid - The userid to test for validation
- @RETURN boolean - Whether or not the userid already exists
- """
- return userid in self.players
- def __delitem__(self, userid):
- """
- Removes the player and object from memory so the RAM is cleared.
- object.removePlayer(userid) == object.__delitem__(userid)
- @PARAM int|str userid - The userid of the player to remove
- """
- self.removePlayer(userid)
- def addPlayer(self, userid):
- """
- Add the player into memory as an Player object
- @PARAM int|str userid - The userid of the player to add
- """
- self.players[userid] = Player(userid)
- def removePlayer(self, userid):
- """
- Removes the player and object from memory
- @PARAM int|str userid - The userid of the player to remove
- """
- if userid in self.players:
- del self.players[userid]
- class PlayerObject(object):
- """
- This is an object which will revolve around all active players. This should
- contain all relevant information about a particular player, and cache all
- their details so we don't need to query the database at regular intervals.
- """
- cache = None
- userid = None
- def __init__(self, userid):
- """"
- Default constructor, initialize variables
- Set up all necessary objects and cache values here.
- @PARAM int|str userid - The ID of the user who this object references
- """
- self.userid = int(userid)
- self.cache = PlayerCache(self.userid)
- def __getattr__(self, attribute):
- """
- This object will allow us to get attributes from the cache object
- @PARAM str attribute - The attribute of the PlayerCache we want to
- @RETURN str attribute - The attribute if it he exist
- """
- if hasattr(self.cache, attribute):
- return getattr(self.cache, attribute)
- raise AttributeError('Player object has no attribute %s' % attribute)
- def __setattr__(self, attribute, value):
- """
- This object will allow us to reassing values in the PlayerCache object
- @PARAM str attribute - The attribute to change
- @PARAM int|str value - The value to set to the attribute
- @RETURN mixed attribute - setattr object if cache has attribute
- """
- if hasattr(self.cache, attribute):
- return setattr(self.cache, attribute, value)
- object.__setattr__(attribute, value)
- class PlayerCache(object):
- """
- This object should be used by each player and should store all relevant
- information regarding their current stats. Each time he make a trick, if the
- information has not already been querieid, query it and cache it. Only
- refresh if explicitly told to; we never need to refresh on ticks. This means
- we can reduce the amount of DB queries we need which improves read time and
- efficiency.
- """
- def __init__(self, userid):
- """"
- Default constructor, initialize variables
- @PARAM str|int userid - The ID of the user on the server
- """
- self.userid = userid
- self.steamid = playerlib.uniqueid(self.userid, True)
- self.update()
- def update(self):
- """
- This method simply refreshes the local attributes
- with the attributes from the dictionnary.
- """
- database.query('SELECT name, tricks FROM player WHERE steamid=?', self.steamid)
- name, tricks = database.fetchone()
- self.oldName = self.name = name
- self.tricks = self.oldTricks = tricks
- def commit(self):
- """
- This method should commit the local attributes to the database
- only if the local values have been altered.
- """
- if self.name != self.oldName or self.tricks != self.oldTricks:
- database.query('UPDATE player SET name=?, tricks=? WHERE steamid=?', (self.name, self.tricks, self.steamid))
- self.oldName = self.name
- self.oldTricks = self.tricks
- class PopupManager(object):
- ...
- class MessageManager(object):
- ...
- class HUDHintManager(object):
- """
- This class will be used for HUDS management
- """
- def __init__(self):
- """ Default constructor, initialize variables """
- self._name = '%s(%s)' % (self.__class__.__name__, id(self))
- self.players = {}
- self._refresh()
- def stop(self):
- """ Static method for stop all delays """
- gamethread.cancelDelayed(self._name)
- self.players.clear()
- def addLine(self, player, line, timeout=10):
- """
- Add a line to the HUD of a player
- @PARAM player - UserID of the player
- @PARAM line - Line to add
- @PARAM timeout - The time after the line is deleted, 10 by default
- """
- if player not in self.players:
- self.players[player] = collections.deque([], 10)
- self.players[player].append(line)
- gamethread.delayedname(timeout if timeout < 30 else 10, self._name, self.removeLine, (player, line))
- def removeLine(self, player, line):
- """
- Remove a line to the HUD of a player
- @PARAM player - UserID of the player
- @PARAM line - Line to remove
- """
- if line in self.players[player]:
- self.players[player].remove(line)
- if not len(self.players[player]):
- del self.players[player]
- def _refresh(self):
- """ Class method only, used to auto-refresh the HUDs """
- for player in self.players:
- if len(self.players[player]):
- usermsg.hudhint(player, '\n'.join(self.players[player])
- gamethread.delayedname(1, self._name, self._refresh)
- class Trigger(object):
- """
- This is an object which will revolve around all triggers. This should
- contain all relevant information about a particular trigger
- """
- trigger = None
- def __init__(self, trigger, coords):
- self.trigger = trigger
- self.coords = coords
- class TriggerManager(object):
- """
- This class is used to manage triggers.
- This will store individual Trigger objects by a tag name
- and allows us to reference the singleton object
- """
- def __init__(self, path):
- """
- Default constructor, initialize variables
- @PARAM str path - Path of the file who contains triggers
- """
- self.triggers = {}
- self.triggersC = cfglib.AddonINI(path)
- def __getitem__(self, trigger):
- """
- Executed when object[x] is executed on the singleton.
- @PARAM str trigger - The trigger name we wish to return the Trigger object
- @RETURN Trigger - The Trigger object referenced by name
- """
- return self.triggers[trigger]
- def __iter__(self):
- """
- This function executes automatically when "for x in object" is executed.
- @RETURN generator - A generator to a list of all the player objects
- """
- return self.triggers.itervalues()
- def __contains__(self, trigger):
- """
- Executed automatically when we use the syntax "x in object".
- @PARAM str trigger - The trigger to test for validation
- @RETURN boolean - Whether or not the trigger already exists
- """
- return trigger in self.triggers
- def __delitem__(self, userid):
- """
- Removes the trigger and object from memory so the RAM is cleared.
- object.removeTrigger(userid) == object.__delitem__(userid)
- @PARAM str trigger - The trigger to remove
- """
- self.removeTrigger(trigger)
- def addTrigger(self, trigger, *coords):
- """
- Add the trigger into memory as an Trigger object
- @PARAM str trigger - The trigger to add
- @PARAM list coords - List of points of the trigger
- """
- self.triggers[trigger] = Trigger(trigger, coords[0])
- if not triggersC.has_key(trigger):
- self.triggersC.addGroup(trigger)
- for x in xrange(len(coords[0])):
- self.triggersC.addValueToGroup(trigger, x, coords[0][x], True)
- self.triggersC.write()
- def removeTrigger(self, trigger):
- """
- Removes the trigger and object from memory
- @PARAM str userid - The trigger to remove
- """
- if trigger in self.triggers:
- del self.triggers[trigger]
- del self.triggersC[trigger]
- self.triggersC.write()
- class Trick(object):
- ...
- class TrickManager(object):
- ...
- database = SQLiteManager(databasePath)
- players = PlayerManager()
- popups = PopupManager()
- messages = MessageManager()
- huds = HUDHintManager()
- triggers = TriggerManager(triggersPath)
- tricks = TrickManager(tricksPath)
- """
- players.addPlayer(2) # Add a player
- players[2].userid # we can access PlayerObject attributes
- players[2].tricks # We can also access the cache objects
- players[2].cache.commit() # Commit the cache, update the new values to the DB if they have altered
- players[2].cache.update() # Force a database update, this is done automatically every time a player is created, we shouldn't need to force an update ever
- """
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement