Initial work on using real data for Games page

This commit is contained in:
2026-08-27 23:51:08 -05:00
parent d77408484a
commit 59d884aad1
6 changed files with 223 additions and 61 deletions

View File

@@ -55,6 +55,17 @@ module W3DHubLauncher
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)
pp 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

View File

@@ -4,6 +4,11 @@ module W3DHubLauncher
include GuiExt
def setup
@games = MemCache[:applications]&.select { |app| app.type.include?("game") } || []
@current_app = @games.first
@current_channel = @current_app&.channels&.first
# game bar container
flow(width: 1.0, height: 60) do
widget(width: 220, height: 1.0, background_nine_slice: NINE_SLICE_ROUNDED, background_nine_slice_from_edge: NINE_SLICE_EDGE, background_nine_slice_color: ALPHA_GRAY, hover: { background_nine_slice_color: ALPHA_BLACK }, active: { background_nine_slice_color: ALPHA_GRAY }) do
@@ -13,65 +18,119 @@ module W3DHubLauncher
end
end
flow(fill: true, height: 1.0, background_nine_slice: NINE_SLICE_ROUNDED, background_nine_slice_from_edge: NINE_SLICE_EDGE, background_nine_slice_color: ALPHA_GRAY, margin_left: PADDING) do
image safe_get_image("#{ROOT_PATH}/data/cache/apb.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: "Red Alert: A Path Beyond"
image safe_get_image("#{ROOT_PATH}/data/cache/ren.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: "Command & Conquer: Renegade"
image safe_get_image("#{ROOT_PATH}/data/cache/tsr.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: "Tiberian Sun: Reborn"
image safe_get_image("#{ROOT_PATH}/data/cache/woa.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: "Battle for Dune: War of Assassins"
@games_list_container = flow(fill: true, height: 1.0, background_nine_slice: NINE_SLICE_ROUNDED, background_nine_slice_from_edge: NINE_SLICE_EDGE, background_nine_slice_color: ALPHA_GRAY, margin_left: PADDING) do
end
end
# game content container
flow(width: 1.0, fill: true, margin_top: LARGE_PADDING) do
# game info container
stack(width: 340, height: 1.0) do
# logo
image safe_get_image("#{ROOT_PATH}/media/default.png"), width: 1.0, max_height: 124
# web links
stack(width: 1.0, fill: true, padding: 0, padding_top: LARGE_PADDING) do
link "Modifications", text_size: 24
link "Bug Tracker", text_size: 24
link "Player Statistics", text_size: 24
end
# launching ta game
caption "Game Version"
list_box items: [ "Release", "Open Testing" ], width: 1.0, margin_bottom: PADDING
flow(width: 1.0, height: 60) do
button "PLAY", fill: true, height: 1.0, background_nine_slice: NINE_SLICE_ROUNDED_LEFT, **CTA_BUTTON_THEME
button safe_get_image("#{ROOT_PATH}/media/icons/singleplayer.png"), image_height: 1.0, background_nine_slice: NINE_SLICE_SQUARE, **CTA_BUTTON_THEME
button safe_get_image("#{ROOT_PATH}/media/icons/gear.png"), image_height: 1.0, background_nine_slice: NINE_SLICE_ROUNDED_RIGHT, **CTA_BUTTON_THEME
end
inscription "Version: 3.9.2.15", margin_top: PADDING
@game_info_container = stack(width: 340, height: 1.0) do
end
# game events and news container
stack(fill: true, height: 1.0, margin_left: LARGE_PADDING, scroll: true) do
flow(width: 1.0, height: 1.0, max_height: 380, background_nine_slice: NINE_SLICE_ROUNDED, background_nine_slice_from_edge: NINE_SLICE_EDGE, background_nine_slice_color: ALPHA_GRAY) do
image safe_get_image("#{ROOT_PATH}/media/background.png"), fill: true, aspect_ratio: 16.0 / 9.0
stack(fill: true, height: 1.0, margin_left: PADDING) do
caption "Upcoming Event".upcase, color: 0xff_22aa11
title "Red Alert: A Path Beyond Game Night"
tagline "July 11, 2028"
flow(fill: true)
button "Read More", margin_left: PADDING, margin_right: LARGE_PADDING, margin_bottom: PADDING, width: 1.0
end
@event_container = flow(width: 1.0, height: 1.0, max_height: 380, background_nine_slice: NINE_SLICE_ROUNDED, background_nine_slice_from_edge: NINE_SLICE_EDGE, background_nine_slice_color: ALPHA_GRAY) do
end
# news container
flow(width: 1.0, margin_top: PADDING) do
9.times do
stack(width: 1.0 / 3, min_width: 345, height: 345, aspect_ratio: 1, margin_left: HALF_PADDING, margin_right: HALF_PADDING, margin_bottom: PADDING) do
stack(width: 1.0, fill: true, background_image: safe_get_image("#{ROOT_PATH}/media/background.png"), background_image_mode: :fill)
stack(width: 1.0, height: 1.0 / 3, padding: PADDING, v_align: :bottom, background_nine_slice: NINE_SLICE_ROUNDED_BOTTOM, background_nine_slice_from_edge: NINE_SLICE_EDGE, background_nine_slice_color: ALPHA_GRAY, border_thickness_top: 1, border_color_top: Gosu::Color::BLACK) do
caption "NEWS", color: 0x88_ffffff
tagline "A News Item Post A News Item Post"
end
end
@news_container = flow(width: 1.0, margin_top: PADDING) do
end
end
end
populate_games_list
populate_game_info
populate_game_event
populate_game_news
end
def populate_games_list
@games_list_container.clear do
@games.each_with_index do |game, i|
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
@current_app = game
@current_channel = game&.channels&.first
populate_games_list
populate_game_info
populate_game_event
populate_game_news
end
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
@current_app = game
@current_channel = game&.channels&.first
populate_games_list
populate_game_info
populate_game_event
populate_game_news
end
end
end
end
end
def populate_game_info
@game_info_container.clear do
# logo
image safe_get_image("#{ROOT_PATH}/media/#{@current_app.id}.png"), width: 1.0, max_height: 124
# web links
stack(width: 1.0, fill: true, padding: 0, padding_top: LARGE_PADDING) do
@current_app.web_links.each do |link|
link link.name, text_size: 24, tip: link.uri
end
end
# launching ta game
if (@current_app&.channels&.size || 0) > 1
caption "Game Version"
list_box(items: @current_app.channels.map(&:name), choose: @current_channel&.name, width: 1.0, margin_bottom: PADDING) do |item|
@current_channel = @current_app.channels.find { |c| c.name == item }
populate_game_info
end
end
flow(width: 1.0, height: 60) do
button "JOIN", tip: "Join most populated or lowest ping server", fill: true, height: 1.0, background_nine_slice: NINE_SLICE_ROUNDED_LEFT, **CTA_BUTTON_THEME
button safe_get_image("#{ROOT_PATH}/media/icons/singleplayer.png"), tip: "Single player", image_height: 1.0, background_nine_slice: NINE_SLICE_SQUARE, **CTA_BUTTON_THEME
button safe_get_image("#{ROOT_PATH}/media/icons/gear.png"), tip: "Options", image_height: 1.0, background_nine_slice: NINE_SLICE_ROUNDED_RIGHT, **CTA_BUTTON_THEME
end
# FIXME: the reported version should be the _installed_ version, not the current channel version
inscription "Version: #{@current_channel.version}", margin_top: PADDING, tip: "Installed version"
end
end
def populate_game_event
# TODO: Hide event container if there is no event
@event_container.show if false
@event_container.hide if true
@event_container.clear do
image safe_get_image("#{ROOT_PATH}/media/background.png"), fill: true, aspect_ratio: 16.0 / 9.0
stack(fill: true, height: 1.0, margin_left: PADDING) do
caption "Upcoming Event".upcase, color: 0xff_22aa11
title "Red Alert: A Path Beyond Game Night"
tagline "July 11, 2028"
flow(fill: true)
button "Read More", margin_left: PADDING, margin_right: LARGE_PADDING, margin_bottom: PADDING, width: 1.0
end
end
end
def populate_game_news
@news_container.clear do
9.times do
stack(width: 1.0 / 3, min_width: 345, height: 345, aspect_ratio: 1, margin_left: HALF_PADDING, margin_right: HALF_PADDING, margin_bottom: PADDING) do
stack(width: 1.0, fill: true, background_image: safe_get_image("#{ROOT_PATH}/media/background.png"), background_image_mode: :fill)
stack(width: 1.0, height: 1.0 / 3, padding: PADDING, v_align: :bottom, background_nine_slice: NINE_SLICE_ROUNDED_BOTTOM, background_nine_slice_from_edge: NINE_SLICE_EDGE, background_nine_slice_color: ALPHA_GRAY, border_thickness_top: 1, border_color_top: Gosu::Color::BLACK) do
caption "NEWS", color: 0x88_ffffff
tagline "A News Item Post A News Item Post"
end
end
end

View File

@@ -77,6 +77,8 @@ module W3DHubLauncher
text_shadow: false,
color: 0xff_ffffff,
background: 0,#x88_5e5c64,
padding_left: HALF_PADDING,
padding_right: HALF_PADDING,
background_nine_slice: NINE_SLICE_ROUNDED,
background_nine_slice_from_edge: NINE_SLICE_EDGE,
background_nine_slice_mode: :stretched,

View File

@@ -36,17 +36,18 @@ module W3DHubLauncher
UNIXServer.open(IPC_PATH) do |server|
while(socket = server.accept)
task.async do
data = socket.gets
json = JSON.parse(data)
query = Request::Query.new(type: json["type"].to_sym, request_id: json["request_id"], data: json["data"])
while(data =socket.gets)
json = JSON.parse(data)
query = Request::Query.new(type: json["type"].to_sym, request_id: json["request_id"], data: json["data"])
pp [:server_incoming, data, query]
pp [:server_incoming, data, query]
if respond_to?(query.type)
response = send(query.type, query)
pp [:server_to_client, response]
payload = { status: response.status, request_id: response.request_id, data: response.data.data }.to_json
socket.puts(payload)
if respond_to?(query.type)
response = send(query.type, query)
pp [:server_to_client, response]
payload = { status: response.status, request_id: response.request_id, data: response.data.data }.to_json
socket.puts(payload)
end
end
end
end

View File

@@ -0,0 +1,92 @@
module W3DHubLauncher
class Worker
class Api
class Application
attr_reader :id, :category, :name, :type, :channels, :extended_data, :web_links
def initialize(data)
pp data
@id = data["id"]
@category = data["category"]
@name = data["name"]
@type = data["type"]
@channels = data["channels"]&.map { |c| Channel.new(c) } || []
@extended_data = data["extended-data"]&.map { |d| ExtendedData.new(d) } || nil
@web_links = data["web-links"]&.map { |d| WebLink.new(d) } || nil
end
# libgosu friendly color
def color
"ff_#{(@extended_data["colour"] || "#000000").sub("#", "")}".to_i(16)
end
def to_json(context = nil)
{
"id": @id,
"category": @category,
"name": @name,
"type": @type,
"channels": @channels,
"extended-data": @extended_data,
"web-links": @web_links
}.to_json(context)
end
class Channel
attr_reader :id, :name, :user_level, :version
def initialize(data)
@id = data["id"]
@name = data["name"]
@user_level = data["user-level"]
@version = Gem::Version.new(data["current-version"])
end
def to_json(context = nil)
{
"id": @id,
"name": @name,
"user-level": @user_level,
"current-version": @version.to_s
}.to_json(context)
end
end
class ExtendedData
attr_reader :name, :value
def initialize(data)
@name = data["name"]
@value = data["value"]
end
def to_json(context = nil)
{
"name": @name,
"value": @value
}.to_json(context)
end
end
class WebLink
attr_reader :name, :uri
def initialize(data)
@name = data["name"]
@uri = data["uri"]
end
def to_json(context = nil)
{
"name": @name,
"uri": @uri
}.to_json(context)
end
end
end
end
end
end

View File

@@ -36,6 +36,7 @@ require_relative "lib/window"
require_relative "lib/worker"
require_relative "lib/worker/api"
require_relative "lib/worker/api/application"
require_relative "lib/worker/request"
require_relative "lib/worker/w3dhub_api"
require_relative "lib/worker/task"
@@ -45,6 +46,8 @@ require_relative "lib/worker/tasks/repair_application"
require_relative "lib/worker/tasks/update_application"
module W3DHubLauncher
MemCache = {}
# UNIXServer
Thread.new do
W3DHubLauncher::Worker.new.listen
@@ -55,12 +58,6 @@ module W3DHubLauncher
WORKER.connect
end
# 10.times do
# W3DHubLauncher::Worker::Request.new(:w3dhub_api_call, { call: :fetch_applications }) do |result|
# pp [:CALLBACK, result]
# end
# end
window = W3DHubLauncher::Window.new(width: 1280, height: 800, resizable: true)
# window = W3DHubLauncher::Window.new(width: 1920, height: 1080, resizable: true)
window.show