| Class | Account |
| In: |
lib/core/account.rb
|
| Parent: | Root |
The Account class handles connection login and passes them to character.
| character | [RW] | |
| conn | [RW] | |
| echo | [RW] | |
| mode | [RW] | |
| terminal | [RW] | |
| termsize | [RW] |
Create an Account connection. This is a temporary object that handles login for character and gets them connected.
# 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
# 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
# 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
# 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.
@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
# 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.
@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)
# 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
# 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
# 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
# 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
# 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.
This supports the following:
is done setting up and done negotiating an initial state. It triggers us to start sending output and parsing input.
send it to parse_messages.
# 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