Class: Modsvaskr::Game

Inherits:
Object
  • Object
show all
Includes:
Logger, RunCmd
Defined in:
lib/modsvaskr/game.rb

Overview

Common functionality for any Game

Direct Known Subclasses

Modsvaskr::Games::SkyrimSe

Instance Method Summary collapse

Methods included from Logger

#log, #out, #wait_for_user_enter

Methods included from RunCmd

#run_cmd

Constructor Details

#initialize(config, game_info) ⇒ Game

Constructor

Parameters
  • config (Config): The config

  • game_info (Hash<String,Object>): Game info:

    • name (String): Game name

    • path (String): Game installation dir

    • launch_exe (String): Executable to be launched

    • min_launch_time_secs (Integer): Minimum expected lauch time for the game, in seconds [default: 10]

    • tests_poll_secs (Integer): Interval in seconds to be respected between 2 test statuses polling [default: 5]

    • timeout_frozen_tests_secs (Integer): Timeout in seconds of a frozen game [default: 300]

    • timeout_interrupt_tests_secs (Integer): Timeout in seconds for the player to interrupt a tests session before restarting the game [default: 10]



25
26
27
28
29
30
31
32
33
34
35
36
37
# File 'lib/modsvaskr/game.rb', line 25

def initialize(config, game_info)
  @config = config
  # Set default values here
  @game_info = {
    'min_launch_time_secs' => 10,
    'tests_poll_secs' => 5,
    'timeout_frozen_tests_secs' => 300,
    'timeout_interrupt_tests_secs' => 10
  }.merge(game_info)
  @name = name
  @pid = nil
  init if respond_to?(:init)
end

Instance Method Details

#decode_form_id(form_id) ⇒ Object

Get the mod and base id corresponding to a given form id. Uses load order to determine it.

Parameters
  • form_id (String or Integer): Form ID, either as hexadecimal string, or numercial value

Result
  • String: Plugin name

  • Integer: Base form id, independent from the load order



201
202
203
204
# File 'lib/modsvaskr/game.rb', line 201

def decode_form_id(form_id)
  form_id = form_id.to_i(16) if form_id.is_a?(String)
  [load_order[form_id / 16_777_216], form_id % 16_777_216]
end

#killObject

Kill the game, and wait till it is killed



166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
# File 'lib/modsvaskr/game.rb', line 166

def kill
  if @pid
    first_time = true
    while @pid
      system "taskkill #{first_time ? '' : '/F '}/pid #{@pid}"
      first_time = false
      sleep 1
      if running?
        log "[ Game #{name} ] - #{running_exe} is still running (PID #{@pid}). Wait for its kill..."
        sleep 5
      end
    end
  else
    log "[ Game #{name} ] - Game not started, so nothing to kill."
  end
end

#launch(autoload: false) ⇒ Object

Launch the game, and wait for launch to be successful

Parameters
  • autoload (Boolean or String): If false, then launch the game using the normal launcher. If String, then use AutoLoad to load a given saved file (or empty to continue latest save) [default: false].



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
127
128
129
130
131
132
133
134
135
136
137
138
139
# File 'lib/modsvaskr/game.rb', line 100

def launch(autoload: false)
  # Launch the game
  @idx_launch = 0 unless defined?(@idx_launch)
  if autoload
    log "[ Game #{name} ] - Launch game (##{@idx_launch}) using AutoLoad #{autoload}..."
    autoload_file = "#{path}/Data/AutoLoad.cmd"
    if File.exist?(autoload_file)
      run_cmd(
        {
          dir: path,
          exe: 'Data\AutoLoad.cmd',
          args: [autoload]
        }
      )
    else
      log "[ Game #{name} ] - Missing file #{autoload_file}. Can't use AutoLoad to load game automatically. Please install the AutoLoad mod."
    end
  else
    log "[ Game #{name} ] - Launch game (##{@idx_launch}) using configured launcher (#{launch_exe})..."
    run_cmd(
      {
        dir: path,
        exe: launch_exe
      }
    )
  end
  @idx_launch += 1
  # The game launches asynchronously, so just wait a little bit and check for the process existence
  sleep @game_info['min_launch_time_secs']
  tasklist_stdout = nil
  loop do
    tasklist_stdout = `tasklist | find "#{running_exe}"`.strip
    break unless tasklist_stdout.empty?

    log "[ Game #{name} ] - #{running_exe} is not running. Wait for its startup..."
    sleep 1
  end
  @pid = Integer(tasklist_stdout.split[1])
  log "[ Game #{name} ] - #{running_exe} has started with PID #{@pid}"
end

#launch_exeObject

Return the launch executable

Result
  • String: Launch executable



59
60
61
# File 'lib/modsvaskr/game.rb', line 59

def launch_exe
  @game_info['launch_exe']
end

#load_orderObject

Get the load order. Keep a cache of it.

Result
  • Array<String>: List of all active plugins, including masters



188
189
190
191
# File 'lib/modsvaskr/game.rb', line 188

def load_order
  @cache_load_order = read_load_order unless defined?(@cache_load_order)
  @cache_load_order
end

#nameObject

Return the game name

Result
  • String: Game name



43
44
45
# File 'lib/modsvaskr/game.rb', line 43

def name
  @game_info['name']
end

#pathObject

Return the game path

Result
  • String: Game path



51
52
53
# File 'lib/modsvaskr/game.rb', line 51

def path
  @game_info['path']
end

#running?Boolean

Is the game currently running?

Result
  • Boolean: Is the game currently running?

Returns:

  • (Boolean)


145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
# File 'lib/modsvaskr/game.rb', line 145

def running?
  if @pid
    running = true
    begin
      # Process.kill does not work when the game has crashed (the process is still detected as zombie)
      # running = Process.kill(0, @pid) == 1
      tasklist_stdout = `tasklist | find "#{running_exe}"`.strip
      running = !tasklist_stdout.empty?
      # log "[ Game #{name} ] - Tasklist returned no #{running_exe}:\n#{tasklist_stdout}" unless running
    rescue Errno::ESRCH
      log "[ Game #{name} ] - Got error while waiting for #{running_exe} PID #{@pid}: #{$ERROR_INFO}"
      running = false
    end
    @pid = nil unless running
    running
  else
    false
  end
end

#tests_poll_secsObject

Return the tests polling interval

Result
  • Integer: Tests polling interval



67
68
69
# File 'lib/modsvaskr/game.rb', line 67

def tests_poll_secs
  @game_info['tests_poll_secs']
end

#timeout_frozen_tests_secsObject

Return the timeout to detect a frozen game

Result
  • Integer: Timeout to detect a frozen game



75
76
77
# File 'lib/modsvaskr/game.rb', line 75

def timeout_frozen_tests_secs
  @game_info['timeout_frozen_tests_secs']
end

#timeout_interrupt_tests_secsObject

Return the timeout before restarting a game tests session

Result
  • Integer: Timeout before restarting a game tests session



83
84
85
# File 'lib/modsvaskr/game.rb', line 83

def timeout_interrupt_tests_secs
  @game_info['timeout_interrupt_tests_secs']
end

#xeditObject

Return an xEdit instance for this game

Result
  • Xedit: The xEdit instance



91
92
93
94
# File 'lib/modsvaskr/game.rb', line 91

def xedit
  @xedit = Xedit.new(@config.xedit_path, path) unless defined?(@xedit)
  @xedit
end