mirror of
https://github.com/cyberarm/w3d_hub_linux_launcher.git
synced 2025-12-15 16:52:34 +00:00
Removed dependence on the bsdtar command, fixed Play Now button not doing anything if a server nickname wasn't set, refactor a bit so that the Server List's 'Join Server' button functionality can be reused for the Play Now button, installer now always unpacks into 'data/*' instead of 'Data/*'
This commit is contained in:
1
Gemfile
1
Gemfile
@@ -9,6 +9,7 @@ gem "ffi"
|
||||
gem "websocket-client-simple"
|
||||
gem "thread-local"
|
||||
gem "ircparser"
|
||||
gem "rubyzip"
|
||||
gem "win32-security", platforms: [:x64_mingw, :mingw]
|
||||
gem "win32-process", platforms: [:x64_mingw, :mingw]
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ GEM
|
||||
digest-crc (0.6.4)
|
||||
rake (>= 12.0.0, < 14.0.0)
|
||||
event_emitter (0.2.6)
|
||||
excon (0.93.1)
|
||||
excon (0.94.0)
|
||||
ffi (1.15.5)
|
||||
ffi (1.15.5-x64-mingw-ucrt)
|
||||
ffi (1.15.5-x64-mingw32)
|
||||
@@ -27,6 +27,7 @@ GEM
|
||||
public_suffix (5.0.0)
|
||||
rake (13.0.6)
|
||||
rexml (3.2.5)
|
||||
rubyzip (2.3.2)
|
||||
thread-local (1.1.0)
|
||||
websocket (1.2.9)
|
||||
websocket-client-simple (0.6.0)
|
||||
@@ -51,10 +52,11 @@ DEPENDENCIES
|
||||
ircparser
|
||||
launchy
|
||||
rexml
|
||||
rubyzip
|
||||
thread-local
|
||||
websocket-client-simple
|
||||
win32-process
|
||||
win32-security
|
||||
|
||||
BUNDLED WITH
|
||||
2.3.17
|
||||
2.3.26
|
||||
|
||||
15
lib/api.rb
15
lib/api.rb
@@ -45,7 +45,18 @@ class W3DHub
|
||||
end
|
||||
|
||||
begin
|
||||
Excon.post(url, headers: headers, body: body, tcp_nodelay: true, write_timeout: API_TIMEOUT, read_timeout: API_TIMEOUT, connection_timeout: API_TIMEOUT)
|
||||
Excon.post(
|
||||
url,
|
||||
headers: headers,
|
||||
body: body,
|
||||
tcp_nodelay: true,
|
||||
write_timeout: API_TIMEOUT,
|
||||
read_timeout: API_TIMEOUT,
|
||||
connection_timeout: API_TIMEOUT,
|
||||
idempotent: true,
|
||||
retry_limit: 6,
|
||||
retry_interval: 5
|
||||
)
|
||||
rescue Excon::Errors::Timeout
|
||||
logger.error(LOG_TAG) { "Connection to \"#{url}\" timed out after: #{API_TIMEOUT} seconds" }
|
||||
DummyResponse.new
|
||||
@@ -233,7 +244,7 @@ class W3DHub
|
||||
|
||||
logger.debug(LOG_TAG) { "Fetching GET \"#{url}\"..." }
|
||||
|
||||
Excon.get(url, headers: headers, body: body, persistent: true)
|
||||
Excon.get(url, headers: headers, body: body, persistent: true, idempotent: true, retry_limit: 6, retry_interval: 5)
|
||||
end
|
||||
|
||||
# Method: GET
|
||||
|
||||
@@ -231,8 +231,25 @@ class W3DHub
|
||||
|
||||
return false unless server
|
||||
|
||||
if Store.settings[:server_list_username].to_s.length.zero?
|
||||
W3DHub.prompt_for_nickname(
|
||||
accept_callback: proc do |entry|
|
||||
Store.settings[:server_list_username] = entry
|
||||
Store.settings.save_settings
|
||||
|
||||
if server.status.password
|
||||
W3DHub.prompt_for_password(
|
||||
accept_callback: proc do |password|
|
||||
join_server(app_id, channel, server)
|
||||
end
|
||||
)
|
||||
else
|
||||
join_server(app_id, channel, server)
|
||||
end
|
||||
end
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
def favorive(app_id, bool)
|
||||
Store.settings[:favorites] ||= {}
|
||||
|
||||
@@ -146,10 +146,7 @@ class W3DHub
|
||||
|
||||
# FIXME: Check that there is enough disk space
|
||||
|
||||
# tar present?
|
||||
bsdtar_present = W3DHub.command("#{W3DHub.tar_command} --help")
|
||||
fail!("FAIL FAST: `#{W3DHub.tar_command} --help` command failed, #{W3DHub.tar_command} is not installed. Will be unable to unpack packages.") unless bsdtar_present
|
||||
|
||||
# TODO: Is missing wine/proton really a failure condition?
|
||||
# Wine present?
|
||||
if W3DHub.unix?
|
||||
wine_present = W3DHub.command("which #{Store.settings[:wine_command]}")
|
||||
@@ -286,8 +283,8 @@ class W3DHub
|
||||
|
||||
manifest.files.each do |file|
|
||||
safe_file_name = file.name.gsub("\\", "/")
|
||||
# Fix borked data -> Data 'cause Windows don't care about capitalization
|
||||
safe_file_name.sub!("data/", "Data/") # unless File.exist?("#{path}/#{safe_file_name}")
|
||||
# Fix borked Data -> data 'cause Windows don't care about capitalization
|
||||
safe_file_name.sub!("Data/", "data/")
|
||||
|
||||
file_path = "#{path}/#{safe_file_name}"
|
||||
|
||||
@@ -490,8 +487,6 @@ class W3DHub
|
||||
unpack_package(package, path)
|
||||
end
|
||||
|
||||
repair_windows_case_insensitive(package, path)
|
||||
|
||||
if status
|
||||
@status.operations[:"#{package.checksum}"].value = package.custom_is_patch ? "Patched" : "Unpacked"
|
||||
@status.operations[:"#{package.checksum}"].progress = 1.0
|
||||
@@ -635,8 +630,9 @@ class W3DHub
|
||||
logger.info(LOG_TAG) { " #{package.name}:#{package.version}" }
|
||||
package_path = Cache.package_path(package.category, package.subcategory, package.name, package.version)
|
||||
|
||||
logger.info(LOG_TAG) { " Running #{W3DHub.tar_command} command: #{W3DHub.tar_command} -xf \"#{package_path}\" -C \"#{path}\"" }
|
||||
return W3DHub.command("#{W3DHub.tar_command} -xf \"#{package_path}\" -C \"#{path}\"")
|
||||
logger.info(LOG_TAG) { " Unpacking package \"#{package_path}\" in \"#{path}\"" }
|
||||
|
||||
return unzip(package_path, path)
|
||||
end
|
||||
|
||||
def apply_patch(package, path)
|
||||
@@ -647,19 +643,18 @@ class W3DHub
|
||||
|
||||
Cache.create_directories(temp_path, true)
|
||||
|
||||
logger.info(LOG_TAG) { " Running #{W3DHub.tar_command} command: #{W3DHub.tar_command} -xf \"#{package_path}\" -C \"#{temp_path}\"" }
|
||||
W3DHub.command("#{W3DHub.tar_command} -xf \"#{package_path}\" -C \"#{temp_path}\"")
|
||||
logger.info(LOG_TAG) { " Unpacking patch \"#{package_path}\" in \"#{temp_path}\"" }
|
||||
unzip(package_path, temp_path)
|
||||
|
||||
logger.info(LOG_TAG) { " Loading #{temp_path}/#{manifest_file.name}.patch..." }
|
||||
patch_mix = W3DHub::Mixer::Reader.new(file_path: "#{temp_path}/#{manifest_file.name}.patch", ignore_crc_mismatches: false)
|
||||
# Fix borked Data -> data 'cause Windows don't care about capitalization
|
||||
safe_file_name = "#{manifest_file.name.sub('Data/', 'data/')}"
|
||||
|
||||
logger.info(LOG_TAG) { " Loading #{temp_path}/#{safe_file_name}.patch..." }
|
||||
patch_mix = W3DHub::Mixer::Reader.new(file_path: "#{temp_path}/#{safe_file_name}.patch", ignore_crc_mismatches: false)
|
||||
patch_info = JSON.parse(patch_mix.package.files.find { |f| f.name == ".w3dhub.patch" || f.name == ".bhppatch" }.data, symbolize_names: true)
|
||||
|
||||
repaired_path = "#{path}/#{manifest_file.name}"
|
||||
# Fix borked data -> Data 'cause Windows don't care about capitalization
|
||||
repaired_path = "#{path}/#{manifest_file.name.sub('data', 'Data')}" unless File.exist?(repaired_path) && path
|
||||
|
||||
logger.info(LOG_TAG) { " Loading #{repaired_path}..." }
|
||||
target_mix = W3DHub::Mixer::Reader.new(file_path: repaired_path, ignore_crc_mismatches: false)
|
||||
logger.info(LOG_TAG) { " Loading #{path}/#{safe_file_name}..." }
|
||||
target_mix = W3DHub::Mixer::Reader.new(file_path: "#{path}/#{safe_file_name}", ignore_crc_mismatches: false)
|
||||
|
||||
logger.info(LOG_TAG) { " Removing files..." } if patch_info[:removedFiles].size.positive?
|
||||
patch_info[:removedFiles].each do |file|
|
||||
@@ -681,27 +676,38 @@ class W3DHub
|
||||
end
|
||||
end
|
||||
|
||||
logger.info(LOG_TAG) { " Writing updated #{repaired_path}..." } if patch_info[:updatedFiles].size.positive?
|
||||
W3DHub::Mixer::Writer.new(file_path: repaired_path, package: target_mix.package, memory_buffer: true)
|
||||
logger.info(LOG_TAG) { " Writing updated #{path}/#{safe_file_name}..." } if patch_info[:updatedFiles].size.positive?
|
||||
W3DHub::Mixer::Writer.new(file_path: "#{path}/#{safe_file_name}", package: target_mix.package, memory_buffer: true)
|
||||
|
||||
FileUtils.remove_dir(temp_path)
|
||||
|
||||
true
|
||||
end
|
||||
|
||||
def repair_windows_case_insensitive(package, path)
|
||||
# Windows is just confused
|
||||
return true if W3DHub.windows?
|
||||
def unzip(package_path, path)
|
||||
stream = Zip::InputStream.new(File.open(package_path))
|
||||
|
||||
# Force data/ to Data/
|
||||
return true unless File.exist?("#{path}/data") && File.directory?("#{path}/data")
|
||||
while (entry = stream.get_next_entry)
|
||||
|
||||
logger.info(LOG_TAG) { " Moving #{path}/data/ to #{path}/Data/" }
|
||||
safe_file_name = entry.name.gsub("\\", "/")
|
||||
# Fix borked Data -> data 'cause Windows don't care about capitalization
|
||||
safe_file_name.sub!("Data/", "data/")
|
||||
|
||||
FileUtils.mv(Dir.glob("#{path}/data/**"), "#{path}/Data", force: true)
|
||||
FileUtils.remove_dir("#{path}/data", force: true)
|
||||
dir_path = "#{path}/#{File.dirname(safe_file_name)}"
|
||||
unless dir_path.end_with?("/.") || Dir.exist?(dir_path)
|
||||
FileUtils.mkdir_p(dir_path)
|
||||
end
|
||||
|
||||
true
|
||||
File.open("#{path}/#{safe_file_name}", "wb") do |f|
|
||||
i = entry.get_input_stream
|
||||
|
||||
while (chunk = i.read(32_000_000)) # Read up to ~32 MB per chunk
|
||||
f.write chunk
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -32,11 +32,46 @@ class W3DHub
|
||||
linux? || mac?
|
||||
end
|
||||
|
||||
def self.tar_command
|
||||
if windows?
|
||||
"tar"
|
||||
def self.prompt_for_nickname(accept_callback: nil, cancel_callback: nil)
|
||||
CyberarmEngine::Window.instance.push_state(
|
||||
W3DHub::States::PromptDialog,
|
||||
title: I18n.t(:"server_browser.set_nickname"),
|
||||
message: I18n.t(:"server_browser.set_nickname_message"),
|
||||
prefill: Store.settings[:server_list_username],
|
||||
accept_callback: accept_callback,
|
||||
cancel_callback: cancel_callback,
|
||||
# See: https://gitlab.com/danpaul88/brenbot/-/blob/master/Source/renlog.pm#L136-175
|
||||
valid_callback: proc do |entry|
|
||||
entry.length > 1 && entry.length < 30 && (entry =~ /(:|!|&|%| )/i).nil? &&
|
||||
(entry =~ /[\001\002\037]/).nil? && (entry =~ /\\/).nil?
|
||||
end
|
||||
)
|
||||
end
|
||||
|
||||
def self.prompt_for_password(accept_callback: nil, cancel_callback: nil)
|
||||
CyberarmEngine::Window.instance.push_state(
|
||||
W3DHub::States::PromptDialog,
|
||||
title: I18n.t(:"server_browser.enter_password"),
|
||||
message: I18n.t(:"server_browser.enter_password_message"),
|
||||
input_type: :password,
|
||||
accept_callback: accept_callback,
|
||||
cancel_callback: cancel_callback,
|
||||
valid_callback: proc { |entry| entry.length.positive? }
|
||||
)
|
||||
end
|
||||
|
||||
def self.join_server(server, password)
|
||||
if (
|
||||
(server.status.password && password.length.positive?) ||
|
||||
!server.status.password) &&
|
||||
Store.settings[:server_list_username].to_s.length.positive?
|
||||
|
||||
Store.application_manager.join_server(
|
||||
server.game,
|
||||
server.channel, server, password
|
||||
)
|
||||
else
|
||||
"bsdtar"
|
||||
CyberarmEngine::Window.instance.push_state(W3DHub::States::MessageDialog, type: "?", title: "?", message: "?")
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -80,7 +80,7 @@ class W3DHub
|
||||
@nickname_label = inscription "#{Store.settings[:server_list_username]}"
|
||||
image "#{GAME_ROOT_PATH}/media/ui_icons/wrench.png", height: 16, hover: { color: 0xaa_ffffff }, tip: I18n.t(:"server_browser.set_nickname") do
|
||||
# Prompt for player name
|
||||
prompt_for_nickname(
|
||||
W3DHub.prompt_for_nickname(
|
||||
accept_callback: proc do |entry|
|
||||
@nickname_label.value = entry
|
||||
Store.settings[:server_list_username] = entry
|
||||
@@ -390,32 +390,32 @@ class W3DHub
|
||||
# prompt for password
|
||||
# Launch game
|
||||
if Store.settings[:server_list_username].to_s.length.zero?
|
||||
prompt_for_nickname(
|
||||
W3DHub.prompt_for_nickname(
|
||||
accept_callback: proc do |entry|
|
||||
@nickname_label.value = entry
|
||||
Store.settings[:server_list_username] = entry
|
||||
Store.settings.save_settings
|
||||
|
||||
if server.status.password
|
||||
prompt_for_password(
|
||||
W3DHub.prompt_for_password(
|
||||
accept_callback: proc do |password|
|
||||
join_server(server, password)
|
||||
W3DHub.join_server(server, password)
|
||||
end
|
||||
)
|
||||
else
|
||||
join_server(server, nil)
|
||||
W3DHub.join_server(server, nil)
|
||||
end
|
||||
end
|
||||
)
|
||||
else
|
||||
if server.status.password
|
||||
prompt_for_password(
|
||||
W3DHub.prompt_for_password(
|
||||
accept_callback: proc do |password|
|
||||
join_server(server, password)
|
||||
W3DHub.join_server(server, password)
|
||||
end
|
||||
)
|
||||
else
|
||||
join_server(server, nil)
|
||||
W3DHub.join_server(server, nil)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -599,49 +599,6 @@ class W3DHub
|
||||
data
|
||||
end
|
||||
|
||||
def prompt_for_nickname(accept_callback: nil, cancel_callback: nil)
|
||||
push_state(
|
||||
W3DHub::States::PromptDialog,
|
||||
title: I18n.t(:"server_browser.set_nickname"),
|
||||
message: I18n.t(:"server_browser.set_nickname_message"),
|
||||
prefill: Store.settings[:server_list_username],
|
||||
accept_callback: accept_callback,
|
||||
cancel_callback: cancel_callback,
|
||||
# See: https://gitlab.com/danpaul88/brenbot/-/blob/master/Source/renlog.pm#L136-175
|
||||
valid_callback: proc do |entry|
|
||||
entry.length > 1 && entry.length < 30 && (entry =~ /(:|!|&|%| )/i).nil? &&
|
||||
(entry =~ /[\001\002\037]/).nil? && (entry =~ /\\/).nil?
|
||||
end
|
||||
)
|
||||
end
|
||||
|
||||
def prompt_for_password(accept_callback: nil, cancel_callback: nil)
|
||||
push_state(
|
||||
W3DHub::States::PromptDialog,
|
||||
title: I18n.t(:"server_browser.enter_password"),
|
||||
message: I18n.t(:"server_browser.enter_password_message"),
|
||||
input_type: :password,
|
||||
accept_callback: accept_callback,
|
||||
cancel_callback: cancel_callback,
|
||||
valid_callback: proc { |entry| entry.length.positive? }
|
||||
)
|
||||
end
|
||||
|
||||
def join_server(server, password)
|
||||
if (
|
||||
(server.status.password && password.length.positive?) ||
|
||||
!server.status.password) &&
|
||||
Store.settings[:server_list_username].to_s.length.positive?
|
||||
|
||||
Store.application_manager.join_server(
|
||||
server.game,
|
||||
server.channel, server, password
|
||||
)
|
||||
else
|
||||
window.push_state(W3DHub::States::MessageDialog, type: "?", title: "?", message: "?")
|
||||
end
|
||||
end
|
||||
|
||||
def formatted_score(int)
|
||||
int.to_s.reverse.scan(/.{1,3}/).join(",").reverse
|
||||
end
|
||||
|
||||
@@ -7,6 +7,7 @@ require "rexml"
|
||||
require "logger"
|
||||
require "time"
|
||||
require "base64"
|
||||
require "zip"
|
||||
|
||||
class W3DHub
|
||||
W3DHUB_DEBUG = ARGV.join.include?("--debug")
|
||||
@@ -55,8 +56,8 @@ end
|
||||
begin
|
||||
require_relative "../cyberarm_engine/lib/cyberarm_engine"
|
||||
rescue LoadError => e
|
||||
logger.warn(W3D::LOG_TAG) { "Failed to load local cyberarm_engine:" }
|
||||
logger.warn(W3D::LOG_TAG) { e }
|
||||
logger.warn(W3DHub::LOG_TAG) { "Failed to load local cyberarm_engine:" }
|
||||
logger.warn(W3DHub::LOG_TAG) { e }
|
||||
|
||||
require "cyberarm_engine"
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user