Module: Lich::DragonRealms::DRInfomon

Extended by:
Common::Watchable
Defined in:
documented/dragonrealms/drinfomon/startup.rb,
documented/dragonrealms/drinfomon.rb

Overview

Populates initial game state after login and manages startup completion tracking.

Sends game commands (info, played, exp all 0, ability, flag) whose output is parsed by DRParser to populate XMLData with character stats, skills, spells, and other essential state. Uses ExecScript to ensure commands block until responses are parsed.

Scripts should check DRInfomon.startup_complete? before issuing their own info/played/exp/ability commands to avoid sending duplicates during initialization.

Includes automatic filesystem warnings about obsolete scripts and shadowed custom files.

See Also:

Constant Summary collapse

DRINFOMON_CORE_LICH_DEFINES =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

An array of core Lich defines used in DRInfomon.

Returns:

  • (Array<String>)

    the list of core defines

%W(drinfomon common common-arcana common-crafting common-healing common-healing-data common-items common-money common-moonmage common-summoning common-theurgy common-travel common-validation events slackbot equipmanager spellmonitor)
DRINFOMON_IN_CORE_LICH =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

Indicates whether DRInfomon is included in the core Lich.

Returns:

  • (Boolean)

    true if included, false otherwise

true
DR_OBSOLETE_SCRIPTS =

Script names that are obsolete and should be deleted. Checked on login to warn users about stale files.

%w[
  events slackbot spellmonitor exp-monitor
  common-travel common-validation common drinfomon equipmanager
  common-money common-moonmage common-summoning common-theurgy common-arcana
  bootstrap common-crafting common-healing-data common-healing common-items
  update-shops
].freeze
DR_OBSOLETE_DATA_FILES =

Data filenames that are obsolete and should be deleted.

%w[].freeze
@@startup_complete =

Populates initial game state after login by issuing game commands whose output is parsed by DRParser.

Uses ExecScript so that fput blocks until the game responds, guaranteeing DRParser.parse has processed every response line before the next command is sent.

Called once from the game lifecycle hook in games.rb after the character name is known and the session is ready.

Detection from scripts:

DRInfomon.startup_complete? - true after all startup commands have finished.
Use this to avoid sending duplicate info/played/exp/ability commands.
false

Class Method Summary collapse

Methods included from Common::Watchable

watch!

Class Method Details

.post_startup_checksvoid

This method returns an undefined value.

Best-effort filesystem checks that run once after startup completes. These don't need game commands, just file existence checks and warnings. Failures are logged but do not block the PostLoad lifecycle.



146
147
148
149
150
151
152
153
154
155
156
157
# File 'documented/dragonrealms/drinfomon/startup.rb', line 146

def self.post_startup_checks
  warn_obsolete_scripts
  warn_obsolete_data_files
  warn_custom_scripts
  $setupfiles.reload if defined?($setupfiles) && $setupfiles
  # Drop CustomSubstitutions' memoized lists so a fresh login re-reads any
  # edited custom_* settings (its cache is separate from $setupfiles').
  Lich::DragonRealms::CustomSubstitutions.reset! if defined?(Lich::DragonRealms::CustomSubstitutions)
rescue StandardError => e
  safe_message('error', "DRInfomon: post_startup_checks failed: #{e.message}")
  safe_log("DRInfomon: post_startup_checks error: #{e.inspect}\n\t#{e.backtrace&.first(5)&.join("\n\t")}")
end

.safe_log(text) ⇒ void

This method returns an undefined value.

Guarded logging -- safe to call if Lich.log is unavailable.

Parameters:

  • text (String)

    log message



176
177
178
179
180
181
182
# File 'documented/dragonrealms/drinfomon/startup.rb', line 176

def self.safe_log(text)
  if defined?(Lich) && Lich.respond_to?(:log)
    Lich.log(text)
  else
    $stderr.puts(text)
  end
end

.safe_message(type, text) ⇒ void

This method returns an undefined value.

Guarded messaging -- safe to call if Lich::Messaging is unavailable.

Parameters:

  • type (String)

    message type (e.g. 'error', 'info')

  • text (String)

    message text



164
165
166
167
168
169
170
# File 'documented/dragonrealms/drinfomon/startup.rb', line 164

def self.safe_message(type, text)
  if defined?(Lich::Messaging) && Lich::Messaging.respond_to?(:msg)
    Lich::Messaging.msg(type, text)
  else
    safe_log(text)
  end
end

.startupvoid

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

This method returns an undefined value.

Runs the startup script that populates initial game state.

Executes startup_script via ExecScript with quiet mode and a descriptive name. Called once by the watch! lifecycle hook after the character is ready.



74
75
76
# File 'documented/dragonrealms/drinfomon/startup.rb', line 74

def self.startup
  ExecScript.start(startup_script, { quiet: true, name: 'drinfomon_startup' })
end

.startup_complete?Boolean

Returns whether DRInfomon has finished populating initial game state after login.

Examples:

unless DRInfomon.startup_complete?
  wait_while { !DRInfomon.startup_complete? }
end

Returns:

  • (Boolean)

    true if startup commands have all completed, false otherwise



45
46
47
# File 'documented/dragonrealms/drinfomon/startup.rb', line 45

def self.startup_complete?
  @@startup_complete
end

.startup_completed!void

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

This method returns an undefined value.

Marks startup as complete and triggers post-startup housekeeping.

Sets the startup_complete flag to true, calls PostLoad.game_loaded! if available, and runs post_startup_checks to warn about obsolete and shadowed scripts.



135
136
137
138
139
# File 'documented/dragonrealms/drinfomon/startup.rb', line 135

def self.startup_completed!
  @@startup_complete = true
  PostLoad.game_loaded! if defined?(PostLoad)
  post_startup_checks
end

.startup_scriptString

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Generates the startup script content that populates game state.

Constructs a heredoc string containing game commands issued in order:

  • info: populates character stats (name, race, guild, circle)
  • played: populates account name and subscription level
  • exp all 0: populates all skill ranks and learning rates
  • ability: populates spells, barbarian abilities, or thief khri (guild-dependent)
  • flag: ensures MonsterBold is enabled (one-time per character)

Each command uses Lich::Util.issue_command with regex patterns and 1-second timeout. Completes by calling startup_completed! to signal readiness.

Returns:

  • (String)

    the startup script as a heredoc



92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# File 'documented/dragonrealms/drinfomon/startup.rb', line 92

def self.startup_script
  <<~SCRIPT
    # Populate stats, race, guild, circle, etc.
    Lich::Util.issue_command("info", /^Name/, /^<output class=""/, quiet: true, timeout: 1) unless dead?

    # Populate account name and subscription level
    Lich::Util.issue_command("played", /^Account Info for/, quiet: true, timeout: 1)

    # Populate all skill ranks and learning rates
    Lich::Util.issue_command("exp all 0", /^Circle: \\d+/, /^EXP HELP/, quiet: true, timeout: 1)

    # Populate known spells/abilities/khri
    # The `ability` command works for all guilds:
    #   - Magic guilds: proxies to `spells`, parsed by check_known_spells
    #   - Barbarians: parsed by check_known_barbarian_abilities
    #   - Thieves: parsed by check_known_thief_khri
    Lich::Util.issue_command("ability", /^You (?:know the Berserks|recall the spells you have learned from your training)|^From (?:your apprenticeship you remember practicing|the \\w+ tree)/, /^You (?:recall that you have \\d+ training sessions|can use SPELL STANCE \\[HELP\\]|have \\d+ available slot)/, quiet: true, timeout: 1)

    # Ensure the MonsterBold flag is enabled (one-time per character). ShowRoomID is no
    # longer forced: room UIDs now come from the <nav> tag regardless of that flag, so
    # whether the game shows inline room IDs is left entirely to the player's preference.
    unless UserVars.dependency_setflags
      flags = Array(Lich::Util.issue_command("flag", /^Usage/, /^For other setting options, see AVOID, SET, and TOGGLE/, quiet: true, timeout: 1, usexml: false))
      required = ["MonsterBold"]
      required.each do |flag|
        fput("flag \#{flag} on") unless flags.any? { |f| f.match?(/\#{Regexp.escape(flag)}\\s+ON/) }
      end
      # Re-query to verify flags applied; only mark sentinel if all confirmed
      flags = Array(Lich::Util.issue_command("flag", /^Usage/, /^For other setting options, see AVOID, SET, and TOGGLE/, quiet: true, timeout: 1, usexml: false))
      UserVars.dependency_setflags = Time.now if required.all? { |flag| flags.any? { |f| f.match?(/\#{Regexp.escape(flag)}\\s+ON/) } }
    end

    Lich::DragonRealms::DRInfomon.startup_completed!
  SCRIPT
end

.warn_custom_scriptsvoid

This method returns an undefined value.

Warns when scripts/custom/ contains files that shadow curated scripts, preventing the curated versions from receiving updates.



226
227
228
229
230
231
232
233
234
235
236
237
238
# File 'documented/dragonrealms/drinfomon/startup.rb', line 226

def self.warn_custom_scripts
  custom_dir = File.join(SCRIPT_DIR, 'custom')
  return unless File.directory?(custom_dir)

  custom_scripts = Dir.entries(custom_dir).select { |f| f.end_with?('.lic') }
  curated_scripts = Dir.entries(SCRIPT_DIR).select { |f| f.end_with?('.lic') }
  shadowed = custom_scripts.select { |script| curated_scripts.include?(script) }

  unless shadowed.empty?
    Lich::Messaging.msg("info", "NOTE: The following curated scripts are in your custom folder and will not receive updates")
    Lich::Messaging.msg("info", shadowed.join(', '))
  end
end

.warn_obsolete_data_filesvoid

This method returns an undefined value.

Warns about obsolete data files still present in SCRIPT_DIR/data.



212
213
214
215
216
217
218
219
220
# File 'documented/dragonrealms/drinfomon/startup.rb', line 212

def self.warn_obsolete_data_files
  data_dir = File.join(SCRIPT_DIR, 'data')
  DR_OBSOLETE_DATA_FILES.each do |filename|
    path = File.join(data_dir, filename)
    next unless File.exist?(path)

    _respond Lich::Messaging.monsterbold("--- Lich: '#{filename}' is obsolete and can be safely deleted from #{data_dir}.")
  end
end

.warn_obsolete_scriptsvoid

This method returns an undefined value.

Warns about obsolete .lic files still present in SCRIPT_DIR.



200
201
202
203
204
205
206
207
# File 'documented/dragonrealms/drinfomon/startup.rb', line 200

def self.warn_obsolete_scripts
  DR_OBSOLETE_SCRIPTS.each do |script_name|
    path = File.join(SCRIPT_DIR, "#{script_name}.lic")
    next unless File.exist?(path)

    _respond Lich::Messaging.monsterbold("--- Lich: '#{script_name}.lic' is obsolete and should be deleted from #{SCRIPT_DIR}. It is no longer needed and may cause problems.")
  end
end

.watch!Object

Self-watching thread that triggers startup when ready Follows the ActiveSpell.watch! pattern for lifecycle management



51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'documented/dragonrealms/drinfomon/startup.rb', line 51

def self.watch!
  @startup_thread ||= Thread.new do
    begin
      # Wait for character to be ready
      sleep 0.1 until GameBase::Game.autostarted? && XMLData.name && !XMLData.name.empty?

      # Run startup once
      startup
    rescue StandardError => e
      Lich::Messaging.msg('error', 'DRInfomon: Error in startup thread')
      Lich::Messaging.msg('error', "DRInfomon: #{e.inspect}")
      Lich::Messaging.msg('error', "DRInfomon: #{e.backtrace.join("\n")}")
    end
  end
end