elthran / RPG-Game

0 stars 1 forks source link

Write an event logging module. #363

Open klondikemarlen opened 5 years ago

klondikemarlen commented 5 years ago

This module should be able to be attached to any local game function and should spit out basic data using aprearanged list of codes.

e.g.

@logging.log("login", "account_info", "time")
def login_account(username, password, session):
    ....

Would make a new table record looking like this (paraphased from Elthran): "Login event", "Haldon", "3", current time. When the user selects a hero (after login): This event could have the Hero data added to it (hero gold, hero level, etc.) When they logout this event could have a session length added, and could compute gold spent.

klondikemarlen commented 5 years ago

I need to create a new label for this concept :)

klondikemarlen commented 5 years ago

From Elthran (unedited):

Create a file for 'analytic_events'. They are not related to game states and used for analytics. But they can help us find bugs, check user interest, and stuff. Here is what I have:

class UserActivity(database):
    def __init__(self):
        self.table = None
        self.valid = True
        self.user_status = ['dev', 'normal', 'spam'] # Each account is marked as 'normal' by default. Admin accounts are marked as dev on creation. We can mark suspicious accounts as spam, so we can filter them out when we do analysis
        self.timestamp = Timestamp
        self.version = String # We should record which version of the game they were playing on. It might be unnecessary with timestamps already, but it might also make things clearer. Each time the production branch gets updated it should update the version

    def validate(self):
        """
        Each one needs a specific validation. this is here in parent class so we don't forget to adda validation!
        Note, this might be a class method? Or a class property? What do you think?
        """
        raise NotImplementedError("Implementations must override this!")

    def generate_table_row(self):
        """
        Maybe this can be generic and not needed in child classes?
        """
        raise NotImplementedError("Implementations must override this!")

    def generate_error_row(self):
        # Create a row in table 'errors' with as much info as possible (user, timestamp, etc.)

class AuthenticationActivity(UserActivity):
    """
    A row is generated for every authentication action in the game (account creation, login, logout.
    """
    def __init__(self, event):
        UserActivity.__init__(self)
        self.table = 'authentication'
        self.event = String
        self.username = String
        self.user_id = Integer
        self.hero = ID
        self.account_age = Integer # How many days old the acccount is (0 if it was created today)
        self.session_length = Integer (If event is logout, this is delta time since last activity, else this is null) # ie. how long they were logged in for
        self.user_ip = String # Do we want to get user IP? Can we even get it?
        self.since_previous_session = Integer (If this is login, this is delta time since last activity, else this is null) # ie. how long since they last logged in
        self.money_spent = Integer # We might want to add this here to easily query and compare free/paid users?

    def validate(self):
        self.valid = False if self.event not in ['create', 'login', 'logout']
        self.valid = False if self.timestamp is not valid timestamp
        self.valid = False if (self.session_length is Integer and self.eevnt is not 'logout')
        self.valid = False if user_id is not Integer

    def generate_table_row(self):
        if not self.valid:
            return generate_error_row(self)
        # Create a row in table self.table with each column as the objects of this class

class BattleActivity(UserActivity):
    """
    A row is generated for every battle fought in the entire game.
    """
    def __init__(self, event):
        UserActivity.__init__(self)
        self.battle_type = String # ['battle', 'duel', 'ai', 'training']
        self.rounds = Integer # How many rounds of combat there were
        self.attacker_name = String
        self.attacker_id = Integer
        self.attacker_class = String
        self.attacker_age = Integer # The level of the player
        self.attacker_account_age = Integer # How many days since attacker created their account
        self.attacker_strength = Integer
        # Continue for every attribute, proficiency, item_equipped, ability learned, etc. for both attacker and defender?
        self.win = Boolean # Whether the attacker won
        self.experience_gained = Integer
        self.item1_gained = String
        self.item2_gained = String # Maybe a better way to do this? Its only for analytics. Maybe just do # of items gained or something

    def validate(self):
        Return False if any values are not expected, otherwise true

    def generate_table_row(self):
        if not self.valid:
            return generate_error_row(self)
        # Create a row in table self.table with each column as the objects of this class

class QuestActivity(UserActivity):
    """
    A row is generated for every quest start or completion event
    """
    def __init__(self, event):
        UserActivity.__init__(self)
        self.event = String # ['start', 'complete'] Should either be starting or completing a stage of a quest
        self.quest_name = String
        self.quest_id = Integer
        self.stages_in_parent_quest = integer
        self.current_stage = Integer # The stage you just started or completed.
        self.account_age = Integer # How many days old the account is
        self.experience_gained = Integer

    def validate(self):
        return ...

    def generate_table_row(self):
        if not self.valid:
            return generate_error_row(self)
        # Create a row in table self.table with each column as the objects of this class

class TransactionActivity(UserActivity):
    """
    A row is generated for every transaction in the game (with in game currency or real money). This current method would only allow one currency
    """
    def __init__(self, event):
        UserActivity.__init__(self)
        self.action = String # ['buy', 'sell', 'refund'] if its a refund, then it needs to reference the evetn where they bought something.
        self.currency = String # ['gold', 'money']
        self.country_currency = String # ['None', 'CAD', 'USD'] maybe needed if you want to price things in different currencies. If the transaction was in in-game currency then this should be None or Null
        self.amount = Integer
        self.account_age = Integer # How many days old the account is
        self.refund_link_id = Integer # (-1 for most transactions, but if its a refund then it should be the id of the purchase that is being refunded)
        self.processed = Boolean # True if its complete, False if the process is pending
        self.processing_id = Integer # (-1 for most transactions, but if its a complete for an earlier processing transaction, then the processing transaction id)
        """
        Example. I buy armour for 50 gold. It immediately is processed so processed==True and processing_id==-1. Then I buy a subscription for $10.
        It first creates a purchase event with processed==False and amount==$10. Then after it's processed a second event is created
        with a processed==True, processing_id==(last event's id) and amount==0. If the process fails then there would be a second event which instead looks like
        processed==False, processing_id==(last event'is id) and amount==-10. Maybe like this? We can always rework it later. 
        """

    def generate_table_row(self):
        if not self.valid:
            return generate_error_row(self)
        # Create a row in table self.table with each column as the objects of this class