diff --git a/lib/application_manager.rb b/lib/application_manager.rb index 1092c4a..80287b5 100644 --- a/lib/application_manager.rb +++ b/lib/application_manager.rb @@ -22,7 +22,6 @@ class W3DHub installer = Installer.new(app_id, channel) @tasks.push(installer) - # installer.start end def import(app_id, channel, path) @@ -81,7 +80,7 @@ class W3DHub end def installing?(app_id, channel) - @tasks.find { |t| t.is_a?(Installer) && t.app_id == app_id } + @tasks.find { |t| t.is_a?(Installer) && t.app_id == app_id && t.release_channel == channel } end # No application tasks are being done @@ -91,11 +90,27 @@ class W3DHub # Whether some operation is in progress def busy? - @tasks.any? { |t| t.state == :running } + current_task end def current_task - @tasks.first#find { |t| t.state == :running } + @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 diff --git a/lib/application_manager/task.rb b/lib/application_manager/task.rb index fd5f0b0..62144bd 100644 --- a/lib/application_manager/task.rb +++ b/lib/application_manager/task.rb @@ -4,7 +4,8 @@ class W3DHub include CyberarmEngine::Common attr_reader :app_id, :release_channel, :application, :channel, - :total_bytes_to_download, :bytes_downloaded, :packages_to_download + :total_bytes_to_download, :bytes_downloaded, :packages_to_download, + :manifests def initialize(app_id, release_channel) @app_id = app_id @@ -19,12 +20,18 @@ class W3DHub @total_bytes_to_download = -1 @bytes_downloaded = -1 + @manifests = [] + setup end def setup end + def type + raise NotImplementedError + end + def state @task_state end @@ -41,6 +48,9 @@ class W3DHub @task_state = :failed unless status @task_state = :complete unless @task_state == :failed + + hide_application_taskbar if @task_state == :failed + send_message_dialog(:failure, "Task #{type.inspect} failed for #{@application.name}", @task_failure_reason) if @task_state == :failed end end @@ -85,6 +95,14 @@ class W3DHub window.main_thread_queue << block end + def send_message_dialog(type, title, message) + run_on_main_thread( + proc do + window.push_state(W3DHub::States::MessageDialog, type: type, title: title, message: message) + end + ) + end + def update_application_taskbar(message, status, progress) run_on_main_thread( proc do @@ -115,11 +133,9 @@ class W3DHub ############### def fetch_manifests - manifests = [] - if fetch_manifest("games", app_id, "manifest.xml", @channel.current_version) manifest = load_manifest("games", app_id, "manifest.xml", @channel.current_version) - manifests << manifest + @manifests << manifest until(manifest.full?) fetch_manifest("games", app_id, "manifest.xml", manifest.base_version) @@ -128,7 +144,7 @@ class W3DHub end end - manifests + @manifests end def build_package_list(manifests) @@ -140,6 +156,11 @@ class W3DHub manifest.files.each do |file| next if file.removed? # No package data + if file.patch? + fail!("#{@application.name} requires patches. Patching is not yet supported.") + break + end + next if packages.detect do |pkg| pkg.category == "games" && pkg.subcategory == @app_id && @@ -235,8 +256,9 @@ class W3DHub def fetch_manifest(category, subcategory, name, version, &block) # Check for and integrity of local manifest + package = Api.package_details([{ category: category, subcategory: subcategory, name: name, version: version }]) + if File.exist?(Cache.package_path(category, subcategory, name, version)) - package = Api.package_details([{ category: category, subcategory: subcategory, name: name, version: version }]) verified = verify_package(package) # download manifest if not valid diff --git a/lib/application_manager/tasks/installer.rb b/lib/application_manager/tasks/installer.rb index 1e1bfa8..8af379e 100644 --- a/lib/application_manager/tasks/installer.rb +++ b/lib/application_manager/tasks/installer.rb @@ -1,6 +1,10 @@ class W3DHub class ApplicationManager class Installer < Task + def type + :installer + end + def execute_task update_application_taskbar("Downloading #{@application.name}...", "Fetching manifests...", 0.0) manifests = fetch_manifests diff --git a/lib/page.rb b/lib/page.rb index 25410ec..eef9942 100644 --- a/lib/page.rb +++ b/lib/page.rb @@ -19,6 +19,9 @@ class W3DHub @host.main_thread_queue end + def update_application_manager_status + end + def options=(options) @options = options end diff --git a/lib/pages/games.rb b/lib/pages/games.rb index b14e77e..a08f2b7 100644 --- a/lib/pages/games.rb +++ b/lib/pages/games.rb @@ -137,7 +137,8 @@ class W3DHub button "Single Player", margin_left: 24 else unless game.id == "ren" - button "Install", margin_left: 24 do + button "Install", margin_left: 24, enabled: !window.application_manager.task?(:installer, game.id, channel.name) do |button| + button.enabled = false window.application_manager.install(game.id, channel.name) end end diff --git a/lib/states/boot.rb b/lib/states/boot.rb index 061ed87..e9c352e 100644 --- a/lib/states/boot.rb +++ b/lib/states/boot.rb @@ -2,6 +2,8 @@ class W3DHub class States class Boot < CyberarmEngine::GuiState def setup + theme(W3DHub::THEME) + background 0xff_252525 @fraction = 0.0 @@ -18,7 +20,7 @@ class W3DHub stack(width: 1.0, height: 0.925) do end - @progressbar = progress height: 0.025, width: 1.0, fraction_background: 0xff_00acff, border_thickness: 0 + @progressbar = progress height: 0.025, width: 1.0 flow(width: 1.0, height: 0.05, padding_left: 16, padding_right: 16, padding_bottom: 8, padding_top: 8) do @status_label = caption "Starting #{NAME}...", width: 0.5 diff --git a/lib/states/interface.rb b/lib/states/interface.rb index 96bc8cf..b7065f4 100644 --- a/lib/states/interface.rb +++ b/lib/states/interface.rb @@ -15,62 +15,7 @@ class W3DHub @main_thread_queue = [] - theme({ - ToolTip: { - background: 0xff_dedede, - color: 0xaa_000000, - text_size: 18, - text_border: false, - text_shadow: false, - }, - TextBlock: { - # font: "Inconsolata", - text_border: false, - text_shadow: true, - text_shadow_size: 1, - text_shadow_color: 0x88_000000, - }, - EditLine: { - border_thickness: 2, - border_color: Gosu::Color::WHITE, - hover: { color: Gosu::Color::WHITE } - }, - Link: { - color: 0xff_cdcdcd, - hover: { - color: Gosu::Color::WHITE - }, - active: { - color: 0xff_eeeeee - } - }, - Button: { - text_size: 18, - padding_top: 8, - padding_left: 32, - padding_right: 32, - padding_bottom: 8, - border_color: Gosu::Color::NONE, - background: 0xff_00acff, - hover: { - background: 0xff_bee6fd - }, - active: { - background: 0xff_add5ec - } - }, - ToggleButton: { - padding_left: 8, - padding_right: 8, - width: 18, - image_width: 18, - checkmark_image: "#{GAME_ROOT_PATH}/media/ui_icons/checkmark.png" - }, - Progress: { - fraction_background: 0xff_00acff, - border_thickness: 0 - } - }) + theme(W3DHub::THEME) stack(width: 1.0, height: 1.0, border_thickness: 1, border_color: 0xff_aaaaaa) do background 0xff_252525 @@ -227,6 +172,10 @@ class W3DHub @page.focus end + def update_application_manager_status + @page.update_application_manager_status + end + def show_application_taskbar @application_taskbar_container.show end diff --git a/lib/states/message_dialog.rb b/lib/states/message_dialog.rb new file mode 100644 index 0000000..67078e8 --- /dev/null +++ b/lib/states/message_dialog.rb @@ -0,0 +1,35 @@ +class W3DHub + class States + class MessageDialog < CyberarmEngine::GuiState + def setup + window.show_cursor = true + + theme(W3DHub::THEME) + + background 0xee_444444 + + stack(width: 1.0, height: 1.0, margin: 128, padding: 8, background: 0xee_222222) do + flow(width: 1.0, height: 0.06) do + image "#{GAME_ROOT_PATH}/media/ui_icons/warning.png", width: 0.04, align: :center, color: 0xff_ff8800 + + tagline "#{@options[:title]}", width: 0.9, text_align: :center + end + + para @options[:message], width: 1.0, height: 0.7, padding: 8 + + button "Okay", width: 1.0, margin_top: 64 do + pop_state + end + end + end + + def draw + previous_state&.draw + + Gosu.flush + + super + end + end + end +end diff --git a/lib/theme.rb b/lib/theme.rb new file mode 100644 index 0000000..c438ee9 --- /dev/null +++ b/lib/theme.rb @@ -0,0 +1,58 @@ +class W3DHub + THEME = { + ToolTip: { + background: 0xff_dedede, + color: 0xaa_000000, + text_size: 18, + text_border: false, + text_shadow: false + }, + TextBlock: { + # font: "Inconsolata", + text_border: false, + text_shadow: true, + text_shadow_size: 1, + text_shadow_color: 0x88_000000 + }, + EditLine: { + border_thickness: 2, + border_color: Gosu::Color::WHITE, + hover: { color: Gosu::Color::WHITE } + }, + Link: { + color: 0xff_cdcdcd, + hover: { + color: Gosu::Color::WHITE + }, + active: { + color: 0xff_eeeeee + } + }, + Button: { + text_size: 18, + padding_top: 8, + padding_left: 32, + padding_right: 32, + padding_bottom: 8, + border_color: Gosu::Color::NONE, + background: 0xff_00acff, + hover: { + background: 0xff_bee6fd + }, + active: { + background: 0xff_add5ec + } + }, + ToggleButton: { + padding_left: 8, + padding_right: 8, + width: 18, + image_width: 18, + checkmark_image: "#{GAME_ROOT_PATH}/media/ui_icons/checkmark.png" + }, + Progress: { + fraction_background: 0xff_00acff, + border_thickness: 0 + } + } +end diff --git a/lib/window.rb b/lib/window.rb index 0fa8df6..7e9b253 100644 --- a/lib/window.rb +++ b/lib/window.rb @@ -14,6 +14,13 @@ class W3DHub push_state(W3DHub::States::Boot) end + def update + super + + @application_manager.start_next_available_task if @application_manager.idle? + current_state.update_application_manager_status if current_state.is_a?(States::Interface) + end + def close @settings.save_settings diff --git a/w3dhub.rb b/w3dhub.rb index 528c419..5b9ed79 100644 --- a/w3dhub.rb +++ b/w3dhub.rb @@ -23,6 +23,7 @@ class W3DHub end require_relative "lib/version" +require_relative "lib/theme" require_relative "lib/common" require_relative "lib/window" require_relative "lib/cache" @@ -36,6 +37,7 @@ require_relative "lib/application_manager/tasks/repairer" require_relative "lib/application_manager/tasks/importer" require_relative "lib/states/boot" require_relative "lib/states/interface" +require_relative "lib/states/message_dialog" require_relative "lib/api" require_relative "lib/api/service_status"