Files
w3dhub_linux_launcher/lib/application_manager.rb

253 lines
7.4 KiB
Ruby

class W3DHub
class ApplicationManager
include CyberarmEngine::Common
def initialize
@tasks = [] # :installer, :importer, :repairer, :uninstaller
end
def install(app_id, channel)
puts "Installation Request: #{app_id}-#{channel}"
return false if installed?(app_id, channel) || installing?(app_id, channel)
# if on unix: ask/make a wine prefix
# add install task to a list and mark as installing
# fetch manifests
# cycle through manifests and check package cache
# generate list of required packages to download
# download packages
# verify packages
# unpack packages
# install dependencies (e.g. visual C runtime)
installer = Installer.new(app_id, channel)
@tasks.push(installer)
end
def import(app_id, channel, path)
puts "Import Request: #{app_id}-#{channel} -> #{path}"
# Check registry for auto-import if windows
# if auto-import fails ask user for path to game exe
# mark app as imported/installed
@tasks.push(Importer.new(app_id, channel, path))
end
def settings(app_id, channel)
puts "Settings Request: #{app_id}-#{channel}"
# open wwconfig.exe or config.exe for ecw
if (app_data = installed?(app_id, channel))
config_exe = app_id == "ecw" ? "config.exe" : "wwconfig.exe"
exe = "#{app_data[:install_directory]}/#{config_exe}"
if File.exist?(exe)
pid = Process.spawn("#{wine_command(app_id, channel)}\"#{exe}\"")
Process.detach(pid)
end
end
end
def wine_configuration(app_id, channel)
puts "Wine Configuration Request: #{app_id}-#{channel}"
# open wwconfig.exe or config.exe for ecw
if (app_data = installed?(app_id, channel) && W3DHub.unix?)
exe = if window.settings[:wine_prefix]
"WINEPREFIX=\"#{window.settings[:wine_prefix]}\" winecfg"
else
"winecfg"
end
Process.spawn("#{exe}")
end
end
def repair(app_id, channel)
puts "Repair Installation Request: #{app_id}-#{channel}"
return false if !installed?(app_id, channel) || installing?(app_id, channel)
# verify/download manifests
# verify game files
# verify package cache packages of any files that failed verification
# re/download needed packages
# unpack packages
# install dependencies (e.g. visual C runtime) if appropriate
@tasks.push(Repairer.new(app_id, channel))
end
def uninstall(app_id, channel)
puts "Uninstall Request: #{app_idchannel}"
return false if !installed?(app_id, channel) || installing?(app_id, channel)
@tasks.push(Uninstaller.new(app_id, channel))
end
def show_folder(app_id, channel, type)
puts "Show Folder Request: #{app_id} -> #{type.inspect}"
case type
when :installation
when :user_data
when :screenshots
else
warn "Unknown folder type: #{type.inspect}"
end
end
def wine_command(app_id, channel)
return "" if W3DHub.windows?
if window.settings[:wine_prefix]
"WINEPREFIX=\"#{window.settings[:wine_prefix]}\" \"#{window.settings[:wine_command]}\" "
else
"#{window.settings[:wine_command]} "
end
end
def run(app_id, channel, *args)
if (app_data = installed?(app_id, channel))
pp "#{wine_command(app_id, channel)}#{app_data[:install_path]}", *args
pid = Process.spawn("#{wine_command(app_id, channel)}#{app_data[:install_path]}", *args)
Process.detach(pid)
end
end
def join_server(app_id, channel, server, password = nil)
if installed?(app_id, channel) && window.settings[:server_list_username].to_s.length.positive?
run(
app_id, channel,
"-launcher",
"+connect #{server.address}:#{server.port}",
"+netplayername \"#{window.settings[:server_list_username]}\"",
password ? "+password \"#{password}\"" : ""
)
end
end
def auto_import
return unless W3DHub.windows?
# Renegade
auto_import_win32_registry("ren", "release", 'SOFTWARE\Westwood\Renegade')
# Red Alert: A Path Beyond
auto_import_win32_registry("apb", "release")
# Expansive Civilian Warfare
auto_import_win32_registry("ecw", "release")
# Interim Apex
auto_import_win32_registry("ia", "release")
# Tiberian Sun: Reborn
auto_import_win32_registry("tsr", "release")
end
def auto_import_win32_registry(app_id, channel_id, registry_path = nil)
return unless W3DHub.windows?
return if installed?(app_id, channel_id)
puts "Importing: #{app_id}-#{channel_id}"
require "win32/registry"
registry_path ||= "SOFTWARE\\W3D Hub\\games\\#{app_id}-#{channel_id}"
reg_type = Win32::Registry::KEY_READ
reg_constant = app_id == "ren" ? Win32::Registry::HKEY_CURRENT_USER : Win32::Registry::HKEY_LOCAL_MACHINE
begin
reg_constant.open(registry_path, reg_type) do |reg|
if (install_path = reg["InstallPath"])
if File.exist?(install_path) || (app_id == "ecw" && File.exist?("#{File.dirname(install_path)}/game750.exe"))
install_path.gsub!("\\", "/")
installed_version = reg["InstalledVersion"] unless app_id == "ren"
application_data = {
install_directory: File.dirname(install_path),
installed_version: app_id == "ren" ? "1.0.0.0" : installed_version,
install_path: app_id == "ecw" ? "#{File.dirname(install_path)}/game750.exe" : install_path,
wine_prefix: nil
}
window.settings[:games] ||= {}
window.settings[:games][:"#{app_id}_#{channel_id}"] = application_data
window.settings.save_settings
end
end
end
rescue => e
puts e.message, e.backtrace
false
end
end
def installed!(task)
# install_dir
# installed_version
# installPath # game executable
# wine_prefix # optional
install_directory = Cache.install_path(task.application, task.channel)
application_data = {
install_directory: install_directory,
installed_version: task.channel.current_version,
install_path: "#{install_directory}/game.exe",
wine_prefix: task.wine_prefix
}
window.settings[:games] ||= {}
window.settings[:games][:"#{task.app_id}_#{task.release_channel}"] = application_data
window.settings.save_settings
end
def installed?(app_id, channel)
window.settings[:games, :"#{app_id}_#{channel}"]
end
def installing?(app_id, channel)
@tasks.find { |t| t.is_a?(Installer) && t.app_id == app_id && t.release_channel == channel }
end
# No application tasks are being done
def idle?
!busy?
end
# Whether some operation is in progress
def busy?
current_task
end
def current_task
@tasks.find { |t| [:running, :paused].include?(t.state) }
end
def start_next_available_task
return unless idle?
task = @tasks.find { |t| t.state == :not_started }
task&.start
end
def task?(type, app_id, channel)
@tasks.find do |t|
t.type == type &&
t.app_id == app_id &&
t.release_channel == channel &&
[ :not_started, :running, :paused ].include?(t.state)
end
end
end
end