diff --git a/lib/pages/boot/start_up.rb b/lib/pages/boot/start_up.rb index 6c241b5..a2450ee 100644 --- a/lib/pages/boot/start_up.rb +++ b/lib/pages/boot/start_up.rb @@ -23,74 +23,6 @@ module W3DHubLauncher stack(width: 1.0, fill: true, padding: PADDING) do @initialization_container = stack(width: 1.0, fill: true, scroll: true) do - # a = flow(width: 1.0, height: HALF_PADDING + PADDING, visible: false) do - # image safe_get_image("#{ROOT_PATH}/media/icons/checkmark.png"), height: 1.0, v_align: :center - # tagline "DNS resolution", height: 1.0, text_v_align: :center - # end - # after(500) do - # a.show - # end - # b = flow(width: 1.0, height: HALF_PADDING + PADDING, visible: false) do - # image safe_get_image("#{ROOT_PATH}/media/icons/information.png"), height: 1.0, v_align: :center, color: 0xff_ff8800 - # tagline "Upstream backend", height: 1.0, text_v_align: :center - # caption "Notice: Unreachable. Accounts will be unavailable.", height: 1.0, text_v_align: :center, color: 0xff_ff8800 - # end - # after(1000) do - # b.show - # end - # c = flow(width: 1.0, height: HALF_PADDING + PADDING, visible: false) do - # image safe_get_image("#{ROOT_PATH}/media/icons/checkmark.png"), height: 1.0, v_align: :center - # tagline "Alternate backend", height: 1.0, text_v_align: :center - # end - # after(1500) do - # c.show - # end - # d = flow(width: 1.0, height: HALF_PADDING + PADDING, visible: false) do - # image safe_get_image("#{ROOT_PATH}/media/icons/information.png"), height: 1.0, v_align: :center, color: 0xff_ff8800 - # tagline "Refresh account session", height: 1.0, text_v_align: :center - # caption "Notice: Upstream backend unavailable, session not refreshed.", height: 1.0, text_v_align: :center, color: 0xff_ff8800 - # end - # after(2000) do - # d.show - # end - # e = flow(width: 1.0, height: HALF_PADDING + PADDING, visible: false) do - # image safe_get_image("#{ROOT_PATH}/media/icons/checkmark.png"), height: 1.0, v_align: :center - # tagline "Fetch game servers", height: 1.0, text_v_align: :center - # end - # after(2500) do - # e.show - # end - # f = flow(width: 1.0, height: HALF_PADDING + PADDING, visible: false) do - # image safe_get_image("#{ROOT_PATH}/media/icons/cross.png"), height: 1.0, v_align: :center, color: 0xff_ff0000 - # tagline "Fetch applications", height: 1.0, text_v_align: :center - # caption "Fatal: Failed to retrieve applications list and no local cache exists. Cannot continue.", height: 1.0, text_v_align: :center, color: 0xff_ff0000 - # end - # after(3000) do - # puts "HELLO" - # W3DHubLauncher::Worker::Request.new(:w3dhub_api_call, { call: :fetch_applications }) do |result| - # # pp [:CALLBACK, result] - # File.write("applications.json", result.data) - # hash = JSON.parse(result.data) - # applications = hash["applications"]&.map { |app| W3DHubLauncher::Worker::Api::Application.new(app) } || [] - # # pp applications.to_json - - # MemCache[:applications] = applications - # end - - # f.show - # @progress_bar.type = :linear - # @progress_bar.value = 0.0 - # end - - # after(35000) do - # parent.page_host.clear do - # banner "Battlefield control established".upcase, width: 1.0, height: 1.0, text_v_align: :center, text_align: :center - # end - # end - # after(36000) do - # pop_state - # push_state(States::Interface) - # end end flow(width: 1.0, padding_top: PADDING) do @@ -153,18 +85,21 @@ module W3DHubLauncher tagline "Requesting server listing..." end - Worker::Api.servers do |result| - @initialization_container.append do - if result.okay? - MemCache[:servers] = JSON.parse(result.data).map { |s| Worker::Api::GameServer.new(s) } + counter = 0 + every(1000) do + if !MemCache[:servers].nil? || counter >= 5 + @initialization_container.append do + if MemCache[:servers] + caption "Received #{MemCache[:servers].size} servers OK", margin_left: LARGE_PADDING + else + caption "Failed to retrieve server listing.", color: 0xff_ff8800, margin_left: LARGE_PADDING + end - caption "Received #{MemCache[:servers].size} servers OK", margin_left: LARGE_PADDING - else - caption "Failed to retrieve server listing.", color: 0xff_ff8800, margin_left: LARGE_PADDING + next_step end - - next_step end + + counter += 1 end end diff --git a/lib/pages/server_browser.rb b/lib/pages/server_browser.rb index 67ce4ac..ed83ddd 100644 --- a/lib/pages/server_browser.rb +++ b/lib/pages/server_browser.rb @@ -57,68 +57,130 @@ module W3DHubLauncher def focus CyberarmEngine::EventBus.subscribe("game_server_pings", self, :handle_game_server_pings) + CyberarmEngine::EventBus.subscribe("game_server_added", self, :handle_game_server_updated) # <- not a typo + CyberarmEngine::EventBus.subscribe("game_server_updated", self, :handle_game_server_updated) + CyberarmEngine::EventBus.subscribe("game_server_removed", self, :handle_game_server_removed) + @parent.show_server_details_panel end def blur CyberarmEngine::EventBus.unsubscribe("game_server_pings", self) + CyberarmEngine::EventBus.unsubscribe("game_server_added", self) + CyberarmEngine::EventBus.unsubscribe("game_server_updated", self) + CyberarmEngine::EventBus.unsubscribe("game_server_removed", self) + @parent.hide_server_details_panel end def handle_game_server_pings(payload) - # TODO: Update displayed server ping + addresses = payload.keys + + MemCache[:servers]&.select { |s| addresses.include?(s.address) }.each do |server| + w = find_element_by_tag(@servers_container, :"server_#{server.id}") + ping_label = find_element_by_tag(w, :ping_label) + ping_bar = find_element_by_tag(w, :ping_bar) + + ping_label&.value = format("%ims", payload[server.address]) + ping_label&.tip = "" + + if ping_bar + ping_bar.style.height = server.ping_score_ratio + ping_bar.style.background_nine_slice_color = server.ping_score_color + ping_bar.recalculate + end + end + + # TODO: Sort servers? + end + + def handle_game_server_updated(payload) + game_server = Worker::Api::GameServer.new(payload) + + w = find_element_by_tag(@servers_container, :"server_#{game_server.id}") + if w + # update existing server widget + name_label = find_element_by_tag(w, :name_label) + info_label = find_element_by_tag(w, :info_label) + map_label = find_element_by_tag(w, :map_label) + players_label = find_element_by_tag(w, :players_label) + + name_label&.value = game_server.name + name_label&.tip = game_server.name + info_label&.value = "#{game_server.channel} • #{game_server.region} • #{game_server.time_elapsed} / #{game_server.match_remaining_time}" + map_label&.value = game_server.current_map + map_label&.tip = game_server.current_map + players_label&.value = format("%d / %d", game_server.player_count, game_server.max_players) + + # ensure we don't add servers that are meant to be filtered out + elsif @games_filter.empty? || @games_filter.include?(game_server.game) + @servers_container.append do + populate_server(game_server) + end + end + + # TODO: Sort servers? + end + + def handle_game_server_removed(payload) + w = find_element_by_tag(@servers_container, :"server_#{payload["id"]}") + @servers_container.remove(w) end def populate_server_list @servers_container.clear do (MemCache[:servers] || []).select { |s| @games_filter.empty? ? true : @games_filter.include?(s.game) }.sort_by { |s| [s.player_count, -s.ping] }.reverse.each do |server| - app = MemCache[:applications].find { |a| a.id == server.game } + populate_server(server) + end + end + end - widget(width: 1.0, height: 56 + PADDING, padding_top: HALF_PADDING, padding_bottom: HALF_PADDING, margin_bottom: HALF_PADDING, background_nine_slice: NINE_SLICE_ROUNDED, background_nine_slice_from_edge: NINE_SLICE_EDGE, background_nine_slice_color: server.channel == "release" ? ALPHA_GRAY : 0xaa_c64600, hover: { background_nine_slice_color: 0xff_5e5c64 } , active: { background_nine_slice_color: 0xaa_5e5c64 }) do |w| - # app icon container - image(safe_get_image("#{CACHE_PATH}/icon_#{app.id}.png"), tip: app.name, width: 56, height: 1.0, margin_left: HALF_PADDING) + def populate_server(server) + app = MemCache[:applications].find { |a| a.id == server.game } - # server name, region, and times container - stack(fill: true, height: 1.0, margin_left: HALF_PADDING) do - stack(width: 1.0, v_align: :center) do - # server name - caption server.name, text_wrap: :none, tip: server.name - # server info - inscription "#{server.channel} • #{server.region} • #{server.time_elapsed} / #{server.match_remaining_time}", text_wrap: :none, margin_top: -HALF_PADDING - end - end + widget(tag: :"server_#{server.id}", width: 1.0, height: 56 + PADDING, padding_top: HALF_PADDING, padding_bottom: HALF_PADDING, margin_bottom: HALF_PADDING, background_nine_slice: NINE_SLICE_ROUNDED, background_nine_slice_from_edge: NINE_SLICE_EDGE, background_nine_slice_color: server.channel == "release" ? ALPHA_GRAY : 0xaa_c64600, hover: { background_nine_slice_color: 0xff_5e5c64 } , active: { background_nine_slice_color: 0xaa_5e5c64 }) do |w| + # app icon container + image(safe_get_image("#{CACHE_PATH}/icon_#{app.id}.png"), tip: app.name, width: 56, height: 1.0, margin_left: HALF_PADDING) - # server map - stack(width: 256, height: 1.0, margin_left: HALF_PADDING) do - stack(width: 1.0, fill: true, v_align: :center) do - caption server.current_map, tip: server.current_map, text_wrap: :none, width: 1.0, text_align: :center - inscription "map", text_wrap: :none, width: 1.0, text_align: :center, margin_top: -HALF_PADDING - end - end - - # server player count - stack(width: 96, height: 1.0, margin_left: HALF_PADDING) do - stack(width: 1.0, fill: true, v_align: :center) do - caption format("%d / %d", server.player_count, server.max_players), width: 1.0, text_align: :center - inscription "players", text_wrap: :none, width: 1.0, text_align: :center, margin_top: -HALF_PADDING - end - end - - # server ping - flow(width: 96, height: 1.0, margin_left: HALF_PADDING, margin_right: HALF_PADDING) do - stack(fill: true, height: 1.0, v_align: :center) do - caption server.ping == Worker::Api::GameServer::BAD_OR_UNKNOWN_PING ? "?" : format("%ims", server.ping), width: 1.0, text_align: :center, tip: server.ping == Worker::Api::GameServer::BAD_OR_UNKNOWN_PING ? "Server has not replied yet or did not reply to ICMP Echo Request.\nPing unknown." : "" - inscription "ping", text_wrap: :none, width: 1.0, text_align: :center, margin_top: -HALF_PADDING - end - stack(width: 8, height: server.ping_score_ratio, v_align: :center, min_height: 8, background_nine_slice: NINE_SLICE_ROUNDED_SMALL, background_nine_slice_from_edge: NINE_SLICE_EDGE_SMALL, background_nine_slice_color: server.ping_score_color) - end - - w.subscribe(:clicked_left_mouse_button) do - @parent.populate_server_information(server) - end + # server name, region, and times container + stack(fill: true, height: 1.0, margin_left: HALF_PADDING) do + stack(width: 1.0, v_align: :center) do + # server name + caption server.name, tag: :name_label, text_wrap: :none, tip: server.name + # server info + inscription "#{server.channel} • #{server.region} • #{server.time_elapsed} / #{server.match_remaining_time}", tag: :info_label, text_wrap: :none, margin_top: -HALF_PADDING end end + + # server map + stack(width: 256, height: 1.0, margin_left: HALF_PADDING) do + stack(width: 1.0, fill: true, v_align: :center) do + caption server.current_map, tag: :map_label, tip: server.current_map, text_wrap: :none, width: 1.0, text_align: :center + inscription "map", text_wrap: :none, width: 1.0, text_align: :center, margin_top: -HALF_PADDING + end + end + + # server player count + stack(width: 96, height: 1.0, margin_left: HALF_PADDING) do + stack(width: 1.0, fill: true, v_align: :center) do + caption format("%d / %d", server.player_count, server.max_players), tag: :players_label, width: 1.0, text_align: :center + inscription "players", text_wrap: :none, width: 1.0, text_align: :center, margin_top: -HALF_PADDING + end + end + + # server ping + flow(width: 96, height: 1.0, margin_left: HALF_PADDING, margin_right: HALF_PADDING) do + stack(fill: true, height: 1.0, v_align: :center) do + caption server.ping == Worker::Api::GameServer::BAD_OR_UNKNOWN_PING ? "?" : format("%ims", server.ping), tag: :ping_label, width: 1.0, text_align: :center, tip: server.ping == Worker::Api::GameServer::BAD_OR_UNKNOWN_PING ? "Server has not replied yet or did not reply to ICMP Echo Request.\nPing unknown." : "" + inscription "ping", text_wrap: :none, width: 1.0, text_align: :center, margin_top: -HALF_PADDING + end + stack(width: 8, height: server.ping_score_ratio, tag: :ping_bar, v_align: :center, min_height: 8, background_nine_slice: NINE_SLICE_ROUNDED_SMALL, background_nine_slice_from_edge: NINE_SLICE_EDGE_SMALL, background_nine_slice_color: server.ping_score_color) + end + + w.subscribe(:clicked_left_mouse_button) do + @parent.populate_server_information(server) + end end end end