mirror of
https://github.com/cyberarm/w3d_hub_linux_launcher.git
synced 2026-09-19 14:53:49 +00:00
Added GSH game server data containing class, stub Account and Join Server dialogs, support 'lazy loading' remote images (downloading images in the background then calling a callback to replace temp image if host element is still in layout), misc. other changes.
This commit is contained in:
25
lib/dialogs/account.rb
Normal file
25
lib/dialogs/account.rb
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
module W3DHubLauncher
|
||||||
|
class Dialog
|
||||||
|
class Account < W3DHubLauncher::Dialog
|
||||||
|
def setup
|
||||||
|
super
|
||||||
|
|
||||||
|
stack(width: 1.0, max_width: 600, height: 1.0, max_height: 600, h_align: :center, v_align: :center, background_nine_slice: NINE_SLICE_ROUNDED, background_nine_slice_from_edge: NINE_SLICE_EDGE, background_nine_slice_color: ALPHA_BLACK) do
|
||||||
|
flow(width: 1.0, background_nine_slice: NINE_SLICE_ROUNDED_TOP, background_nine_slice_from_edge: NINE_SLICE_EDGE, background_nine_slice_color: ALPHA_GRAY) do
|
||||||
|
banner "Account", width: 1.0, text_align: :center
|
||||||
|
end
|
||||||
|
|
||||||
|
stack(width: 1.0, fill: true, scroll: true, padding_left: PADDING, padding_right: PADDING) do
|
||||||
|
button "Sign In", tip: "https://sso.w3d.cyberarm.dev" do
|
||||||
|
# use SSO service
|
||||||
|
pop_state
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
flow(width: 1.0, padding: PADDING, background_nine_slice: NINE_SLICE_ROUNDED_BOTTOM, background_nine_slice_from_edge: NINE_SLICE_EDGE, background_nine_slice_color: ALPHA_GRAY) do
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
38
lib/dialogs/server.rb
Normal file
38
lib/dialogs/server.rb
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
module W3DHubLauncher
|
||||||
|
class Dialog
|
||||||
|
class Server < W3DHubLauncher::Dialog
|
||||||
|
def setup
|
||||||
|
super
|
||||||
|
|
||||||
|
stack(width: 1.0, max_width: 600, height: 1.0, max_height: 600, h_align: :center, v_align: :center, background_nine_slice: NINE_SLICE_ROUNDED, background_nine_slice_from_edge: NINE_SLICE_EDGE, background_nine_slice_color: ALPHA_BLACK) do
|
||||||
|
flow(width: 1.0, background_nine_slice: NINE_SLICE_ROUNDED_TOP, background_nine_slice_from_edge: NINE_SLICE_EDGE, background_nine_slice_color: ALPHA_GRAY) do
|
||||||
|
banner "Downloads", width: 1.0, text_align: :center
|
||||||
|
end
|
||||||
|
|
||||||
|
stack(width: 1.0, fill: true, scroll: true, padding_left: PADDING, padding_right: PADDING) do
|
||||||
|
50.times do
|
||||||
|
stack(width: 1.0, margin_top: HALF_PADDING, margin_bottom: HALF_PADDING) do
|
||||||
|
flow(width: 1.0) do
|
||||||
|
para "PACKAGE_NAME.mix"
|
||||||
|
flow(fill: true)
|
||||||
|
para ["Downloading...", "Pending...", "Done.", "Patching...", "Unpacking..."].sample
|
||||||
|
end
|
||||||
|
progress(width: 1.0, fraction: rand)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
flow(width: 1.0, padding: PADDING, background_nine_slice: NINE_SLICE_ROUNDED_BOTTOM, background_nine_slice_from_edge: NINE_SLICE_EDGE, background_nine_slice_color: ALPHA_GRAY) do
|
||||||
|
flow(fill: true)
|
||||||
|
|
||||||
|
button "Close" do
|
||||||
|
pop_state
|
||||||
|
end
|
||||||
|
|
||||||
|
flow(fill: true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -6,7 +6,11 @@ module W3DHubLauncher
|
|||||||
def safe_get_image(path, retro: false)
|
def safe_get_image(path, retro: false)
|
||||||
raise RuntimeError, "Images may only be loaded from the main thread!" unless Thread.current == Thread.main
|
raise RuntimeError, "Images may only be loaded from the main thread!" unless Thread.current == Thread.main
|
||||||
|
|
||||||
return get_image(path, retro: retro) if File.exist?(path)
|
begin
|
||||||
|
return get_image(path, retro: retro) if File.exist?(path)
|
||||||
|
rescue RuntimeError => e
|
||||||
|
pp e
|
||||||
|
end
|
||||||
|
|
||||||
path = "#{ROOT_PATH}/media/default.png"
|
path = "#{ROOT_PATH}/media/default.png"
|
||||||
return get_image(path, retro: retro) if File.exist?(path)
|
return get_image(path, retro: retro) if File.exist?(path)
|
||||||
@@ -24,6 +28,30 @@ module W3DHubLauncher
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Downloads requested url and on success check if host element is still in the layout and call the block if so.
|
||||||
|
def remote_image(path, url:, element:, &block)
|
||||||
|
memcache_key = :"lock_net_download_#{element.style.tag}"
|
||||||
|
|
||||||
|
if !File.exist?(path) && MemCache[memcache_key].nil?
|
||||||
|
MemCache[memcache_key] = true
|
||||||
|
|
||||||
|
Worker::Api.download_url(url, path) do |result|
|
||||||
|
# ignore progress reports
|
||||||
|
next unless result.okay? && result.data == true
|
||||||
|
|
||||||
|
MemCache.delete(memcache_key)
|
||||||
|
# does the target element still exist in the layout?
|
||||||
|
e = find_element_by_tag(element.root, element.style.tag)
|
||||||
|
|
||||||
|
next unless e
|
||||||
|
|
||||||
|
if result.okay?
|
||||||
|
block.call(element, path)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def on_main_thread(block)
|
def on_main_thread(block)
|
||||||
window.add_to_queue(block)
|
window.add_to_queue(block)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -57,11 +57,11 @@ module W3DHubLauncher
|
|||||||
after(3000) do
|
after(3000) do
|
||||||
puts "HELLO"
|
puts "HELLO"
|
||||||
W3DHubLauncher::Worker::Request.new(:w3dhub_api_call, { call: :fetch_applications }) do |result|
|
W3DHubLauncher::Worker::Request.new(:w3dhub_api_call, { call: :fetch_applications }) do |result|
|
||||||
pp [:CALLBACK, result]
|
# pp [:CALLBACK, result]
|
||||||
File.write("applications.json", result.data)
|
File.write("applications.json", result.data)
|
||||||
hash = JSON.parse(result.data)
|
hash = JSON.parse(result.data)
|
||||||
pp applications = hash["applications"]&.map { |app| W3DHubLauncher::Worker::Api::Application.new(app) } || []
|
applications = hash["applications"]&.map { |app| W3DHubLauncher::Worker::Api::Application.new(app) } || []
|
||||||
pp applications.to_json
|
# pp applications.to_json
|
||||||
|
|
||||||
MemCache[:applications] = applications
|
MemCache[:applications] = applications
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -39,6 +39,13 @@ module W3DHubLauncher
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
populate_game
|
||||||
|
end
|
||||||
|
|
||||||
|
def populate_game(game = @current_app, channel = @current_channel)
|
||||||
|
@current_app = game
|
||||||
|
@current_channel = game&.channels&.first
|
||||||
|
|
||||||
populate_games_list
|
populate_games_list
|
||||||
populate_game_info
|
populate_game_info
|
||||||
populate_game_event
|
populate_game_event
|
||||||
@@ -49,24 +56,12 @@ module W3DHubLauncher
|
|||||||
@games_list_container.clear do
|
@games_list_container.clear do
|
||||||
@games.each_with_index do |game, i|
|
@games.each_with_index do |game, i|
|
||||||
if i.zero?
|
if i.zero?
|
||||||
image(safe_get_image("#{ROOT_PATH}/data/cache/#{game.id}.png"), height: 1.0, padding: HALF_PADDING, background_nine_slice: NINE_SLICE_ROUNDED_TOP, background_nine_slice_from_edge: NINE_SLICE_EDGE, background_nine_slice_color: 0x88_5e5c64, border_thickness_bottom: 3, border_color_bottom: 0xff_3584e4, tip: game.name)do
|
image(safe_get_image("#{ROOT_PATH}/data/cache/#{game.id}.png"), tag: :"image_icon_#{game.id}", height: 1.0, padding: HALF_PADDING, background_nine_slice: NINE_SLICE_ROUNDED_TOP, background_nine_slice_from_edge: NINE_SLICE_EDGE, background_nine_slice_color: 0x88_5e5c64, border_thickness_bottom: 3, border_color_bottom: 0xff_3584e4, tip: game.name)do
|
||||||
@current_app = game
|
populate_game(game, game&.channels&.first)
|
||||||
@current_channel = game&.channels&.first
|
|
||||||
|
|
||||||
populate_games_list
|
|
||||||
populate_game_info
|
|
||||||
populate_game_event
|
|
||||||
populate_game_news
|
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
image(safe_get_image("#{ROOT_PATH}/data/cache/#{game.id}.png"), height: 1.0, padding: HALF_PADDING, background_nine_slice: NINE_SLICE_ROUNDED_TOP, background_nine_slice_from_edge: NINE_SLICE_EDGE, background_nine_slice_color: 0, tip: game.name)do
|
image(safe_get_image("#{ROOT_PATH}/data/cache/#{game.id}.png"), tag: :"image_icon_#{game.id}", height: 1.0, padding: HALF_PADDING, background_nine_slice: NINE_SLICE_ROUNDED_TOP, background_nine_slice_from_edge: NINE_SLICE_EDGE, background_nine_slice_color: 0, tip: game.name)do
|
||||||
@current_app = game
|
populate_game(game, game&.channels&.first)
|
||||||
@current_channel = game&.channels&.first
|
|
||||||
|
|
||||||
populate_games_list
|
|
||||||
populate_game_info
|
|
||||||
populate_game_event
|
|
||||||
populate_game_news
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -76,7 +71,10 @@ module W3DHubLauncher
|
|||||||
def populate_game_info
|
def populate_game_info
|
||||||
@game_info_container.clear do
|
@game_info_container.clear do
|
||||||
# logo
|
# logo
|
||||||
image safe_get_image("#{ROOT_PATH}/media/#{@current_app.id}.png"), width: 1.0, max_height: 124
|
img = image safe_get_image("#{ROOT_PATH}/data/cache/logo_#{@current_app.id}.png"), tag: :"image_logo_#{@current_app.id}", width: 1.0, max_height: 124
|
||||||
|
remote_image("#{ROOT_PATH}/data/cache/logo_#{@current_app.id}.png", url: "https://s3.w3d.cyberarm.dev/games/#{@current_app.id}/logo.png", element: img) do |e, path|
|
||||||
|
e&.value = safe_get_image(path)
|
||||||
|
end
|
||||||
|
|
||||||
# web links
|
# web links
|
||||||
stack(width: 1.0, fill: true, padding: 0, padding_top: LARGE_PADDING) do
|
stack(width: 1.0, fill: true, padding: 0, padding_top: LARGE_PADDING) do
|
||||||
|
|||||||
@@ -53,7 +53,10 @@ module W3DHubLauncher
|
|||||||
# self account container
|
# self account container
|
||||||
flow(width: 300, height: 80, margin_left: LARGE_PADDING) do
|
flow(width: 300, height: 80, margin_left: LARGE_PADDING) do
|
||||||
# self avatar container
|
# self avatar container
|
||||||
stack(width: 80, height: 1.0, background_image: rounded_avatar(safe_get_image("#{ROOT_PATH}/media/default.png"))) do
|
stack(width: 80, height: 1.0, background_image: rounded_avatar(safe_get_image("#{ROOT_PATH}/media/default.png"))) do |i|
|
||||||
|
i.subscribe(:clicked_left_mouse_button) do
|
||||||
|
dialog(Dialog::Account)
|
||||||
|
end
|
||||||
# self online state container
|
# self online state container
|
||||||
stack(width: 20, height: 20, v_align: :bottom, h_align: :right, background_image: safe_get_image("#{ROOT_PATH}/media/ui/circle_small.png"), background_image_color: 0xff_26a269)
|
stack(width: 20, height: 20, v_align: :bottom, h_align: :right, background_image: safe_get_image("#{ROOT_PATH}/media/ui/circle_small.png"), background_image_color: 0xff_26a269)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,5 +1,10 @@
|
|||||||
module W3DHubLauncher
|
module W3DHubLauncher
|
||||||
class Worker
|
class Worker
|
||||||
|
DEFAULT_HEADERS = [
|
||||||
|
["user-agent", W3DHubLauncher::USER_AGENT]
|
||||||
|
].freeze
|
||||||
|
DEFAULT_NETWORK_TIMEOUT = 30
|
||||||
|
|
||||||
Response = Data.define(:status, :request_id, :data)
|
Response = Data.define(:status, :request_id, :data)
|
||||||
|
|
||||||
def initialize
|
def initialize
|
||||||
@@ -109,6 +114,49 @@ module W3DHubLauncher
|
|||||||
end
|
end
|
||||||
|
|
||||||
def download_url(query)
|
def download_url(query)
|
||||||
|
result = CyberarmEngine::Result.new
|
||||||
|
|
||||||
|
|
||||||
|
method = query.data["method"]
|
||||||
|
url = query.data["url"]
|
||||||
|
path = query.data["path"]
|
||||||
|
headers = query.data["headers"] || DEFAULT_HEADERS
|
||||||
|
body = query.data["body"]
|
||||||
|
|
||||||
|
Sync do |task|
|
||||||
|
task.with_timeout(DEFAULT_NETWORK_TIMEOUT) do
|
||||||
|
Async::HTTP::Internet.send(method, url, headers, body) do |response|
|
||||||
|
if response.success?
|
||||||
|
content_length = response.headers["content-length"] || 0
|
||||||
|
|
||||||
|
total_downloaded_bytes = 0
|
||||||
|
File.open(path, "wb") do |file|
|
||||||
|
response.each do |chunk|
|
||||||
|
file.write(chunk)
|
||||||
|
downloaded_bytes = chunk.length
|
||||||
|
total_downloaded_bytes += downloaded_bytes
|
||||||
|
|
||||||
|
progress_result = CyberarmEngine::Result.new(data: {
|
||||||
|
downloaded_bytes: downloaded_bytes,
|
||||||
|
total_downloaded_bytes: total_downloaded_bytes,
|
||||||
|
content_length: content_length
|
||||||
|
})
|
||||||
|
# FIXME: Send intermediate response to requester
|
||||||
|
# send(query, Response.new(Request::STATUS_IN_PROGRESS, query.request_id progress_result))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
result.data = true
|
||||||
|
end
|
||||||
|
# rescue StandardError => e
|
||||||
|
# result.error = e
|
||||||
|
end
|
||||||
|
# rescue Async::TimeoutError
|
||||||
|
# result.error = e
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
deliver_response(result, query)
|
||||||
end
|
end
|
||||||
|
|
||||||
def w3dhub_api_call(query)
|
def w3dhub_api_call(query)
|
||||||
|
|||||||
@@ -8,7 +8,8 @@ module W3DHubLauncher
|
|||||||
end
|
end
|
||||||
|
|
||||||
# downloads requested resource, periodically reporting progress until completion, returning path for file on disk
|
# downloads requested resource, periodically reporting progress until completion, returning path for file on disk
|
||||||
def self.download_url
|
def self.download_url(url, path, method = :get, headers = nil, body = nil, &block)
|
||||||
|
Worker::Request.new(:download_url, { url: url, path: path, method: method, headers: headers, body: body }, &block)
|
||||||
end
|
end
|
||||||
|
|
||||||
# returns user account data
|
# returns user account data
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ module W3DHubLauncher
|
|||||||
attr_reader :id, :category, :name, :type, :channels, :extended_data, :web_links
|
attr_reader :id, :category, :name, :type, :channels, :extended_data, :web_links
|
||||||
|
|
||||||
def initialize(data)
|
def initialize(data)
|
||||||
pp data
|
# pp data
|
||||||
|
|
||||||
@id = data["id"]
|
@id = data["id"]
|
||||||
@category = data["category"]
|
@category = data["category"]
|
||||||
|
|||||||
79
lib/worker/api/game_server.rb
Normal file
79
lib/worker/api/game_server.rb
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
module W3DHubLauncher
|
||||||
|
class Worker
|
||||||
|
class Api
|
||||||
|
# Designed to work with cyberarm's Game Server Hub service data, may work with W3D Hub's service with degraded metadata.
|
||||||
|
class GameServer
|
||||||
|
attr_reader :id, :game, :channel, :address, :port, :region, :version
|
||||||
|
|
||||||
|
def initialize(data)
|
||||||
|
# main data
|
||||||
|
@id = data["id"]
|
||||||
|
@game = data["game"]
|
||||||
|
@channel = data["channel"]
|
||||||
|
@address = data["address"]
|
||||||
|
@port = data["port"]
|
||||||
|
@region = data["region"]
|
||||||
|
|
||||||
|
# status data
|
||||||
|
@name = data["status"]["name"]
|
||||||
|
@password = data["status"]["password"] || false
|
||||||
|
@current_map = data["status"]["map"]
|
||||||
|
@player_count = data["status"]["numplayers"] || 0
|
||||||
|
@max_players = data["status"]["maxplayers"]
|
||||||
|
|
||||||
|
@match_start_time = data["status"]["started"]
|
||||||
|
@estimated_end_time = data["status"]["estimatedEndTime"]
|
||||||
|
@match_remaining_time = data["status"]["remaining"]
|
||||||
|
|
||||||
|
# status teams data
|
||||||
|
@teams = []
|
||||||
|
data["status"]["teams"].each do |team_data|
|
||||||
|
@teams << Team.new(team_data)
|
||||||
|
end
|
||||||
|
|
||||||
|
# status player data
|
||||||
|
data["status"]["players"].each do |player_data|
|
||||||
|
team = @teams.find { |t| t.id == player_data["id"] }
|
||||||
|
next unless team
|
||||||
|
|
||||||
|
team.players << Player.new(player_data)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Cyberarm GSH extras
|
||||||
|
@version = data["version"] || "838"
|
||||||
|
@next_map = data["status"]["nextmap"] || ""
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class Team
|
||||||
|
attr_reader :id, :name, :score, :kills, :deaths, :players
|
||||||
|
|
||||||
|
def initialize(data)
|
||||||
|
@id = data["id"]
|
||||||
|
@name = data["name"]
|
||||||
|
@score = data["score"]
|
||||||
|
@kills = data["kills"]
|
||||||
|
@deaths = data["deaths"]
|
||||||
|
|
||||||
|
@players = []
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class Player
|
||||||
|
attr_reader :name, :team, :score, :kills, :deaths, :ping, :time
|
||||||
|
|
||||||
|
def initialize(data)
|
||||||
|
@name = data["nick"]
|
||||||
|
@team = data["team"]
|
||||||
|
@score = data["score"]
|
||||||
|
@kills = data["kills"]
|
||||||
|
@deaths = data["deaths"]
|
||||||
|
|
||||||
|
# Cyberarm GSH extras
|
||||||
|
@ping = data["ping"] || 0
|
||||||
|
@time = data["time"] || "00:00:00"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -118,7 +118,7 @@ module W3DHubLauncher
|
|||||||
end
|
end
|
||||||
|
|
||||||
# We've gotten data back from both backends, merge them.
|
# We've gotten data back from both backends, merge them.
|
||||||
pp [primary_result, alternate_result]
|
# pp [primary_result, alternate_result]
|
||||||
|
|
||||||
# FIXME: Merge primary and alternate results
|
# FIXME: Merge primary and alternate results
|
||||||
result
|
result
|
||||||
|
|||||||
@@ -30,6 +30,8 @@ require_relative "lib/pages/boot/initial_setup"
|
|||||||
require_relative "lib/pages/boot/start_up"
|
require_relative "lib/pages/boot/start_up"
|
||||||
require_relative "lib/dialogs/about"
|
require_relative "lib/dialogs/about"
|
||||||
require_relative "lib/dialogs/downloads"
|
require_relative "lib/dialogs/downloads"
|
||||||
|
require_relative "lib/dialogs/server"
|
||||||
|
require_relative "lib/dialogs/account"
|
||||||
require_relative "lib/states/boot"
|
require_relative "lib/states/boot"
|
||||||
require_relative "lib/states/interface"
|
require_relative "lib/states/interface"
|
||||||
require_relative "lib/window"
|
require_relative "lib/window"
|
||||||
@@ -37,6 +39,7 @@ require_relative "lib/window"
|
|||||||
require_relative "lib/worker"
|
require_relative "lib/worker"
|
||||||
require_relative "lib/worker/api"
|
require_relative "lib/worker/api"
|
||||||
require_relative "lib/worker/api/application"
|
require_relative "lib/worker/api/application"
|
||||||
|
require_relative "lib/worker/api/game_server"
|
||||||
require_relative "lib/worker/request"
|
require_relative "lib/worker/request"
|
||||||
require_relative "lib/worker/w3dhub_api"
|
require_relative "lib/worker/w3dhub_api"
|
||||||
require_relative "lib/worker/task"
|
require_relative "lib/worker/task"
|
||||||
|
|||||||
Reference in New Issue
Block a user