6 Commits

5 changed files with 125 additions and 85 deletions

View File

@@ -5,6 +5,7 @@ class W3DHub
def initialize def initialize
@tasks = [] # :installer, :importer, :repairer, :uninstaller @tasks = [] # :installer, :importer, :repairer, :uninstaller
@running_applications = {}
end end
def install(app_id, channel) def install(app_id, channel)
@@ -22,9 +23,7 @@ class W3DHub
# unpack packages # unpack packages
# install dependencies (e.g. visual C runtime) # install dependencies (e.g. visual C runtime)
installer = Installer.new(app_id, channel) @tasks.push(Installer.new(app_id, channel))
@tasks.push(installer)
end end
def update(app_id, channel) def update(app_id, channel)
@@ -32,9 +31,7 @@ class W3DHub
return false unless installed?(app_id, channel) return false unless installed?(app_id, channel)
updater = Updater.new(app_id, channel) @tasks.push(Updater.new(app_id, channel))
@tasks.push(updater)
end end
def import(app_id, channel) def import(app_id, channel)
@@ -169,11 +166,16 @@ class W3DHub
def wine_command(app_id, channel) def wine_command(app_id, channel)
return "" if W3DHub.windows? return "" if W3DHub.windows?
if !Store.settings[:wine_prefix].to_s.empty? "\"#{Store.settings[:wine_command]}\" "
"WINEPREFIX=\"#{Store.settings[:wine_prefix]}\" \"#{Store.settings[:wine_command]}\" "
else
"#{Store.settings[:wine_command]} "
end end
def wine_enviroment_variables(app_id, channel)
vars = {}
return vars if W3DHub.windows?
vars["WINEPREFIX"] = Store.settings[:wine_prefix] unless Store.settings[:wine_prefix].to_s.empty?
vars
end end
def mangohud_command(app_id, channel) def mangohud_command(app_id, channel)
@@ -188,6 +190,13 @@ class W3DHub
end end
end end
def mangohud_enviroment_variables(app_id, channel)
vars = {}
return vars if W3DHub.windows?
vars
end
def dxvk_command(app_id, channel) def dxvk_command(app_id, channel)
return "" if W3DHub.windows? return "" if W3DHub.windows?
@@ -201,6 +210,13 @@ class W3DHub
end end
end end
def dxvk_enviroment_variables(app_id, channel)
vars = {}
return vars if W3DHub.windows?
vars
end
def start_command(path, exe) def start_command(path, exe)
if W3DHub.windows? if W3DHub.windows?
"start /D \"#{path}\" /B #{exe}" "start /D \"#{path}\" /B #{exe}"
@@ -212,16 +228,32 @@ class W3DHub
def run(app_id, channel, *args) def run(app_id, channel, *args)
if (app_data = installed?(app_id, channel)) if (app_data = installed?(app_id, channel))
install_directory = app_data[:install_directory] install_directory = app_data[:install_directory]
exe_path = app_id == "ecw" ? "#{install_directory}/game500.exe" : "#{install_directory}/game.exe" exe_path = app_id == "ecw" ? "#{install_directory}/game500.exe" : app_data[:install_path]
exe_path.gsub!("/", "\\") if W3DHub.windows? exe_path.gsub!("/", "\\") if W3DHub.windows?
exe_path.gsub!("\\", "/") if W3DHub.unix? exe_path.gsub!("\\", "/") if W3DHub.unix?
exe = File.basename(exe_path) exe = File.basename(exe_path)
path = File.dirname(exe_path) path = File.dirname(exe_path)
env = {}
if W3DHub.unix?
env.merge!(
dxvk_enviroment_variables(app_id, channel),
mangohud_enviroment_variables(app_id, channel),
wine_enviroment_variables(app_id, channel)
)
end
attempted = false attempted = false
begin begin
pid = Process.spawn("#{dxvk_command(app_id, channel)}#{mangohud_command(app_id, channel)}#{wine_command(app_id, channel)}#{attempted ? start_command(path, exe) : "\"#{exe_path}\""} -launcher #{args.join(' ')}") pid = Process.spawn(
env,
"#{dxvk_command(app_id, channel)}"\
"#{mangohud_command(app_id, channel)}"\
"#{wine_command(app_id, channel)}"\
"#{attempted ? start_command(path, exe) : "\"#{exe_path}\""} "\
"-launcher #{args.join(' ')}"
)
Process.detach(pid) Process.detach(pid)
rescue Errno::EINVAL => e rescue Errno::EINVAL => e
retryable = !attempted retryable = !attempted
@@ -236,13 +268,15 @@ class W3DHub
end end
def join_server(app_id, channel, server, username = Store.settings[:server_list_username], password = nil, multi = false) def join_server(app_id, channel, server, username = Store.settings[:server_list_username], password = nil, multi = false)
if installed?(app_id, channel) && username.to_s.length.positive? return unless installed?(app_id, channel) && username.to_s.length.positive?
run( run(
app_id, channel, app_id, channel,
"+connect #{server.address}:#{server.port} +netplayername #{username}#{password ? " +password \"#{password}\"" : ""}#{multi ? " +multi" : ""}" "+connect #{server.address}:#{server.port} "\
"+netplayername #{username}#{password ? " +password \"#{password}\"" : ""}"\
"#{multi ? " +multi" : ""}"
) )
end end
end
def play_now_server(app_id, channel) def play_now_server(app_id, channel)
app_data = installed?(app_id, channel) app_data = installed?(app_id, channel)
@@ -255,13 +289,18 @@ class W3DHub
!server.status.password && !server.status.password &&
server.status.player_count < server.status.max_players server.status.player_count < server.status.max_players
end end
# sort by player count HIGH to LOW
# and by ping LOW to HIGH
server_options.sort! do |a, b|
[b.status.player_count, a.ping] <=> [a.status.player_count, b.ping]
end
# try to find server with lowest ping and matching version # try to find server with lowest ping and matching version
found_server = server_options.find { |server| server.version == app_data[:installed_version] } found_server = server_options.find { |server| server.version == app_data[:installed_version] }
# try to find server with lowest ping and undefined version # try to find server with lowest ping and undefined version
found_server ||= server_options.find { |server| server.version == Api::ServerListServer::NO_OR_DEFAULT_VERSION } found_server ||= server_options.find { |server| server.version == Api::ServerListServer::NO_OR_DEFAULT_VERSION }
found_server ? found_server : nil found_server
end end
def play_now(app_id, channel) def play_now(app_id, channel)

View File

@@ -746,6 +746,8 @@ class W3DHub
end end
patch_entry = patch_mix.entries.find { |e| e.name.casecmp?(".w3dhub.patch") || e.name.casecmp?(".bhppatch") } patch_entry = patch_mix.entries.find { |e| e.name.casecmp?(".w3dhub.patch") || e.name.casecmp?(".bhppatch") }
patch_entry.read patch_entry.read
# "remove" patch meta file from patch before copying patch data
patch_mix.entries.delete(patch_entry)
patch_info = JSON.parse(patch_entry.blob, symbolize_names: true) patch_info = JSON.parse(patch_entry.blob, symbolize_names: true)
@@ -765,20 +767,15 @@ class W3DHub
patch_info[:updatedFiles].each do |file| patch_info[:updatedFiles].each do |file|
logger.debug(LOG_TAG) { " #{file}" } logger.debug(LOG_TAG) { " #{file}" }
patch = patch_mix.entries.find { |e| e.name.casecmp?(file) } patch_mix.entries.each do |entry|
target = target_mix.entries.find { |e| e.name.casecmp?(file) } target_mix.add_entry(entry: entry, replace: true)
if target
target_mix.entries[target_mix.entries.index(target)] = patch
else
target_mix.entries << patch
end end
end end
logger.info(LOG_TAG) { " Writing updated #{file_path}..." } if patch_info[:updatedFiles].size.positive? logger.info(LOG_TAG) { " Writing updated #{file_path}..." } if patch_info[:updatedFiles].size.positive?
temp_mix_path = "#{temp_path}/#{File.basename(file_path)}" temp_mix_path = "#{temp_path}/#{File.basename(file_path)}"
temp_mix = W3DHub::WWMix.new(path: temp_mix_path) temp_mix = W3DHub::WWMix.new(path: temp_mix_path, encrypted: target_mix.encrypted?)
target_mix.entries.each { |e| temp_mix.add_entry(entry: e) } target_mix.entries.each { |e| temp_mix.add_entry(entry: e, replace: true) }
unless temp_mix.save unless temp_mix.save
raise temp_mix.error_reason raise temp_mix.error_reason
end end

View File

@@ -61,10 +61,8 @@ class W3DHub
prefill: Store.settings[:server_list_username], prefill: Store.settings[:server_list_username],
accept_callback: accept_callback, accept_callback: accept_callback,
cancel_callback: cancel_callback, cancel_callback: cancel_callback,
# See: https://gitlab.com/danpaul88/brenbot/-/blob/master/Source/renlog.pm#L136-175
valid_callback: proc do |entry| valid_callback: proc do |entry|
entry.length > 1 && entry.length < 30 && (entry =~ /(:|!|&|%| )/i).nil? && entry.length.between?(3, 40) && (entry =~ /^[a-z0-9_\-\[\]]+$/i)
(entry =~ /[\001\002\037]/).nil? && (entry =~ /\\/).nil?
end end
) )
end end
@@ -123,7 +121,6 @@ class W3DHub
process_info = Process.create(**hash) process_info = Process.create(**hash)
pid = process_info.process_id pid = process_info.process_id
status = -1
until (status = Process.get_exitcode(pid)) until (status = Process.get_exitcode(pid))
if block if block

View File

@@ -1,4 +1,4 @@
class W3DHub class W3DHub
DIR_NAME = "W3DHubAlt".freeze DIR_NAME = "W3DHubAlt".freeze
VERSION = "0.9.0".freeze VERSION = "0.9.2".freeze
end end

View File

@@ -228,27 +228,34 @@ class W3DHub
@encrypted @encrypted
end end
def add_file(path:) def add_file(path:, replace: false)
return false unless File.exist?(path) return false unless File.exist?(path)
return false if File.directory?(path) return false if File.directory?(path)
info = EntryInfoHeader.new(0, 0, File.size(path)) entry = Entry.new(name: File.basename(path), path: path, info: EntryInfoHeader.new(0, 0, File.size(path)))
@entries << Entry.new(name: File.basename(path), path: path, info: info) add_entry(entry: entry, replace: replace)
true
end end
def add_blob(path:, blob:) def add_blob(path:, blob:, replace: false)
info = EntryInfoHeader.new(0, 0, blob.size) info = EntryInfoHeader.new(0, 0, blob.size)
@entries << Entry.new(name: File.basename(path), path: path, info: info, blob: blob) entry = Entry.new(name: File.basename(path), path: path, info: info, blob: blob)
into.crc32 = @entries.last.calculate_crc32 into.crc32 = @entries.last.calculate_crc32
true add_entry(entry: entry, replace: replace)
end end
def add_entry(entry:) def add_entry(entry:, replace: false)
@entries << entry duplicate = @entries.find { |e| e.name.upcase == entry.name.upcase }
if duplicate
if replace
@entries.delete(duplicate)
else
return false
end
end
@entries << entry
true true
end end