mirror of
https://github.com/cyberarm/w3d_hub_linux_launcher.git
synced 2025-12-16 09:12:35 +00:00
Compare commits
5 Commits
4997cfabb0
...
v0.8.0
| Author | SHA1 | Date | |
|---|---|---|---|
| 3c565e6fee | |||
| 2dc750a686 | |||
| ed119a4925 | |||
| e4d99aac00 | |||
| e9b8638c27 |
@@ -235,11 +235,11 @@ class W3DHub
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def join_server(app_id, channel, server, password = nil)
|
def join_server(app_id, channel, server, username = Store.settings[:server_list_username], password = nil, multi = false)
|
||||||
if installed?(app_id, channel) && Store.settings[:server_list_username].to_s.length.positive?
|
if installed?(app_id, channel) && username.to_s.length.positive?
|
||||||
run(
|
run(
|
||||||
app_id, channel,
|
app_id, channel,
|
||||||
"+connect #{server.address}:#{server.port} +netplayername #{Store.settings[:server_list_username]}#{password ? " +password \"#{password}\"" : ""}"
|
"+connect #{server.address}:#{server.port} +netplayername #{username}#{password ? " +password \"#{password}\"" : ""}#{multi ? " +multi" : ""}"
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -112,9 +112,29 @@ class W3DHub
|
|||||||
@task_state == :failed
|
@task_state == :failed
|
||||||
end
|
end
|
||||||
|
|
||||||
# Helper method to normalize file paths for case-insensitive comparison
|
def normalize_path(path, base_path)
|
||||||
def normalize_path(path)
|
path = path.to_s.gsub("\\", "/")
|
||||||
path.to_s.gsub("\\", "/").downcase
|
return path if W3DHub.windows? # Windows is easy, or annoying, depending how you look at it...
|
||||||
|
|
||||||
|
constructed_path = base_path
|
||||||
|
|
||||||
|
split_path = path.split("/")
|
||||||
|
split_path.each do |segment|
|
||||||
|
Dir.glob("#{constructed_path}/*").each do |part|
|
||||||
|
next unless "#{constructed_path}/#{segment}".downcase == part.downcase
|
||||||
|
|
||||||
|
constructed_path = part
|
||||||
|
|
||||||
|
break if File.file?(constructed_path)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Find file if it exists, otherwise downcase the `path` sans `base_path`
|
||||||
|
if "#{base_path}/#{path}".length == constructed_path.length
|
||||||
|
constructed_path
|
||||||
|
else
|
||||||
|
"#{base_path}/#{path.downcase}"
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def failure_reason
|
def failure_reason
|
||||||
@@ -300,15 +320,13 @@ class W3DHub
|
|||||||
@files.reverse.each do |file|
|
@files.reverse.each do |file|
|
||||||
break unless folder_exists
|
break unless folder_exists
|
||||||
|
|
||||||
# Normalize file paths to handle case-insensitive comparisons
|
file_path = normalize_path(file.name, path)
|
||||||
safe_file_name = normalize_path(file.name)
|
|
||||||
file_path = "#{path}/#{safe_file_name}"
|
|
||||||
|
|
||||||
processed_files += 1
|
processed_files += 1
|
||||||
@status.progress = processed_files.to_f / file_count
|
@status.progress = processed_files.to_f / file_count
|
||||||
|
|
||||||
next if file.removed_since
|
next if file.removed_since
|
||||||
next if accepted_files.key?(safe_file_name)
|
next if accepted_files.key?(file_path)
|
||||||
|
|
||||||
unless File.exist?(file_path)
|
unless File.exist?(file_path)
|
||||||
rejected_files << { file: file, manifest_version: file.version }
|
rejected_files << { file: file, manifest_version: file.version }
|
||||||
@@ -328,7 +346,7 @@ class W3DHub
|
|||||||
logger.info(LOG_TAG) { file.inspect } if file.checksum.nil?
|
logger.info(LOG_TAG) { file.inspect } if file.checksum.nil?
|
||||||
|
|
||||||
if digest.hexdigest.upcase == file.checksum.upcase
|
if digest.hexdigest.upcase == file.checksum.upcase
|
||||||
accepted_files[safe_file_name] = file.version
|
accepted_files[file_path] = file.version
|
||||||
logger.info(LOG_TAG) { "[#{file.version}] Verified file: #{file_path}" }
|
logger.info(LOG_TAG) { "[#{file.version}] Verified file: #{file_path}" }
|
||||||
else
|
else
|
||||||
rejected_files << { file: file, manifest_version: file.version }
|
rejected_files << { file: file, manifest_version: file.version }
|
||||||
@@ -532,7 +550,7 @@ class W3DHub
|
|||||||
logger.info(LOG_TAG) { " #{file.name}" }
|
logger.info(LOG_TAG) { " #{file.name}" }
|
||||||
|
|
||||||
path = Cache.install_path(@application, @channel)
|
path = Cache.install_path(@application, @channel)
|
||||||
file_path = "#{path}/#{file.name}".sub('Data/', 'data/')
|
file_path = normalize_path(file.name, path)
|
||||||
|
|
||||||
File.delete(file_path) if File.exist?(file_path)
|
File.delete(file_path) if File.exist?(file_path)
|
||||||
|
|
||||||
@@ -565,7 +583,7 @@ class W3DHub
|
|||||||
def write_paths_ini
|
def write_paths_ini
|
||||||
path = Cache.install_path(@application, @channel)
|
path = Cache.install_path(@application, @channel)
|
||||||
|
|
||||||
File.open("#{path}/data/paths.ini", "w") do |file|
|
File.open(normalize_path("data/paths.ini", path), "w") do |file|
|
||||||
file.puts("[paths]")
|
file.puts("[paths]")
|
||||||
file.puts("RegBase=W3D Hub")
|
file.puts("RegBase=W3D Hub")
|
||||||
file.puts("RegClient=#{@application.category}\\#{@application.id}-#{@channel.id}")
|
file.puts("RegClient=#{@application.category}\\#{@application.id}-#{@channel.id}")
|
||||||
@@ -710,15 +728,15 @@ class W3DHub
|
|||||||
logger.info(LOG_TAG) { " Unpacking patch \"#{package_path}\" in \"#{temp_path}\"" }
|
logger.info(LOG_TAG) { " Unpacking patch \"#{package_path}\" in \"#{temp_path}\"" }
|
||||||
unzip(package_path, temp_path)
|
unzip(package_path, temp_path)
|
||||||
|
|
||||||
# Normalize the path to handle case-insensitivity consistently
|
file_path = normalize_path(manifest_file.name, path)
|
||||||
safe_file_name = normalize_path(manifest_file.name)
|
temp_file_path = normalize_path(manifest_file.name, temp_path)
|
||||||
|
|
||||||
logger.info(LOG_TAG) { " Loading #{temp_path}/#{safe_file_name}.patch..." }
|
logger.info(LOG_TAG) { " Loading #{temp_file_path}.patch..." }
|
||||||
patch_mix = W3DHub::Mixer::Reader.new(file_path: "#{temp_path}/#{safe_file_name}.patch", ignore_crc_mismatches: false)
|
patch_mix = W3DHub::Mixer::Reader.new(file_path: "#{temp_file_path}.patch", ignore_crc_mismatches: false)
|
||||||
patch_info = JSON.parse(patch_mix.package.files.find { |f| f.name.casecmp?(".w3dhub.patch") || f.name.casecmp?(".bhppatch") }.data, symbolize_names: true)
|
patch_info = JSON.parse(patch_mix.package.files.find { |f| f.name.casecmp?(".w3dhub.patch") || f.name.casecmp?(".bhppatch") }.data, symbolize_names: true)
|
||||||
|
|
||||||
logger.info(LOG_TAG) { " Loading #{path}/#{safe_file_name}..." }
|
logger.info(LOG_TAG) { " Loading #{file_path}..." }
|
||||||
target_mix = W3DHub::Mixer::Reader.new(file_path: "#{path}/#{safe_file_name}", ignore_crc_mismatches: false)
|
target_mix = W3DHub::Mixer::Reader.new(file_path: "#{file_path}", ignore_crc_mismatches: false)
|
||||||
|
|
||||||
logger.info(LOG_TAG) { " Removing files..." } if patch_info[:removedFiles].size.positive?
|
logger.info(LOG_TAG) { " Removing files..." } if patch_info[:removedFiles].size.positive?
|
||||||
patch_info[:removedFiles].each do |file|
|
patch_info[:removedFiles].each do |file|
|
||||||
@@ -740,8 +758,8 @@ class W3DHub
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
logger.info(LOG_TAG) { " Writing updated #{path}/#{safe_file_name}..." } if patch_info[:updatedFiles].size.positive?
|
logger.info(LOG_TAG) { " Writing updated #{file_path}..." } if patch_info[:updatedFiles].size.positive?
|
||||||
W3DHub::Mixer::Writer.new(file_path: "#{path}/#{safe_file_name}", package: target_mix.package, memory_buffer: true, encrypted: target_mix.encrypted?)
|
W3DHub::Mixer::Writer.new(file_path: "#{file_path}", package: target_mix.package, memory_buffer: true, encrypted: target_mix.encrypted?)
|
||||||
|
|
||||||
FileUtils.remove_dir(temp_path)
|
FileUtils.remove_dir(temp_path)
|
||||||
|
|
||||||
@@ -753,14 +771,14 @@ class W3DHub
|
|||||||
|
|
||||||
while (entry = stream.get_next_entry)
|
while (entry = stream.get_next_entry)
|
||||||
# Normalize the path to handle case-insensitivity consistently
|
# Normalize the path to handle case-insensitivity consistently
|
||||||
safe_file_name = normalize_path(entry.name)
|
file_path = normalize_path(entry.name, path)
|
||||||
|
|
||||||
dir_path = "#{path}/#{File.dirname(safe_file_name)}"
|
dir_path = File.dirname(file_path)
|
||||||
unless dir_path.end_with?("/.") || Dir.exist?(dir_path)
|
unless dir_path.end_with?("/.") || Dir.exist?(dir_path)
|
||||||
FileUtils.mkdir_p(dir_path)
|
FileUtils.mkdir_p(dir_path)
|
||||||
end
|
end
|
||||||
|
|
||||||
File.open("#{path}/#{safe_file_name}", "wb") do |f|
|
File.open(file_path, "wb") do |f|
|
||||||
i = entry.get_input_stream
|
i = entry.get_input_stream
|
||||||
|
|
||||||
while (chunk = i.read(32_000_000)) # Read up to ~32 MB per chunk
|
while (chunk = i.read(32_000_000)) # Read up to ~32 MB per chunk
|
||||||
|
|||||||
@@ -90,6 +90,10 @@ class W3DHub
|
|||||||
# Download a W3D Hub package
|
# Download a W3D Hub package
|
||||||
def self.fetch_package(package, block)
|
def self.fetch_package(package, block)
|
||||||
endpoint_download_url = package.download_url || "#{Api::W3DHUB_API_ENDPOINT}/apis/launcher/1/get-package"
|
endpoint_download_url = package.download_url || "#{Api::W3DHUB_API_ENDPOINT}/apis/launcher/1/get-package"
|
||||||
|
if package.download_url
|
||||||
|
uri_path = package.download_url.split("/").last
|
||||||
|
endpoint_download_url = package.download_url.sub(uri_path, URI.encode_uri_component(uri_path))
|
||||||
|
end
|
||||||
path = package_path(package.category, package.subcategory, package.name, package.version)
|
path = package_path(package.category, package.subcategory, package.name, package.version)
|
||||||
headers = { "Content-Type": "application/x-www-form-urlencoded", "User-Agent": Api::USER_AGENT }
|
headers = { "Content-Type": "application/x-www-form-urlencoded", "User-Agent": Api::USER_AGENT }
|
||||||
headers["Authorization"] = "Bearer #{Store.account.access_token}" if Store.account && !package.download_url
|
headers["Authorization"] = "Bearer #{Store.account.access_token}" if Store.account && !package.download_url
|
||||||
|
|||||||
@@ -81,15 +81,19 @@ class W3DHub
|
|||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.join_server(server, password)
|
def self.join_server(server:, username: Store.settings[:server_list_username], password: nil, multi: false)
|
||||||
if (
|
if (
|
||||||
(server.status.password && password.length.positive?) ||
|
(server.status.password && password.length.positive?) ||
|
||||||
!server.status.password) &&
|
!server.status.password) &&
|
||||||
Store.settings[:server_list_username].to_s.length.positive?
|
username.to_s.length.positive?
|
||||||
|
|
||||||
Store.application_manager.join_server(
|
Store.application_manager.join_server(
|
||||||
server.game,
|
server.game,
|
||||||
server.channel, server, password
|
server.channel,
|
||||||
|
server,
|
||||||
|
username,
|
||||||
|
password,
|
||||||
|
multi
|
||||||
)
|
)
|
||||||
else
|
else
|
||||||
CyberarmEngine::Window.instance.push_state(W3DHub::States::MessageDialog, type: "?", title: "?", message: "?")
|
CyberarmEngine::Window.instance.push_state(W3DHub::States::MessageDialog, type: "?", title: "?", message: "?")
|
||||||
|
|||||||
@@ -375,7 +375,7 @@ class W3DHub
|
|||||||
end
|
end
|
||||||
|
|
||||||
container = stack(fill: true, width: 1.0, padding: 8) do
|
container = stack(fill: true, width: 1.0, padding: 8) do
|
||||||
image_path = File.exist?("#{GAME_ROOT_PATH}/media/icons/#{game.id}.png") ? "#{GAME_ROOT_PATH}/media/icons/#{game.id}.png" : "#{GAME_ROOT_PATH}/media/icons/default_icon.png"
|
image_path = File.exist?("#{CACHE_PATH}/#{game.id}.png") ? "#{CACHE_PATH}/#{game.id}.png" : "#{GAME_ROOT_PATH}/media/icons/default_icon.png"
|
||||||
flow(width: 1.0, margin_top: 8) do
|
flow(width: 1.0, margin_top: 8) do
|
||||||
flow(fill: true)
|
flow(fill: true)
|
||||||
image image_path, width: 0.5
|
image image_path, width: 0.5
|
||||||
|
|||||||
@@ -410,11 +410,11 @@ class W3DHub
|
|||||||
if server.status.password
|
if server.status.password
|
||||||
W3DHub.prompt_for_password(
|
W3DHub.prompt_for_password(
|
||||||
accept_callback: proc do |password|
|
accept_callback: proc do |password|
|
||||||
W3DHub.join_server(server, password)
|
W3DHub.join_server(server: server, password: password)
|
||||||
end
|
end
|
||||||
)
|
)
|
||||||
else
|
else
|
||||||
W3DHub.join_server(server, nil)
|
W3DHub.join_server(server: server)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
)
|
)
|
||||||
@@ -422,18 +422,24 @@ class W3DHub
|
|||||||
if server.status.password
|
if server.status.password
|
||||||
W3DHub.prompt_for_password(
|
W3DHub.prompt_for_password(
|
||||||
accept_callback: proc do |password|
|
accept_callback: proc do |password|
|
||||||
W3DHub.join_server(server, password)
|
W3DHub.join_server(server: server, password: password)
|
||||||
end
|
end
|
||||||
)
|
)
|
||||||
else
|
else
|
||||||
W3DHub.join_server(server, nil)
|
W3DHub.join_server(server: server)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if W3DHUB_DEVELOPER
|
if W3DHUB_DEVELOPER
|
||||||
list_box(items: (1..12).to_a.map(&:to_s), margin_left: 16, width: 72, tip: "Number of game clients", enabled: (game_installed && !game_updatable), **TESTING_BUTTON)
|
client_instances = list_box(items: (1..12).to_a.map(&:to_s), margin_left: 16, width: 72, tip: "Number of game clients", enabled: (game_installed && !game_updatable), **TESTING_BUTTON)
|
||||||
button "Multijoin", tip: "Launch multiple clients with configured username_\#{number}", enabled: (game_installed && !game_updatable), **TESTING_BUTTON
|
button("Multijoin", tip: "Launch multiple clients with configured username_\#{number}", enabled: (game_installed && !game_updatable), **TESTING_BUTTON) do
|
||||||
|
username = Store.settings[:server_list_username]
|
||||||
|
|
||||||
|
client_instances.value.to_i.times do |i|
|
||||||
|
W3DHub.join_server(server: server, username: format("%s_%d", username, i), multi: true)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
flow(fill: true)
|
flow(fill: true)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
class W3DHub
|
class W3DHub
|
||||||
DIR_NAME = "W3DHubAlt"
|
DIR_NAME = "W3DHubAlt"
|
||||||
VERSION = "0.7.0"
|
VERSION = "0.8.0"
|
||||||
end
|
end
|
||||||
|
|||||||
Reference in New Issue
Block a user