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:
2022-12-02 14:12:45 -06:00
parent 19a15e937e
commit 55c0f363e0
8 changed files with 126 additions and 96 deletions

View File

@@ -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]

View File

@@ -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

View File

@@ -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

View File

@@ -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] ||= {}

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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