Class Account
In: lib/core/account.rb
Parent: Root
Account
Publisher
Root
dot/f_9.png

The Account class handles connection login and passes them to character.

Methods

Included Modules

Publisher

Attributes

character  [RW] 
conn  [RW] 
echo  [RW] 
mode  [RW] 
terminal  [RW] 
termsize  [RW] 

Public Class methods

Create an Account connection. This is a temporary object that handles login for character and gets them connected.

conn
The session associated with this Account connection.
return
A handle to the Account object.

[Source]

# File lib/core/account.rb, line 32
  def initialize(conn)
    super("",nil)
    self.passwd = nil
    self.color = false
    self.characters = []
    @conn = conn                # Reference to network session (connection)
    @mode = :initialize
    @echo = false
    @termsize = nil
    @terminal = nil
    @checked = 3                # Login retry counter - on 0 disconnect
    @account = nil              # used only during sign-in process
    @character = nil            # reference to the currently played Character.
  end

Public Instance methods

If echo hasn‘t been negotiated, we want to leave the cursor after the message prompt, so we prepend linefeeds in front of messages. This is hackish.

[Source]

# File lib/core/account.rb, line 327
  def append_echo(msg)
    @echo ? msg : "\n" + msg
  end

[Source]

# File lib/core/account.rb, line 379
  def character_menu
    str = '[color Yellow]'
    characters.each_index do |i|
      str << "#{i}) #{get_object(characters[i]).name}\n"
    end
    str << "Pick a character>[/color] "
  end

Disconnects this account

[Source]

# File lib/core/account.rb, line 371
  def disconnect(msg=nil)
    publish("[home 1,1][scrreset][clear]") if vtsupport?
    publish(msg + "\n") if msg
    publish("Bye!\n")
    publish(:quit)
    unsubscribe_all
  end

[Source]

# File lib/core/account.rb, line 387
  def login_menu
    "[color Yellow]1) Create a character\n2) Play\nQ) Quit\n>[/color] "
  end

Handles message while in the login menu - called by parse_messages. This was refactored out of Account#parse_messages for length reasons.

msg
The message string

@mode tracks the state changes, This routine is entered by any @modes staring with :menu.

The following state transition diagram illustrates the possible transitions.

:menu -> :menucr Create a character

           -> :menupl       Play a character

:menucr -> :playing Get character name, create character and play

[Source]

# File lib/core/account.rb, line 270
  def parse_menu(msg)
    case @mode
    when :menu
      case msg
      when /^1/i
        sendmsg(append_echo("Enter character name> "))
        @mode = :menucr
      when /^2/i
        if characters.size == 0
          sendmsg(append_echo(login_menu))
          @mode = :menu
        else
          sendmsg(append_echo(character_menu))
          @mode = :menupl
        end
      when /^Q/i
        disconnect
      else                        # Any other key
        sendmsg(append_echo(login_menu))
        @mode = :menu
      end
    when :menucr
      if msg.proper_name.empty?
        sendmsg(append_echo(login_menu))
        @mode = :menu
      else
        @character = new_char(msg.proper_name)
        @conn.set(:color, color)
        welcome
        @mode = :playing
      end
    when :menupl
      case msg
      when /(\d+)/
        if $1.to_i >= characters.size
          sendmsg(append_echo(character_menu))
        else
          @character = get_object(characters[$1.to_i])
          # make the character non-swappable so we dont lose references
          Engine.instance.db.makenoswap(@character.id)
          world.connected_characters << @character.id
          @character.account = self
          welcome
          @mode = :playing
        end
      else
        sendmsg(append_echo(login_menu))
        @mode = :menu
      end
    else
      log.error "Account#parse_menu unknown :mode - #{@mode.inspect}"
    end
  end

Handles String messages from Connection - called by update. This was refactored out of Account#update for length reasons.

msg
The message string

@mode tracks the state changes, The Account is created with the initial state of :initialize. The following state transition diagram illustrates the possible transitions.

:intialize -> :name Set when Account:update receives :initdone msg :name -> :password Sets @login_name and finds @account

              :playing      Creates a new character if Guest account

:password -> :newacct Sets @login_passwd

           -> :menu         Good passwd, switches account, if account_system
                            option on goes to menu
           -> :playing      Good passwd, switches account, loads character
           -> :name         Bad passwd
           -> disconnect    Bad passwd, exceeds @check attempts
                            (see Account#disconnect)

:newacct -> :menu If account_system option on goes to menu

           -> :playing        Creates new character, adds account

:menu -> parse_menu Redirect message (see Account#parse_menu) :playing -> @character Redirect message (see Character#parse)

[Source]

# File lib/core/account.rb, line 148
  def parse_messages(msg)
    case @mode
    when :initialize
      # ignore everything until negotiation done
    when :name
      publish("[clearline]") if vtsupport?
      @login_name = msg.proper_name
      if options['guest_accounts'] && @login_name =~ /Guest/i
        self.name = "Guest#{id}"
        @character = new_char
        put_object(self)
        world.all_accounts << id
        # make the account non-swappable so we dont lose connection
        Engine.instance.db.makenoswap(id)
        @conn.set(:color, color)
        welcome
        @mode = :playing
      elsif @login_name.empty?
        sendmsg(append_echo("login> "))
        @mode = :name
      else
        acctid = world.all_accounts.find {|a|
          @login_name == get_object(a).name
        }
        @account = get_object(acctid)
        sendmsg(append_echo("password> "))
        @conn.set(:hide, true)
        @mode = :password
      end
    when :password
      @login_passwd = msg
      @conn.set(:hide, false)
      if @account.nil?  # new account
        sendmsg(append_echo("Create new user?\n'Y/y' to create, Hit enter to retry login> "))
        @mode = :newacct
      else
        if @login_passwd.is_passwd?(@account.passwd)  # good login
          # deregister all observers here and on connection
          unsubscribe_all
          @conn.unsubscribe_all
          # reregister all observers to @account
          @conn.subscribe(@account.id)
          # make the account non-swappable so we dont lose connection
          Engine.instance.db.makenoswap(@account.id)
          @conn.set(:color, @account.color)
          switch_acct(@account)
          # Check if this account already logged in
          reconnect = false
          if @account.subscriber_count > 0
            @account.publish(:reconnecting)
            @account.unsubscribe_all
            reconnect = true
          end
          @account.subscribe(@conn)
          if options['account_system']
            @account.sendmsg(append_echo(login_menu))
            @account.mode = :menu
          else
            @character = get_object(@account.characters.first)
            # make the character non-swappable so we dont lose references
            Engine.instance.db.makenoswap(@character.id)
            world.connected_characters << @character.id
            @character.account = @account
            @account.character = @character
            welcome(reconnect)
            @account.mode = :playing
          end
        else  # bad login
          @checked -= 1
          sendmsg(append_echo("Sorry wrong password."))
          if @checked < 1
            disconnect
          else
            @mode = :name
            sendmsg(append_echo("login> "))
          end
        end
      end
    when :newacct
      if msg =~ /^y/i
        self.name = @login_name
        self.passwd = @login_passwd.encrypt
        put_object(self)
        # make the account non-swappable so we dont lose connection
        Engine.instance.db.makenoswap(id)
        world.all_accounts << id
        @conn.set(:color, color)
        if options['account_system']
          sendmsg(append_echo(login_menu))
          @mode = :menu
        else
          @character = new_char
          welcome
          @mode = :playing
        end
      else
        @mode = :name
        sendmsg(append_echo("login> "))
      end
    when :menu, :menucr, :menupl
      parse_menu(msg)
    when :playing
      @character.parse(msg)
    else
      log.error "Account#parse_messages unknown :mode - #{@mode.inspect}"
    end
  end

[Source]

# File lib/core/account.rb, line 338
  def prompt
    if vtsupport?
??
      publish("[home #{@termsize[1]-2},1]" +
        "[color Yellow on Red]#{" "*@termsize[0]}[/color]" +
        "[home #{@termsize[1]-1},1][clearline][color Magenta](#{name})[#{@mode}][/color]" +
        "[home #{@termsize[1]},1][clearline]> ")
    else
#      publish("> ")
    end
  end

[Source]

# File lib/core/account.rb, line 331
  def sendmsg(msg)
    publish("[cursave][home #{@termsize[1]-3},1]") if vtsupport?
    publish(msg)
    publish("[currest]") if vtsupport?
    prompt
  end

[Source]

# File lib/core/account.rb, line 355
  def status_rept
    str = "Terminal: #{@terminal}\n"
    str << "Terminal size: #{@termsize[0]} X #{@termsize[1]}\n"
    str << "Colors toggled #{@color ? '[COLOR Magenta]ON[/COLOR]' : 'OFF' }\n"
    str << "Echo is #{@echo ? 'ON' : 'OFF' }\n"
    str << "ZMP is #{@conn.query(:zmp) ? 'ON' : 'OFF' }\n"
  end

[Source]

# File lib/core/account.rb, line 363
  def toggle_color
    color ? self.color = false : self.color = true
    @conn.set(:color,color)
    "Colors toggled #{color ? '[COLOR Magenta]ON[/COLOR]' : 'OFF' }\n"
  end

Receives messages from a Connection being observed and handles login state.

msg
The message string

This supports the following:

:disconnected
- This symbol from the server informs us that the Connection has disconnected.
:initdone
- This symbol from the server indicates that the Connection
  is done setting up and done negotiating an initial state.
  It triggers us to start sending output and parsing input.
:termsize
- This is sent everytime the terminal size changes (NAWS)
String
- A String is assumed to be input from the Session and we
  send it to parse_messages.

[Source]

# File lib/core/account.rb, line 62
  def update(msg)
    case msg
    # Handle disconnection from server
    # Note that publishing a :quit event (see #disconnect) will return a
    #  :disconnected event when server has closed the connection.
    # Guest accounts and characters are deleted here.
    when :disconnected
      @conn = nil
      unsubscribe_all
      Engine.instance.db.makeswap(id)
      if @character
        world.connected_characters.delete(@character.id)
        world.connected_characters.each do |pid|
          add_event(@character.id,pid,:show,"#{name} has disconnected.")
        end
        Engine.instance.db.makeswap(@character.id)
        @character.account = nil
        if @character.name =~ /Guest/i
          world.all_characters.delete(@character.id)
          delete_object(@character.id)
        end
        @character = nil
      end
      if name =~ /Guest/i
        world.all_accounts.delete(id)
        delete_object(id)
      end
    # Issued when a NAWS event occurs
    # Currently this clears and resets the screen.  Ideally it should attempt
    # to redraw it.
    when :termsize
      @termsize = @conn.query(:termsize)
      if vtsupport?
        publish("[home #{@termsize[1]},1][clearline][cursave]" +
          "[home 1,1][scrreset][clear][scrreg 1,#{@termsize[1]-3}][currest]")
      end
    # Negotiation with client done.  Start talking to it.
    when :initdone
      @echo = @conn.query(:echo)
      @termsize = @conn.query(:termsize)
      @terminal = @conn.query(:terminal)
      if vtsupport?
        publish("[home #{@termsize[1]},1][clearline][cursave]" +
          "[home 1,1][scrreset][clear][scrreg 1,#{@termsize[1]-3}][currest]")
        sendmsg(LOGO)
      end
      sendmsg(BANNER)
      sendmsg(append_echo("login> "))
      @mode = :name
    # This is a message from our user
    when String
      parse_messages(msg)
    else
      log.error "Account#update unknown message - #{msg.inspect}"
    end
  rescue
    # We squash and print out all exceptions here.  There is no reason to
    # throw these back at the Connection.
    log.error $!
  end

[Source]

# File lib/core/account.rb, line 391
  def vtsupport?
    @terminal =~ /^vt|xterm/
  end

[Validate]