Compare commits
16 Commits
451b08bb9e
...
developmen
| Author | SHA1 | Date | |
|---|---|---|---|
| 0eb188f72e | |||
| c8bb271d82 | |||
| f1d6bbe390 | |||
| 56bb6a59e2 | |||
| 9d0a99de6e | |||
| e97e5cc862 | |||
| dc9e737587 | |||
| 30776857a2 | |||
| 43f8af42ec | |||
| 33de050cd2 | |||
| 6da57fef70 | |||
| 36610295cd | |||
| 95187f37f4 | |||
| 4c283ee4d5 | |||
| 5c3926e203 | |||
| 7d6fce2969 |
4
.gitignore
vendored
@@ -6,7 +6,3 @@ data/logs/*
|
||||
!data/logs/.gitkeep
|
||||
_*.*
|
||||
*.log
|
||||
media/icons/*
|
||||
!media/icons/app.*
|
||||
!media/icons/default_icon.png
|
||||
!media/icons/w3dhub.png
|
||||
|
||||
18
Gemfile
@@ -1,3 +1,21 @@
|
||||
source "https://gem.coop"
|
||||
|
||||
# "standard lib" gems
|
||||
gem "base64"
|
||||
gem "rexml"
|
||||
gem "logger"
|
||||
gem "json"
|
||||
|
||||
# "game" library gem
|
||||
gem "cyberarm_engine"
|
||||
gem "sdl2-bindings"
|
||||
|
||||
# networking libs
|
||||
gem "async"
|
||||
gem "async-http"
|
||||
gem "async-websocket"
|
||||
|
||||
# misc. libs
|
||||
gem "digest-crc"
|
||||
gem "ircparser"
|
||||
gem "rubyzip"
|
||||
|
||||
111
Gemfile.lock
@@ -1,20 +1,125 @@
|
||||
GEM
|
||||
remote: https://gem.coop/
|
||||
specs:
|
||||
async (2.39.0)
|
||||
console (~> 1.29)
|
||||
fiber-annotation
|
||||
io-event (~> 1.11)
|
||||
metrics (~> 0.12)
|
||||
traces (~> 0.18)
|
||||
async-http (0.95.0)
|
||||
async (>= 2.10.2)
|
||||
async-pool (~> 0.11)
|
||||
io-endpoint (~> 0.14)
|
||||
io-stream (~> 0.6)
|
||||
metrics (~> 0.12)
|
||||
protocol-http (~> 0.62)
|
||||
protocol-http1 (~> 0.39)
|
||||
protocol-http2 (~> 0.26)
|
||||
protocol-url (~> 0.2)
|
||||
traces (~> 0.10)
|
||||
async-pool (0.11.2)
|
||||
async (>= 2.0)
|
||||
async-websocket (0.30.0)
|
||||
async-http (~> 0.76)
|
||||
protocol-http (~> 0.34)
|
||||
protocol-rack (~> 0.7)
|
||||
protocol-websocket (~> 0.17)
|
||||
base64 (0.3.0)
|
||||
console (1.34.3)
|
||||
fiber-annotation
|
||||
fiber-local (~> 1.1)
|
||||
json
|
||||
cyberarm_engine (0.25.1)
|
||||
gosu (~> 1.1)
|
||||
digest-crc (0.7.0)
|
||||
rake (>= 12.0.0, < 14.0.0)
|
||||
ffi (1.17.4-x86_64-linux-gnu)
|
||||
fiber-annotation (0.2.0)
|
||||
fiber-local (1.1.0)
|
||||
fiber-storage
|
||||
fiber-storage (1.0.1)
|
||||
gosu (1.4.6)
|
||||
io-endpoint (0.17.2)
|
||||
io-event (1.15.1)
|
||||
io-stream (0.11.1)
|
||||
ircparser (1.0.0)
|
||||
json (2.19.4)
|
||||
logger (1.7.0)
|
||||
metrics (0.15.0)
|
||||
protocol-hpack (1.5.1)
|
||||
protocol-http (0.62.2)
|
||||
protocol-http1 (0.39.0)
|
||||
protocol-http (~> 0.62)
|
||||
protocol-http2 (0.26.0)
|
||||
protocol-hpack (~> 1.4)
|
||||
protocol-http (~> 0.62)
|
||||
protocol-rack (0.22.1)
|
||||
io-stream (>= 0.10)
|
||||
protocol-http (~> 0.58)
|
||||
rack (>= 1.0)
|
||||
protocol-url (0.4.0)
|
||||
protocol-websocket (0.21.0)
|
||||
protocol-http (~> 0.2)
|
||||
rack (3.2.6)
|
||||
rake (13.4.2)
|
||||
rexml (3.4.4)
|
||||
rubyzip (3.2.2)
|
||||
sdl2-bindings (0.2.3)
|
||||
ffi (~> 1.15)
|
||||
traces (0.18.2)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
x86_64-linux
|
||||
|
||||
DEPENDENCIES
|
||||
async
|
||||
async-http
|
||||
async-websocket
|
||||
base64
|
||||
cyberarm_engine
|
||||
digest-crc
|
||||
ircparser
|
||||
json
|
||||
logger
|
||||
rexml
|
||||
rubyzip
|
||||
sdl2-bindings
|
||||
|
||||
CHECKSUMS
|
||||
cyberarm_engine (0.25.1)
|
||||
gosu (1.4.6)
|
||||
async (2.39.0) sha256=df18730073f2bbb45788077dfa20cb365ecc1b9453969f44de6796b5191a00aa
|
||||
async-http (0.95.0) sha256=08128cab255a48e41d1e856bfa9cbda001f1c57c88bafa3fa3a545ad795754aa
|
||||
async-pool (0.11.2) sha256=0a43a17b02b04d9c451b7d12fafa9a50e55dc6dd00d4369aca00433f16a7e3ed
|
||||
async-websocket (0.30.0) sha256=55739954528ad8f87f7792d0452e1268d1ef2aa5b3719f79400a05a1a6202cdf
|
||||
base64 (0.3.0) sha256=27337aeabad6ffae05c265c450490628ef3ebd4b67be58257393227588f5a97b
|
||||
console (1.34.3) sha256=869fbd74697efc4c606f102d2812b0b008e4e7fd738a91c591e8577140ec0dcc
|
||||
cyberarm_engine (0.25.1) sha256=6f851a2ed0a32bdd25fc619172b546a8e26eefeb13a62c509f226337170d0efe
|
||||
digest-crc (0.7.0) sha256=64adc23a26a241044cbe6732477ca1b3c281d79e2240bcff275a37a5a0d78c07
|
||||
ffi (1.17.4-x86_64-linux-gnu) sha256=9d3db14c2eae074b382fa9c083fe95aec6e0a1451da249eab096c34002bc752d
|
||||
fiber-annotation (0.2.0) sha256=7abfadf1d119f508867d4103bf231c0354d019cc39a5738945dec2edadaf6c03
|
||||
fiber-local (1.1.0) sha256=c885f94f210fb9b05737de65d511136ea602e00c5105953748aa0f8793489f06
|
||||
fiber-storage (1.0.1) sha256=f48e5b6d8b0be96dac486332b55cee82240057065dc761c1ea692b2e719240e1
|
||||
gosu (1.4.6) sha256=80c7fa48cf61f4960ef067fdd1c000d98b4adc8e11faeaa486543d00908a5c15
|
||||
io-endpoint (0.17.2) sha256=3feaf766c116b35839c11fac68b6aaadc47887bb488902a57bf8e1d288fb3338
|
||||
io-event (1.15.1) sha256=c644cdcf48254015d63f558bf4492f35471f5bb204a42180ea49752be59b30cc
|
||||
io-stream (0.11.1) sha256=fa5f551fcff99581c1757b9d1cee2c37b124f07d2ca4f40b756a05ab9bd21b87
|
||||
ircparser (1.0.0) sha256=0d4598f691172e2ad078207c50ba62c0d3428ae841836b0a682e6cd01d62878d
|
||||
json (2.19.4) sha256=670a7d333fb3b18ca5b29cb255eb7bef099e40d88c02c80bd42a3f30fe5239ac
|
||||
logger (1.7.0) sha256=196edec7cc44b66cfb40f9755ce11b392f21f7967696af15d274dde7edff0203
|
||||
metrics (0.15.0) sha256=61ded5bac95118e995b1bc9ed4a5f19bc9814928a312a85b200abbdac9039072
|
||||
protocol-hpack (1.5.1) sha256=6feca238b8078da1cd295677d6f306c6001af92d75fe0643d33e6956cbc3ad91
|
||||
protocol-http (0.62.2) sha256=e1c1f2f56029c1af8c4e2b8a67d0d096c76620f3afd8d99d1dcd2f6b8ffa773b
|
||||
protocol-http1 (0.39.0) sha256=e49b3f4cda6f5d94c76a323d2b7f6977cba3ebd082d2da437039594da77ad8eb
|
||||
protocol-http2 (0.26.0) sha256=bac89cd78082b241ccd0cf7246f5160e4bb0c9c975fb4bf7deef5f88cc317486
|
||||
protocol-rack (0.22.1) sha256=1185d245927ef9849a603700d6991ca353bc89724fbf98efa4a4333ed62a9fc3
|
||||
protocol-url (0.4.0) sha256=64d4c03b6b51ad815ac6fdaf77a1d91e5baf9220d26becb846c5459dacdea9e1
|
||||
protocol-websocket (0.21.0) sha256=6e2ccc2adf7de1895b0f6548fdfacf5f9735c0d4deb56cd2bac1ae38a1952e93
|
||||
rack (3.2.6) sha256=5ed78e1f73b2e25679bec7d45ee2d4483cc4146eb1be0264fc4d94cb5ef212c2
|
||||
rake (13.4.2) sha256=cb825b2bd5f1f8e91ca37bddb4b9aaf345551b4731da62949be002fa89283701
|
||||
rexml (3.4.4) sha256=19e0a2c3425dfbf2d4fc1189747bdb2f849b6c5e74180401b15734bc97b5d142
|
||||
rubyzip (3.2.2) sha256=c0ed99385f0625415c8f05bcae33fe649ed2952894a95ff8b08f26ca57ea5b3c
|
||||
sdl2-bindings (0.2.3) sha256=878c0755a4bea1aed0fa85c01596effd1c2b7d1878141ceec5bef808038bd309
|
||||
traces (0.18.2) sha256=80f1649cb4daace1d7174b81f3b3b7427af0b93047759ba349960cb8f315e214
|
||||
|
||||
BUNDLED WITH
|
||||
4.0.8
|
||||
|
||||
14
LICENSE.md
@@ -1,7 +1,15 @@
|
||||
Copyright (c) 2021 cyberarm
|
||||
Copyright (c) 2021-2026 cyberarm
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
||||
associated documentation files (the "Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
|
||||
LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
30
lib/attribution.rb
Normal file
@@ -0,0 +1,30 @@
|
||||
module W3DHubLauncher
|
||||
module Attribution
|
||||
Item = Data.define(:name, :description, :url, :license, :license_url)
|
||||
|
||||
SPECIAL_THANKS = [
|
||||
Item.new("W3D Hub", "Creating awesome games and mods for free", "https://w3dhub.com", "", ""),
|
||||
Item.new("Yukihiro \"matz\" Matsumoto", "Creating the Ruby language", "https://matz.rubyist.net", "", ""),
|
||||
Item.new("Samuel \"ioquatix\" Williams", "Creating and maintaining the async libraries for Ruby", "https://www.codeotaku.com", "", ""),
|
||||
Item.new("Kenney", "Creating awesome game assets and releasing them completely for free\nThe launcher uses their UI Icon pack", "https://kenney.nl", "CC0", "https://creativecommons.org/publicdomain/zero/1.0/"),
|
||||
]
|
||||
|
||||
LIBRARIES = [
|
||||
Item.new("Ruby", "Programming language. A Programmer's Best Friend", "https://ruby-lang.org", "BSD 2-Clause", "https://www.ruby-lang.org/en/about/license.txt"),
|
||||
Item.new("gosu", "Light-weight game library", "https://libgosu.org", "MIT", "https://github.com/gosu/gosu/blob/master/COPYING"),
|
||||
Item.new("SDL2", "Simple DirectMedia Layer", "https://libsdl.org", "MIT", "https://github.com/libsdl-org/SDL/blob/SDL2/LICENSE.txt"),
|
||||
Item.new("MojoAL", "OpenAL sound library implementation in a single C file", "https://icculus.org/mojoAL/", "MIT", "https://github.com/icculus/mojoAL/blob/main/LICENSE.txt"),
|
||||
|
||||
Item.new("async", "Asynchronous event-driven reactor for Ruby", "https://github.com/socketry/async", "MIT", "https://github.com/socketry/async/blob/main/license.md"),
|
||||
Item.new("async-http", "Asynchronous http(s) client/server for Ruby", "https://github.com/socketry/async-http", "MIT", "https://github.com/socketry/async-http/blob/main/license.md"),
|
||||
Item.new("async-websocket", "Asynchronous websockets for Ruby", "https://github.com/socketry/async-websocket", "MIT", "https://github.com/socketry/async-websocket/blob/main/license.md"),
|
||||
Item.new("rubyzip", "Ruby library for reading and writing zip files", "https://github.com/rubyzip/rubyzip", "BSD 2-Clause", "https://github.com/rubyzip/rubyzip/blob/main/LICENSE.md"),
|
||||
Item.new("digest-crc", "Ruby library for reading and writing zip files", "https://github.com/postmodern/digest-crc", "MIT", "https://github.com/postmodern/digest-crc/blob/main/LICENSE.txt"),
|
||||
Item.new("ircparser", "Ruby parser for the IRCv3 message format", "https://codeberg.org/sadiepowell/ircparser-ruby", "MIT", "https://codeberg.org/sadiepowell/ircparser-ruby#license"),
|
||||
|
||||
Item.new("base64", "Ruby library for encoding and decoding base64", "https://github.com/ruby/base64", "BSD 2-Clause", "https://github.com/ruby/base64/blob/master/COPYING"),
|
||||
Item.new("rexml", "Ruby library for parsing XML", "https://github.com/ruby/rexml", "BSD 2-Clause", "https://github.com/ruby/rexml/blob/master/LICENSE.txt"),
|
||||
Item.new("logger", "Ruby logging library", "https://github.com/ruby/logger", "BSD 2-Clause", "https://github.com/ruby/logger/blob/master/COPYING"),
|
||||
]
|
||||
end
|
||||
end
|
||||
11
lib/constants.rb
Normal file
@@ -0,0 +1,11 @@
|
||||
module W3DHubLauncher
|
||||
DIRECTORY_NAME = "w3d-hub-linux-launcher".freeze
|
||||
|
||||
ROOT_PATH = Dir.pwd
|
||||
CONFIG_PATH = "#{Dir.home}/.config/#{DIRECTORY_NAME}".freeze
|
||||
CACHE_PATH = "#{Dir.home}/.cache/#{DIRECTORY_NAME}".freeze
|
||||
DEFAULT_PACKAGE_CACHE_PATH = "#{CACHE_PATH}/packages".freeze
|
||||
DEFAULT_APPLICATIONS_PATH = "#{Dir.home}/.local/share/#{DIRECTORY_NAME}/applications".freeze
|
||||
|
||||
USER_AGENT = "#{NAME} v#{VERSION}".freeze
|
||||
end
|
||||
9
lib/dialog.rb
Normal file
@@ -0,0 +1,9 @@
|
||||
module W3DHubLauncher
|
||||
class Dialog < CyberarmEngine::Dialog
|
||||
def setup
|
||||
theme(THEME)
|
||||
|
||||
background 0xee_222222
|
||||
end
|
||||
end
|
||||
end
|
||||
52
lib/dialogs/about.rb
Normal file
@@ -0,0 +1,52 @@
|
||||
module W3DHubLauncher
|
||||
class Dialog
|
||||
class About < 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 "About", width: 1.0, text_align: :center
|
||||
end
|
||||
|
||||
stack(width: 1.0, fill: true, scroll: true, padding_left: PADDING, padding_right: PADDING) do
|
||||
title NAME
|
||||
tagline format("v%s (%s)", VERSION, VERSION_NAME), margin_left: PADDING
|
||||
para "© 2021 - #{Time.now.year} cyberarm", margin_left: PADDING
|
||||
link "MIT licence", margin_left: PADDING
|
||||
|
||||
title "Special Thanks", margin_top: LARGE_PADDING
|
||||
W3DHubLauncher::Attribution::SPECIAL_THANKS.each do |item|
|
||||
present_item(item)
|
||||
end
|
||||
|
||||
title "Software / Libraries", margin_top: LARGE_PADDING
|
||||
W3DHubLauncher::Attribution::LIBRARIES.each do |item|
|
||||
present_item(item)
|
||||
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
|
||||
|
||||
def present_item(item)
|
||||
unless item.url.empty?
|
||||
link item.name, tip: item.url, margin_left: PADDING, font: FONT_BOLD
|
||||
else
|
||||
tagline item.name, margin_left: PADDING
|
||||
end
|
||||
para item.description, margin_left: LARGE_PADDING
|
||||
link item.license, tip: item.license_url, margin_left: PADDING + LARGE_PADDING unless item.license.empty?
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
38
lib/dialogs/downloads.rb
Normal file
@@ -0,0 +1,38 @@
|
||||
module W3DHubLauncher
|
||||
class Dialog
|
||||
class Downloads < 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
|
||||
25
lib/gui_ext.rb
Normal file
@@ -0,0 +1,25 @@
|
||||
module W3DHubLauncher
|
||||
module GuiExt
|
||||
BLACK_IMAGE = Gosu.render(64, 64, retro: true) { Gosu.draw_rect(0, 0, 32, 32, Gosu::Color::BLACK) }
|
||||
WHITE_IMAGE = Gosu.render(64, 64, retro: true) { Gosu.draw_rect(0, 0, 32, 32, Gosu::Color::WHITE) }
|
||||
|
||||
def safe_get_image(path, retro: false)
|
||||
return get_image(path, retro: retro) if File.exist?(path)
|
||||
|
||||
path = "#{ROOT_PATH}/media/default.png"
|
||||
return get_image(path, retro: retro) if File.exist?(path)
|
||||
|
||||
WHITE_IMAGE
|
||||
end
|
||||
|
||||
def rounded_avatar(image)
|
||||
circle = get_image("#{ROOT_PATH}/media/ui/circle.png")
|
||||
scale = [(circle.width.to_f / image.width).abs, (circle.width.to_f / image.height).abs].min
|
||||
|
||||
Gosu.render(circle.width, circle.height) do
|
||||
image.draw_rot(circle.width / 2, circle.height / 2, 0, 0, 0.5, 0.5, scale, scale)
|
||||
circle.draw(0, 0, 1, 1, 1, 0xff_ffffff, :multiply)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
68
lib/pages/boot/initial_setup.rb
Normal file
@@ -0,0 +1,68 @@
|
||||
module W3DHubLauncher
|
||||
module Page
|
||||
module Boot
|
||||
class InitialSetup < CyberarmEngine::Page
|
||||
include GuiExt
|
||||
|
||||
def setup
|
||||
stack(width: 1.0, background_nine_slice: NINE_SLICE_ROUNDED, background_nine_slice_from_edge: 8, background_nine_slice_color: 0x11_ffffff, padding: HALF_PADDING) do
|
||||
banner "Welcome to #{NAME}", width: 1.0, text_align: :center
|
||||
tagline "Your gateway to the world of W3D Hub games.", width: 1.0, text_align: :center
|
||||
end
|
||||
|
||||
stack(width: 1.0, fill: true, padding: PADDING) do
|
||||
stack(width: 1.0, fill: true, scroll: true) do
|
||||
title "Initial Setup"
|
||||
caption "Please confirm launcher's default settings and make any desired tweaks.", font: FONT_REGULAR
|
||||
|
||||
flow(width: 1.0, height: 40, margin_top: HALF_PADDING) do
|
||||
tagline "Launcher package cache directory", height: 1.0, text_v_align: :center
|
||||
edit_line DEFAULT_PACKAGE_CACHE_PATH, fill: true
|
||||
button "Browse..."
|
||||
end
|
||||
inscription "Location where the launcher will download application packages."
|
||||
|
||||
flow(width: 1.0, height: 40, margin_top: HALF_PADDING) do
|
||||
tagline "Application installation directory", height: 1.0, text_v_align: :center
|
||||
edit_line DEFAULT_APPLICATIONS_PATH, fill: true
|
||||
button "Browse..."
|
||||
end
|
||||
inscription "Location where the launcher will install new applications."
|
||||
|
||||
flow(width: 1.0, height: 40, margin_top: HALF_PADDING) do
|
||||
tagline "Wine context", height: 1.0, text_v_align: :center
|
||||
edit_line "", fill: true
|
||||
button "Browse..."
|
||||
end
|
||||
inscription "Location of wine context to use. Leave blank to use default."
|
||||
|
||||
flow(width: 1.0, height: 40, margin_top: HALF_PADDING) do
|
||||
tagline "Wine command", height: 1.0, text_v_align: :center
|
||||
edit_line "wine", fill: true
|
||||
button "Browse..."
|
||||
end
|
||||
inscription "Path to wine executable. Use `wine` for system installed wine."
|
||||
end
|
||||
|
||||
flow(width: 1.0, padding_top: PADDING) do
|
||||
flow(fill: true)
|
||||
button "Accept" do |btn|
|
||||
btn.enabled = false
|
||||
|
||||
Worker::Api.update_settings({}) do |result|
|
||||
if result.okay?
|
||||
page(Page::Boot::StartUp)
|
||||
else
|
||||
btn.enabled = true
|
||||
end
|
||||
|
||||
puts "NOW!"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
82
lib/pages/boot/start_up.rb
Normal file
@@ -0,0 +1,82 @@
|
||||
module W3DHubLauncher
|
||||
module Page
|
||||
module Boot
|
||||
class StartUp < CyberarmEngine::Page
|
||||
include GuiExt
|
||||
|
||||
def setup
|
||||
stack(width: 1.0, background_nine_slice: NINE_SLICE_ROUNDED, background_nine_slice_from_edge: 8, background_nine_slice_color: 0x11_ffffff, padding: HALF_PADDING) do
|
||||
banner "Establishing Battlefield Control", width: 1.0, text_align: :center
|
||||
tagline "Please stand by...", width: 1.0, text_align: :center
|
||||
end
|
||||
|
||||
stack(width: 1.0, fill: true, padding: PADDING) do
|
||||
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
|
||||
f.show
|
||||
@progress_bar.type = :linear
|
||||
@progress_bar.value = 0.0
|
||||
end
|
||||
|
||||
after(3500) 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(3600) do
|
||||
pop_state
|
||||
push_state(States::Interface)
|
||||
end
|
||||
end
|
||||
|
||||
flow(width: 1.0, padding_top: PADDING) do
|
||||
@progress_bar = progress width: 1.0, type: :marquee
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
38
lib/pages/boot/terms.rb
Normal file
@@ -0,0 +1,38 @@
|
||||
module W3DHubLauncher
|
||||
module Page
|
||||
module Boot
|
||||
class Terms < CyberarmEngine::Page
|
||||
include GuiExt
|
||||
|
||||
TERMS_AND_CONDITIONS = <<~TERMS
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
TERMS
|
||||
|
||||
def setup
|
||||
flow(width: 1.0, background_nine_slice: NINE_SLICE_ROUNDED, background_nine_slice_from_edge: 8, background_nine_slice_color: 0x11_ffffff, padding: HALF_PADDING) do
|
||||
banner "Terms and Conditions", width: 1.0, text_align: :center
|
||||
end
|
||||
|
||||
stack(width: 1.0, fill: true, padding: PADDING) do
|
||||
stack(width: 1.0, fill: true, scroll: true, padding_bottom: PADDING) do
|
||||
tagline TERMS_AND_CONDITIONS, font: FONT_REGULAR
|
||||
end
|
||||
|
||||
flow(width: 1.0) do
|
||||
flow(fill: true)
|
||||
button "Decline", margin_right: PADDING do
|
||||
window.close
|
||||
end
|
||||
|
||||
button "Accept" do
|
||||
page(Page::Boot::InitialSetup)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
82
lib/pages/games.rb
Normal file
@@ -0,0 +1,82 @@
|
||||
module W3DHubLauncher
|
||||
module Page
|
||||
class Games < CyberarmEngine::Page
|
||||
include GuiExt
|
||||
|
||||
def setup
|
||||
# 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
|
||||
flow(width: 1.0, height: 40, margin_left: PADDING, v_align: :center, h_align: :center) do
|
||||
image safe_get_image("#{ROOT_PATH}/media/icons/menuGrid.png"), height: 40, color: 0xff_bbbbbb
|
||||
link "ALL GAMES", text_size: 24, font: FONT_BLACK, height: 1.0, text_v_align: :center
|
||||
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"
|
||||
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("/run/media/cyberarm/Storage/W3DHub/Launcher/package-cache/games/apb/logo.png.package"), 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
|
||||
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
|
||||
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
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
71
lib/pages/server_browser.rb
Normal file
@@ -0,0 +1,71 @@
|
||||
module W3DHubLauncher
|
||||
module Page
|
||||
class ServerBrowser < CyberarmEngine::Page
|
||||
include GuiExt
|
||||
|
||||
def setup
|
||||
# game bar container
|
||||
flow(width: 1.0, height: 60) do
|
||||
flow(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) do
|
||||
flow(width: 1.0, height: 40, margin_left: PADDING, v_align: :center, h_align: :center) do
|
||||
image safe_get_image("#{ROOT_PATH}/media/icons/menuGrid.png"), height: 40, color: 0xff_bbbbbb
|
||||
link "ALL SERVERS", text_size: 24, font: FONT_BLACK, height: 1.0, text_v_align: :center
|
||||
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"
|
||||
end
|
||||
end
|
||||
|
||||
# game content container
|
||||
stack(width: 1.0, fill: true, margin_top: LARGE_PADDING, scroll: true) do
|
||||
10.times do
|
||||
widget(width: 1.0, height: 48, 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: ALPHA_GRAY, hover: { background_nine_slice_color: 0xff_5e5c64 } , active: { background_nine_slice_color: 0xaa_5e5c64 }) do
|
||||
# app icon container
|
||||
image(safe_get_image("#{ROOT_PATH}/data/cache/apb.png"), tip: "Red Alert: A Path Beyond", width: 48, height: 1.0, margin_left: HALF_PADDING)
|
||||
# friend name and status container
|
||||
stack(fill: true, height: 1.0, margin_left: HALF_PADDING) do
|
||||
stack(v_align: :center) do
|
||||
# server name
|
||||
server_name = ["Really Long Server Name Goes Here", "[US][W3D Hub] APB Game Night", "[US][W3D Hub] APB Co-op 3.7", "Really Long Server Name Goes Here Really Long Server Name Goes Here"].sample
|
||||
caption server_name, text_wrap: :none, tip: server_name
|
||||
# server info
|
||||
a = ["North America", "South America", "Europe", "Asia", "Antarctica", "Arctica", "Oceania"]
|
||||
inscription "#{a.sample} • 13:52 / #{rand > 0.5 ? '∞' : '30:00'}", 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
|
||||
server_map = ["RA_Under", "C&C Superduple Long Map Name Goes Here", "RA_NorthByNorthWest", "RA_HostileWatersParadox", "RA_PacificThreat"].sample
|
||||
caption server_map, tip: server_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", rand(60), rand(60..127)), 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 rand > 0.85 ? "?" : format("%d ms", rand(16..360)), width: 1.0, text_align: :center
|
||||
inscription "ping", text_wrap: :none, width: 1.0, text_align: :center, margin_top: -HALF_PADDING
|
||||
end
|
||||
stack(width: 8, height: rand(0.25..1.0), 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: [0xff_26a269, 0xff_e5a50a, 0xff_a51d2d, 0xff_3d3846].sample)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
9
lib/state.rb
Normal file
@@ -0,0 +1,9 @@
|
||||
module W3DHubLauncher
|
||||
class State < CyberarmEngine::GuiState
|
||||
include W3DHubLauncher::GuiExt
|
||||
|
||||
def setup
|
||||
theme(THEME)
|
||||
end
|
||||
end
|
||||
end
|
||||
35
lib/states/boot.rb
Normal file
@@ -0,0 +1,35 @@
|
||||
module W3DHubLauncher
|
||||
class States
|
||||
class Boot < W3DHubLauncher::State
|
||||
def setup
|
||||
super
|
||||
|
||||
# root container - background image
|
||||
stack(width: 1.0, height: 1.0, background_image: safe_get_image("/run/media/cyberarm/Storage/W3DHub/Launcher/package-cache/games/apb/background.png.package"), background_image_mode: :fill) do
|
||||
# root container - background image tint
|
||||
flow(width: 1.0, height: 1.0, background: 0xaa_000000) do
|
||||
# content container
|
||||
stack(fill: true, height: 1.0, margin: PADDING, margin_right: PADDING) do
|
||||
# header bar container
|
||||
flow(width: 1.0, height: 80, margin_bottom: PADDING) do |c|
|
||||
# logo image
|
||||
image(safe_get_image("#{ROOT_PATH}/media/logo.png"), height: 1.0)
|
||||
|
||||
stack(fill: true, height: 1.0) do
|
||||
stack(fill: true)
|
||||
title NAME
|
||||
stack(fill: true)
|
||||
end
|
||||
end
|
||||
|
||||
@page_host = stack(width: 1.0, fill: true, background_nine_slice: NINE_SLICE_ROUNDED, background_nine_slice_from_edge: 8, background_nine_slice_color: ALPHA_GRAY) do
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
page(Page::Boot::Terms)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
139
lib/states/interface.rb
Normal file
@@ -0,0 +1,139 @@
|
||||
module W3DHubLauncher
|
||||
class States
|
||||
class Interface < W3DHubLauncher::State
|
||||
def setup
|
||||
super
|
||||
|
||||
# root container - background image
|
||||
stack(width: 1.0, height: 1.0, background_image: safe_get_image("/run/media/cyberarm/Storage/W3DHub/Launcher/package-cache/games/apb/background.png.package"), background_image_mode: :fill) do
|
||||
# root container - background image tint
|
||||
stack(width: 1.0, height: 1.0, background: ALPHA_BLACK) do
|
||||
# content container
|
||||
stack(width: 1.0, fill: true, margin: PADDING) do
|
||||
# header bar container
|
||||
flow(width: 1.0, height: 80, margin_bottom: PADDING) do |c|
|
||||
# logo + menu button
|
||||
button(safe_get_image("#{ROOT_PATH}/media/logo.png"), image_height: 1.0, background: 0, border_color: 0, hover: { background: 0 }, active: { background: 0, color: 0xff_ffffff }) do |btn|
|
||||
menu(parent: btn) do
|
||||
menu_item("Settings")
|
||||
menu_item("About") do
|
||||
dialog(Dialog::About)
|
||||
end
|
||||
menu_item("Exit") do
|
||||
window.close
|
||||
end
|
||||
end.show
|
||||
end
|
||||
|
||||
# navigation bar container
|
||||
stack(fill: true, height: 1.0) do
|
||||
# stack(fill: true)
|
||||
|
||||
# navigation container
|
||||
flow(width: 1.0) do
|
||||
link("GAMES", text_v_align: :center, font: FONT_BLACK, margin_left: PADDING) { page(Page::Games) }
|
||||
link("SERVERS", text_v_align: :center, font: FONT_BLACK, margin_left: PADDING) { page(Page::ServerBrowser) }
|
||||
stack(fill: true)
|
||||
image safe_get_image("#{ROOT_PATH}/media/icons/import.png"), height: 40, color: 0xff_bbbbbb, tip: "Downloads" do |img|
|
||||
dialog(Dialog::Downloads)
|
||||
end
|
||||
image safe_get_image("#{ROOT_PATH}/media/icons/information.png"), height: 40, color: 0xff_bbbbbb, tip: "Notifications"
|
||||
end
|
||||
# application task status bar container
|
||||
stack(width: 1.0, fill: true, margin_left: PADDING) do
|
||||
flow(width: 1.0) do
|
||||
para "Updating Red Alert: A Path Beyond (Release)"
|
||||
stack(fill: true)
|
||||
para "Fetching manifests..."
|
||||
end
|
||||
progress(width: 1.0, fraction: 0.75)
|
||||
end
|
||||
end
|
||||
|
||||
# self account container
|
||||
flow(width: 300, height: 80, margin_left: LARGE_PADDING) do
|
||||
# self avatar container
|
||||
stack(width: 80, height: 1.0, background_image: rounded_avatar(safe_get_image("#{ROOT_PATH}/media/default.png"))) do
|
||||
# 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)
|
||||
end
|
||||
|
||||
stack(fill: true, height: 1.0, margin_left: HALF_PADDING) do
|
||||
flow(fill: true)
|
||||
# self name
|
||||
caption "cyberarm", font: FONT_BLACK, text_wrap: :none
|
||||
# self set online state
|
||||
link "Online ▼", text_size: 18 do |l|
|
||||
menu(parent: l) do
|
||||
menu_item("Online")
|
||||
menu_item("Do Not Disturb")
|
||||
menu_item("Away")
|
||||
menu_item("Invisible")
|
||||
menu_item("Sign Out")
|
||||
end.show
|
||||
end
|
||||
flow(fill: true)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# layout container
|
||||
flow(width: 1.0, fill: true) do
|
||||
# page host container
|
||||
@page_host = stack(fill: true, height: 1.0) do
|
||||
end
|
||||
|
||||
# battleview/friends container
|
||||
@battleview_container = stack(width: 300, height: 1.0, margin_left: LARGE_PADDING, visible: true) do
|
||||
# friend management container
|
||||
flow(width: 1.0, height: 60) do
|
||||
flow(width: 1.0, v_align: :center) do
|
||||
button safe_get_image("#{ROOT_PATH}/media/icons/singleplayer.png"), image_height: 1.0
|
||||
button safe_get_image("#{ROOT_PATH}/media/icons/gear.png"), image_height: 1.0, margin_left: HALF_PADDING
|
||||
edit_line "", margin_left: HALF_PADDING, fill: true, height: 1.0
|
||||
end
|
||||
end
|
||||
|
||||
# friends/clanmates list container
|
||||
stack(width: 1.0, fill: true, margin_top: LARGE_PADDING, scroll: true) do
|
||||
50.times do |i|
|
||||
# friend container
|
||||
widget(width: 1.0, height: 48, padding_top: HALF_PADDING, padding_bottom: HALF_PADDING, background_nine_slice: NINE_SLICE_ROUNDED, background_nine_slice_from_edge: NINE_SLICE_EDGE, background_nine_slice_color: 0, hover: { background_nine_slice_color: ALPHA_GRAY }, active: { background_nine_slice_color: ALPHA_BLACK }) do |w|
|
||||
w.subscribe(:clicked_left_mouse_button) do
|
||||
puts "HELLO THERE"
|
||||
end
|
||||
|
||||
|
||||
# friend avatar container
|
||||
stack(width: 48, height: 1.0, margin_left: HALF_PADDING, background_image: rounded_avatar(safe_get_image("#{ROOT_PATH}/media/default.png"))) do
|
||||
stack(width: 12, height: 12, v_align: :bottom, h_align: :right, background_image: safe_get_image("#{ROOT_PATH}/media/ui/circle_small.png"), background_image_color: 0xff_26a269)
|
||||
end
|
||||
# friend name and status container
|
||||
stack(fill: true, height: 1.0, margin_left: HALF_PADDING, margin_right: HALF_PADDING) do
|
||||
stack(v_align: :center) do
|
||||
caption ["Silverlight", "PXD2000", "Alstar", "SteelGhost", "FRAYDO"].sample, text_wrap: :none
|
||||
inscription "RA_Under • 13:52", text_wrap: :none, margin_top: -HALF_PADDING
|
||||
end
|
||||
end
|
||||
# friend active application container
|
||||
stack(width: 48, height: 1.0, margin_right: HALF_PADDING, background_image: safe_get_image("#{ROOT_PATH}/media/logo.png"))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
page(Page::Games)
|
||||
end
|
||||
|
||||
def button_up(id)
|
||||
super
|
||||
|
||||
@battleview_container.toggle if id == Gosu::KB_F8
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
152
lib/theme.rb
Normal file
@@ -0,0 +1,152 @@
|
||||
module W3DHubLauncher
|
||||
LARGE_PADDING = 40
|
||||
PADDING = 20
|
||||
HALF_PADDING = 10
|
||||
ALPHA_BLACK = 0x88_000000
|
||||
ALPHA_GRAY = 0x88_5e5c64
|
||||
|
||||
FONT_LIGHT = "#{ROOT_PATH}/media/fonts/NotoSans-Light.ttf"
|
||||
FONT_REGULAR = "#{ROOT_PATH}/media/fonts/NotoSans-Regular.ttf"
|
||||
FONT_BOLD = "#{ROOT_PATH}/media/fonts/NotoSans-Bold.ttf"
|
||||
FONT_BLACK = "#{ROOT_PATH}/media/fonts/NotoSans-Black.ttf"
|
||||
|
||||
FONT_MONO = "#{ROOT_PATH}/media/fonts/NotoSansMono-Regular.ttf"
|
||||
|
||||
NINE_SLICE_EDGE = 8
|
||||
NINE_SLICE_EDGE_SMALL = 4
|
||||
NINE_SLICE_EDGE_TINY = 2
|
||||
NINE_SLICE_ROUNDED = "#{ROOT_PATH}/media/ui/rounded.png"
|
||||
NINE_SLICE_ROUNDED_SMALL = "#{ROOT_PATH}/media/ui/rounded_small.png"
|
||||
NINE_SLICE_ROUNDED_TINY = "#{ROOT_PATH}/media/ui/rounded_small.png"
|
||||
NINE_SLICE_ROUNDED_LEFT = "#{ROOT_PATH}/media/ui/rounded_left.png"
|
||||
NINE_SLICE_ROUNDED_RIGHT = "#{ROOT_PATH}/media/ui/rounded_right.png"
|
||||
NINE_SLICE_ROUNDED_TOP = "#{ROOT_PATH}/media/ui/rounded_top.png"
|
||||
NINE_SLICE_ROUNDED_BOTTOM = "#{ROOT_PATH}/media/ui/rounded_bottom.png"
|
||||
NINE_SLICE_SQUARE = "#{ROOT_PATH}/media/ui/square.png"
|
||||
|
||||
CTA_BUTTON_THEME = {
|
||||
color: 0xff_ffffff,
|
||||
background_nine_slice_color: 0xff_1c71d8,
|
||||
hover: {
|
||||
color: 0xff_ffffff,
|
||||
background_nine_slice_color: 0xff_3584e4
|
||||
},
|
||||
active: {
|
||||
color: 0xff_ffffff,
|
||||
background_nine_slice_color: 0xff_1a5fb4
|
||||
}
|
||||
}
|
||||
|
||||
THEME = {
|
||||
TextBlock: {
|
||||
text_static: true,
|
||||
font: FONT_REGULAR,
|
||||
text_shadow: true,
|
||||
text_shadow_color: 0x44_000000
|
||||
},
|
||||
Link: {
|
||||
font: FONT_REGULAR,
|
||||
color: 0xff_bbbbbb,
|
||||
hover: {
|
||||
color: 0xff_ffffff
|
||||
},
|
||||
active: {
|
||||
color: 0xff_888888
|
||||
}
|
||||
},
|
||||
Inscription: {
|
||||
text_size: 18
|
||||
},
|
||||
Para: {
|
||||
text_size: 20
|
||||
},
|
||||
Caption: {
|
||||
font: FONT_BOLD
|
||||
},
|
||||
Tagline: {
|
||||
font: FONT_BOLD
|
||||
},
|
||||
Title: {
|
||||
font: FONT_BOLD
|
||||
},
|
||||
Banner: {
|
||||
font: FONT_BLACK
|
||||
},
|
||||
Button: {
|
||||
font: FONT_BOLD,
|
||||
text_shadow: false,
|
||||
color: 0xff_ffffff,
|
||||
background: 0,#x88_5e5c64,
|
||||
background_nine_slice: NINE_SLICE_ROUNDED,
|
||||
background_nine_slice_from_edge: NINE_SLICE_EDGE,
|
||||
background_nine_slice_mode: :stretched,
|
||||
background_nine_slice_color: 0x88_5e5c64,
|
||||
border_thickness: 0,
|
||||
hover: {
|
||||
color: 0xcc_ffffff,
|
||||
background: 0,
|
||||
background_nine_slice_color: 0xff_5e5c64
|
||||
},
|
||||
active: {
|
||||
color: 0x88_ffffff,
|
||||
background: 0,
|
||||
background_nine_slice_color: 0xaa_5e5c64
|
||||
}
|
||||
},
|
||||
EditLine: {
|
||||
font: FONT_REGULAR
|
||||
},
|
||||
ListBox: {
|
||||
text_align: :left,
|
||||
text_size: 24,
|
||||
font: FONT_REGULAR,
|
||||
padding_left: HALF_PADDING
|
||||
# background: 0xaa_000000,
|
||||
# border_color: 0xff_000000,
|
||||
# hover: {
|
||||
# background: 0xaa_222222
|
||||
# },
|
||||
# active: {
|
||||
# background: 0xaa_444444
|
||||
# }
|
||||
},
|
||||
Menu: {
|
||||
border_thickness: 1,
|
||||
border_color: 0xff_000000
|
||||
},
|
||||
MenuItem: {
|
||||
text_size: 24,
|
||||
text_align: :left,
|
||||
font: FONT_REGULAR,
|
||||
background_nine_slice: NINE_SLICE_SQUARE,
|
||||
background: 0xee_000000,
|
||||
border_color: 0xaa_000000,
|
||||
hover: {
|
||||
background: 0xee_222222
|
||||
},
|
||||
active: {
|
||||
background: 0xee_444444
|
||||
}
|
||||
},
|
||||
Progress: {
|
||||
height: NINE_SLICE_EDGE_TINY * 2,
|
||||
background: 0,
|
||||
background_nine_slice: NINE_SLICE_ROUNDED_TINY,
|
||||
background_nine_slice_from_edge: NINE_SLICE_EDGE_TINY,
|
||||
background_nine_slice_mode: :stretched,
|
||||
background_nine_slice_color: 0x88_5e5c64,
|
||||
fraction_background: 0xff_1a5fb4,
|
||||
border_thickness: 0,
|
||||
},
|
||||
ToolTip: {
|
||||
delay: 500,
|
||||
text_size: 24,
|
||||
background: 0,#x88_5e5c64,
|
||||
background_nine_slice: NINE_SLICE_ROUNDED,
|
||||
background_nine_slice_from_edge: NINE_SLICE_EDGE,
|
||||
background_nine_slice_mode: :stretched,
|
||||
background_nine_slice_color: 0xcc_000000,
|
||||
border_thickness: 0
|
||||
}
|
||||
}
|
||||
end
|
||||
5
lib/version.rb
Normal file
@@ -0,0 +1,5 @@
|
||||
module W3DHubLauncher
|
||||
NAME = "Cyberarm's W3D Hub Linux Launcher".freeze
|
||||
VERSION = "2.0.0".freeze
|
||||
VERSION_NAME = "alpha".freeze # TODO: Come up with a short, fun, release name
|
||||
end
|
||||
256
lib/window.rb
@@ -2,260 +2,14 @@ module W3DHubLauncher
|
||||
class Window < CyberarmEngine::Window
|
||||
def setup
|
||||
self.show_cursor = true
|
||||
self.caption = "Cyberarm's W3D Hub Linux Launcher | v2.0.0 alpha"
|
||||
self.caption = format("%s | v%s (%s)", NAME, VERSION, VERSION_NAME) # "Cyberarm's W3D Hub Linux Launcher | v2.0.0 alpha"
|
||||
|
||||
push_state(Interface)
|
||||
push_state(States::Boot)
|
||||
# push_state(States::Interface)
|
||||
end
|
||||
end
|
||||
|
||||
class Interface < CyberarmEngine::GuiState
|
||||
LARGE_PADDING = 40
|
||||
PADDING = 20
|
||||
HALF_PADDING = 10
|
||||
ALPHA_BLACK = 0x88_000000
|
||||
|
||||
FONT_LIGHT = "./media/fonts/NotoSans-Light.ttf"
|
||||
FONT_REGULAR = "./media/fonts/NotoSans-Regular.ttf"
|
||||
FONT_BOLD = "./media/fonts/NotoSans-Bold.ttf"
|
||||
FONT_BLACK = "./media/fonts/NotoSans-Black.ttf"
|
||||
|
||||
FONT_MONO = "./media/fonts/NotoSansMono-Regular.ttf"
|
||||
|
||||
CTA_BUTTON_THEME = {
|
||||
background: 0xff_1a5fb4
|
||||
}
|
||||
|
||||
THEME = {
|
||||
TextBlock: {
|
||||
text_static: true,
|
||||
font: FONT_REGULAR,
|
||||
text_shadow: true,
|
||||
text_shadow_color: 0x44_000000
|
||||
},
|
||||
Link: {
|
||||
font: FONT_REGULAR,
|
||||
color: 0xff_bbbbbb,
|
||||
hover: {
|
||||
color: 0xff_ffffff
|
||||
},
|
||||
active: {
|
||||
color: 0xff_888888
|
||||
}
|
||||
},
|
||||
Button: {
|
||||
font: FONT_BOLD,
|
||||
text_shadow: false,
|
||||
background: 0x88_5e5c64,
|
||||
border_thickness: 1,
|
||||
border_color: 0xff_000000
|
||||
},
|
||||
EditLine: {
|
||||
font: FONT_REGULAR
|
||||
},
|
||||
ListBox: {
|
||||
text_align: :left,
|
||||
text_size: 24,
|
||||
font: FONT_REGULAR,
|
||||
# background: 0xaa_000000,
|
||||
# border_color: 0xff_000000,
|
||||
# hover: {
|
||||
# background: 0xaa_222222
|
||||
# },
|
||||
# active: {
|
||||
# background: 0xaa_444444
|
||||
# }
|
||||
},
|
||||
Menu: {
|
||||
border_thickness: 1,
|
||||
border_color: 0xff_000000
|
||||
},
|
||||
MenuItem: {
|
||||
text_size: 24,
|
||||
text_align: :left,
|
||||
font: FONT_REGULAR,
|
||||
background: 0xee_000000,
|
||||
border_color: 0xaa_000000,
|
||||
hover: {
|
||||
background: 0xee_222222
|
||||
},
|
||||
active: {
|
||||
background: 0xee_444444
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def setup
|
||||
theme(THEME)
|
||||
|
||||
# root container - background image
|
||||
stack(width: 1.0, height: 1.0, background_image: get_image("/run/media/cyberarm/Storage/W3DHub/Launcher/package-cache/games/apb/background.png.package"), background_image_mode: :fill) do
|
||||
# root container - background image tint
|
||||
flow(width: 1.0, height: 1.0, background: ALPHA_BLACK) do
|
||||
# content container
|
||||
stack(fill: true, height: 1.0, margin: PADDING, margin_right: LARGE_PADDING) do
|
||||
# header bar container
|
||||
flow(width: 1.0, height: 80, margin_bottom: PADDING) do |c|
|
||||
# logo + menu button
|
||||
button(get_image("./media/logo.png"), image_height: 1.0, background: 0, border_color: 0, hover: { background: 0 }, active: { background: 0, color: 0xff_ffffff }) do |btn|
|
||||
menu(parent: btn) do
|
||||
menu_item("Settings")
|
||||
menu_item("About")
|
||||
menu_item("Exit") do
|
||||
window.close
|
||||
end
|
||||
end.show
|
||||
end
|
||||
|
||||
stack(fill: true, height: 1.0) do
|
||||
stack(fill: true)
|
||||
flow(width: 1.0) do
|
||||
link "GAMES", text_v_align: :center, font: FONT_BLACK, margin_left: PADDING
|
||||
link "SERVERS", text_v_align: :center, font: FONT_BLACK, margin_left: PADDING
|
||||
stack(fill: true)
|
||||
image get_image("./media/icons/import.png"), height: 40, color: 0xff_bbbbbb
|
||||
image get_image("./media/icons/information.png"), height: 40, color: 0xff_bbbbbb
|
||||
end
|
||||
stack(fill: true)
|
||||
end
|
||||
end
|
||||
|
||||
# page content container
|
||||
stack(width: 1.0, fill: true) do
|
||||
# game bar container
|
||||
flow(width: 1.0, height: 60) do
|
||||
flow(width: 220, height: 1.0, background: ALPHA_BLACK) do
|
||||
flow(width: 1.0, height: 40, margin_left: PADDING, v_align: :center, h_align: :center) do
|
||||
image get_image("./media/icons/menuGrid.png"), height: 40, color: 0xff_bbbbbb
|
||||
link "ALL GAMES", text_size: 24, font: FONT_BLACK, height: 1.0, text_v_align: :center
|
||||
end
|
||||
end
|
||||
|
||||
flow(fill: true, height: 1.0, background: ALPHA_BLACK, margin_left: PADDING) do
|
||||
image get_image("./data/cache/apb.png"), height: 1.0, padding: HALF_PADDING, background:0x88_5e5c64, border_thickness_bottom: 3, border_color_bottom: 0xff_3584e4, tip: "Red Alert: A Path Beyond"
|
||||
image get_image("./data/cache/ren.png"), height: 1.0, padding: HALF_PADDING, tip: "Command & Conquer: Renegade"
|
||||
image get_image("./data/cache/tsr.png"), height: 1.0, padding: HALF_PADDING, tip: "Tiberian Sun: Reborn"
|
||||
image get_image("./data/cache/woa.png"), height: 1.0, padding: HALF_PADDING, tip: "Battle for Dune: War of Assassins"
|
||||
end
|
||||
end
|
||||
|
||||
# game content container
|
||||
flow(width: 1.0, fill: true, margin_top: PADDING) do
|
||||
# game info container
|
||||
stack(width: 340, height: 1.0) do
|
||||
# logo
|
||||
image get_image("/run/media/cyberarm/Storage/W3DHub/Launcher/package-cache/games/apb/logo.png.package"), 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, **CTA_BUTTON_THEME
|
||||
button get_image("./media/icons/singleplayer.png"), image_height: 1.0, **CTA_BUTTON_THEME
|
||||
button get_image("./media/icons/gear.png"), image_height: 1.0, **CTA_BUTTON_THEME
|
||||
end
|
||||
inscription "Version: 3.9.2.15", margin_top: PADDING
|
||||
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: ALPHA_BLACK, border_thickness: 1, border_color: Gosu::Color::BLACK) do
|
||||
image get_image("./media/background.png"), fill: true, aspect_ratio: 16.0 / 9.0
|
||||
|
||||
stack(fill: true, height: 1.0, margin_left: PADDING) do
|
||||
caption "Upcoming Event", color: 0xff_22aa11, font: FONT_BOLD
|
||||
title "Red Alert: A Path Beyond Game Night", font: FONT_BOLD
|
||||
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
|
||||
|
||||
# news container
|
||||
flow(width: 1.0, margin_top: PADDING) do
|
||||
9.times do
|
||||
stack(width: 1.0 / 3, height: 345, aspect_ratio: 1, margin_left: HALF_PADDING, margin_right: HALF_PADDING, margin_bottom: PADDING, background: ALPHA_BLACK, background_image: get_image("./media/background.png"), background_image_mode: :fill, border_thickness: 1, border_color: Gosu::Color::BLACK) do
|
||||
stack(width: 1.0, height: 1.0 / 3, padding: PADDING, v_align: :bottom, background: 0xdd_000000, border_thickness_top: 1, border_color_top: Gosu::Color::BLACK) do
|
||||
caption "NEWS", color: 0x88_ffffff, font: FONT_BOLD
|
||||
tagline "A News Item Post A News Item Post", font: FONT_BOLD
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# battleview/friends container
|
||||
stack(width: 300, height: 1.0, margin: PADDING, margin_left: 0) do
|
||||
# self account container
|
||||
flow(width: 1.0, height: 80) do
|
||||
# self avatar container
|
||||
stack(width: 80, height: 1.0, background_image: get_image("./media/default.png")) do
|
||||
# self online state container
|
||||
stack(width: 20, height: 20, v_align: :bottom, h_align: :right, background_image: get_image("./media/icons/contrast.png"), background_image_color: 0xff_26a269)
|
||||
end
|
||||
|
||||
stack(fill: true, height: 1.0, margin_left: HALF_PADDING) do
|
||||
flow(fill: true)
|
||||
# self name
|
||||
caption "moonsense715test", font: FONT_BLACK, text_wrap: :none
|
||||
# self set online state
|
||||
link "Online ▼", text_size: 18 do |l|
|
||||
menu(parent: l) do
|
||||
menu_item("Online")
|
||||
menu_item("Do Not Disturb")
|
||||
menu_item("Away")
|
||||
menu_item("Invisible")
|
||||
menu_item("Sign Out")
|
||||
end.show
|
||||
end
|
||||
flow(fill: true)
|
||||
end
|
||||
end
|
||||
|
||||
# friend management container
|
||||
flow(width: 1.0, height: 60, margin_top: PADDING) do
|
||||
flow(width: 1.0) do # FIXME: , v_align: :center
|
||||
button get_image("./media/icons/singleplayer.png"), image_height: 1.0
|
||||
button get_image("./media/icons/gear.png"), image_height: 1.0, margin_left: HALF_PADDING
|
||||
edit_line "", margin_left: HALF_PADDING, fill: true, height: 1.0
|
||||
end
|
||||
end
|
||||
|
||||
# Q
|
||||
stack(width: 1.0, fill: true, margin_top: PADDING, scroll: true) do
|
||||
50.times do |i|
|
||||
# friend container
|
||||
flow(width: 1.0, height: 48, margin_bottom: HALF_PADDING, hover: { background: 0x44_000000 }) do
|
||||
# friend avatar container
|
||||
stack(width: 48, height: 1.0, background_image: get_image("./media/default.png")) do
|
||||
stack(width: 12, height: 12, v_align: :bottom, h_align: :right, background_image: get_image("./media/icons/contrast.png"), background_image_color: 0xff_26a269)
|
||||
end
|
||||
# friend name and status container
|
||||
stack(fill: true, height: 1.0, margin_left: HALF_PADDING, margin_right: HALF_PADDING) do
|
||||
stack(v_align: :center) do
|
||||
caption "moonsense#{715 * i % 1000 }test", font: FONT_BOLD, text_wrap: :none, text_size: 20
|
||||
inscription "RA_Under • 13:52", text_wrap: :none, text_size: 14, margin_top: -HALF_PADDING
|
||||
end
|
||||
end
|
||||
# friend active application container
|
||||
stack(width: 48, height: 1.0, background_image: get_image("./media/logo.png"))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
def needs_redraw?
|
||||
states.any?(&:needs_repaint?)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
59
lib/worker.rb
Normal file
@@ -0,0 +1,59 @@
|
||||
module W3DHubLauncher
|
||||
class Worker
|
||||
Response = Data.define(:status, :request_id, :data)
|
||||
|
||||
def initialize
|
||||
@threads = []
|
||||
@requests = []
|
||||
|
||||
@settings = # Settings.new
|
||||
|
||||
# next available request_id to assign incoming requests
|
||||
@request_id = 0
|
||||
|
||||
# listen for requests from frontend
|
||||
listener = Thread.new { listen }
|
||||
# connect to and monitor GSH web service
|
||||
@threads << Thread.new { game_server_hub_websocket }
|
||||
# connect to and monitor Backend web service
|
||||
@threads << Thread.new { backend_websocket }
|
||||
|
||||
@w3dhub_api = W3DHubLauncher::W3DHubApi.new
|
||||
|
||||
listener.join
|
||||
end
|
||||
|
||||
def listen
|
||||
loop do
|
||||
query = Ractor.receive
|
||||
pp query
|
||||
|
||||
case query.type
|
||||
when Request::FETCH_URL
|
||||
when Request::DOWNLOAD_URL
|
||||
when Request::W3DHUB_API_CALL
|
||||
Async do
|
||||
result = @w3dhub_api.send(query.data[:call], *(query.data[:arguments] || []))
|
||||
response = Response.new(result.okay? ? Request::STATUS_COMPLETE : Request::STATUS_ERROR, query.request_id, result)
|
||||
Ractor.main.send(response)
|
||||
end
|
||||
when Request::LAUNCHER_UPDATE_SETTINGS
|
||||
result = CyberarmEngine::Result.new
|
||||
FileUtils.mkdir_p(W3DHubLauncher::CONFIG_PATH) # FAILABLE!
|
||||
File.write("#{W3DHubLauncher::CONFIG_PATH}/settings.json", query.data) # FAILABLE!
|
||||
result.data = query.data
|
||||
response = Response.new(result.okay? ? Request::STATUS_COMPLETE : Request::STATUS_ERROR, query.request_id, result)
|
||||
Ractor.main.send(response)
|
||||
else
|
||||
raise "UNKNOWN REQUEST"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def game_server_hub_websocket
|
||||
end
|
||||
|
||||
def backend_websocket
|
||||
end
|
||||
end
|
||||
end
|
||||
74
lib/worker/api.rb
Normal file
@@ -0,0 +1,74 @@
|
||||
# Helper for launcher frontend to safely communicate with ractor (prevent deadlocks and concurrent access errors)
|
||||
|
||||
module W3DHubLauncher
|
||||
class Worker
|
||||
class Api
|
||||
# downloads requested resource, returns raw string
|
||||
def self.fetch_url
|
||||
end
|
||||
|
||||
# downloads requested resource, periodically reporting progress until completion, returning path for file on disk
|
||||
def self.download_url
|
||||
end
|
||||
|
||||
# returns user account data
|
||||
#
|
||||
# automatically handles signing in / refreshing token (DOES NOT remove account data if failed to refresh token due to network timeout)
|
||||
def self.account
|
||||
end
|
||||
|
||||
# returns launcher settings
|
||||
def self.settings
|
||||
end
|
||||
|
||||
# write updated launcher settings
|
||||
def self.update_settings(settings, &block)
|
||||
Worker::Request.new(Request::LAUNCHER_UPDATE_SETTINGS, settings.to_json, &block)
|
||||
end
|
||||
|
||||
# returns list of available applications
|
||||
#
|
||||
# if updated list is requested, return cached version immediately and then the updated list later.
|
||||
def self.applications
|
||||
end
|
||||
|
||||
# returns current list of servers as reported from GSH / cache
|
||||
def self.servers
|
||||
end
|
||||
|
||||
# returns news for application
|
||||
def self.news
|
||||
end
|
||||
|
||||
# request installation of application
|
||||
#
|
||||
# periodically reports progress until completion
|
||||
def self.install_application
|
||||
end
|
||||
|
||||
# request update of application
|
||||
#
|
||||
# periodically reports progress until completion
|
||||
def self.update_application
|
||||
end
|
||||
|
||||
# request repair of application
|
||||
#
|
||||
# periodically reports progress until completion
|
||||
def self.repair_application
|
||||
end
|
||||
|
||||
# request relocation of application
|
||||
#
|
||||
# periodically reports progress until completion
|
||||
def self.move_application
|
||||
end
|
||||
|
||||
# request removal of application
|
||||
#
|
||||
# periodically reports progress until completion
|
||||
def self.uninstall_application
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
65
lib/worker/request.rb
Normal file
@@ -0,0 +1,65 @@
|
||||
module W3DHubLauncher
|
||||
class Worker
|
||||
class Request
|
||||
Query = Data.define(:type, :request_id, :data)
|
||||
|
||||
FETCH_URL = 0
|
||||
DOWNLOAD_URL = 1
|
||||
W3DHUB_API_CALL = 10
|
||||
LAUNCHER_SETTINGS = 1000
|
||||
LAUNCHER_UPDATE_SETTINGS = 1001
|
||||
|
||||
STATUS_ERROR = -1 # request has failed
|
||||
STATUS_PENDING = 0 # request has not yet started
|
||||
STATUS_OK = 1 # request completed successfully
|
||||
STATUS_COMPLETE = STATUS_OK
|
||||
STATUS_IN_PROGRESS = 2 # request is in progress
|
||||
STATUS_BUSY = STATUS_IN_PROGRESS
|
||||
|
||||
# NOT "Thread"/Ractor safe
|
||||
@request_id = 0
|
||||
@requests = []
|
||||
|
||||
# NOT "Thread"/Ractor safe. Only call from main ractor
|
||||
# returns next available request id, and auto increments by 1
|
||||
def self.request_id
|
||||
@request_id += 1
|
||||
end
|
||||
|
||||
# NOT "Thread"/Ractor safe.
|
||||
# returns an array of pending requests
|
||||
def self.requests
|
||||
@requests
|
||||
end
|
||||
|
||||
attr_reader :type, :data, :request_id
|
||||
|
||||
def initialize(type, data, request_id: Request.request_id, &block)
|
||||
@type = type.freeze
|
||||
@data = data.freeze
|
||||
@status = STATUS_PENDING
|
||||
|
||||
@request_id = request_id
|
||||
@callback = block # only called on error or success
|
||||
|
||||
enqueue(@type, @request_id, @data)
|
||||
end
|
||||
|
||||
def enqueue(type, id, data)
|
||||
Request.requests << self
|
||||
W3DHubLauncher::WORKER.send(Query.new(type, id, data))
|
||||
end
|
||||
|
||||
# event from Worker received
|
||||
def handle_event(event, data)
|
||||
pp [event, data]
|
||||
|
||||
case event
|
||||
when STATUS_ERROR, STATUS_COMPLETE
|
||||
@callback&.call(data)
|
||||
Request.requests.delete(self)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
4
lib/worker/task.rb
Normal file
@@ -0,0 +1,4 @@
|
||||
module W3DHubLauncher
|
||||
class Task
|
||||
end
|
||||
end
|
||||
0
lib/worker/tasks/install_application.rb
Normal file
0
lib/worker/tasks/repair_application.rb
Normal file
0
lib/worker/tasks/uninstall_application.rb
Normal file
0
lib/worker/tasks/update_application.rb
Normal file
109
lib/worker/w3dhub_api.rb
Normal file
@@ -0,0 +1,109 @@
|
||||
module W3DHubLauncher
|
||||
class W3DHubApi
|
||||
API_TIMEOUT = 30 # seconds
|
||||
API_CONNECT_TIMEOUT = 10 # seconds
|
||||
|
||||
PRIMARY_W3DHUB_API_ENDPOINT = "https://secure.w3dhub.com".freeze
|
||||
ALTERNATIVE_W3DHUB_API_ENDPOINT = "https://backend.w3d.cyberarm.dev".freeze
|
||||
|
||||
def initialize
|
||||
@access_token = nil
|
||||
end
|
||||
|
||||
def headers(form_encoded: false)
|
||||
end
|
||||
|
||||
# return raw response to requester
|
||||
def fetch(url, method: :get, body: nil, headers: headers())
|
||||
result = CyberarmEngine::Result.new
|
||||
|
||||
Sync do |task|
|
||||
task.with_timeout(API_TIMEOUT) do
|
||||
Async::HTTP::Internet.send(method, url, headers, body) do |response|
|
||||
result.data = response.read
|
||||
rescue StandardError => e
|
||||
result.error = e
|
||||
end
|
||||
rescue Async::TimeoutError
|
||||
result.error = e
|
||||
end
|
||||
end
|
||||
|
||||
result
|
||||
end
|
||||
|
||||
# write response to file, periodically reporting progress to requester
|
||||
def download(url, path:, method: :get, body: nil, headers: headers(), &block)
|
||||
result = CyberarmEngine::Result.new
|
||||
|
||||
Sync do |task|
|
||||
task.with_timeout(API_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
|
||||
|
||||
block&.call(downloaded_bytes, total_downloaded_bytes, content_length)
|
||||
end
|
||||
end
|
||||
|
||||
result.data = true
|
||||
end
|
||||
rescue StandardError => e
|
||||
result.error = e
|
||||
end
|
||||
rescue Async::TimeoutError
|
||||
result.error = e
|
||||
end
|
||||
end
|
||||
|
||||
result
|
||||
end
|
||||
|
||||
def user_login()
|
||||
result = CyberarmEngine::Result.new
|
||||
end
|
||||
|
||||
def refresh_user_login()
|
||||
result = CyberarmEngine::Result.new
|
||||
end
|
||||
|
||||
def fetch_user_details()
|
||||
result = CyberarmEngine::Result.new
|
||||
end
|
||||
|
||||
def fetch_applications
|
||||
result = CyberarmEngine::Result.new
|
||||
end
|
||||
|
||||
def fetch_news()
|
||||
result = CyberarmEngine::Result.new
|
||||
end
|
||||
|
||||
def fetch_events()
|
||||
result = CyberarmEngine::Result.new
|
||||
end
|
||||
|
||||
def fetch_manifest()
|
||||
result = CyberarmEngine::Result.new
|
||||
end
|
||||
|
||||
def fetch_manifests()
|
||||
result = CyberarmEngine::Result.new
|
||||
end
|
||||
|
||||
def fetch_package_details()
|
||||
result = CyberarmEngine::Result.new
|
||||
end
|
||||
|
||||
def fetch_package()
|
||||
download()
|
||||
end
|
||||
end
|
||||
end
|
||||
BIN
media/icons/arrowDown.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
media/icons/arrowLeft.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
media/icons/arrowRight.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
media/icons/arrowUp.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
media/icons/audioOff.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
media/icons/audioOn.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
media/icons/barsHorizontal.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
media/icons/barsVertical.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
media/icons/button1.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
media/icons/button2.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
media/icons/button3.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
media/icons/buttonA.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
media/icons/buttonB.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
media/icons/buttonL.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
media/icons/buttonL1.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
media/icons/buttonL2.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
media/icons/buttonR.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
media/icons/buttonR1.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
media/icons/buttonR2.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
media/icons/buttonSelect.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
media/icons/buttonStart.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
media/icons/buttonX.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
media/icons/buttonY.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
media/icons/checkmark.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
media/icons/contrast.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
media/icons/cross.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
media/icons/down.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
media/icons/downLeft.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
media/icons/downRight.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
media/icons/exclamation.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
media/icons/exit.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
media/icons/exitLeft.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
media/icons/exitRight.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
media/icons/export.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
media/icons/fastForward.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
media/icons/gamepad.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
media/icons/gamepad1.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
media/icons/gamepad2.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
media/icons/gamepad3.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
media/icons/gamepad4.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
media/icons/gear.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
media/icons/home.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
media/icons/import.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
media/icons/information.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
media/icons/joystick.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
media/icons/joystickLeft.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
media/icons/joystickRight.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
media/icons/joystickUp.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
media/icons/larger.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
media/icons/leaderboardsComplex.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
media/icons/leaderboardsSimple.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
media/icons/left.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
14
media/icons/license.txt
Normal file
@@ -0,0 +1,14 @@
|
||||
|
||||
###############################################################################
|
||||
|
||||
Game icon pack by Kenney Vleugels (www.kenney.nl)
|
||||
|
||||
------------------------------
|
||||
|
||||
License (CC0)
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
|
||||
You may use these graphics in personal and commercial projects.
|
||||
Credit (Kenney or www.kenney.nl) would be nice but is not mandatory.
|
||||
|
||||
###############################################################################
|
||||
BIN
media/icons/locked.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
media/icons/massiveMultiplayer.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
media/icons/medal1.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
media/icons/medal2.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
media/icons/menuGrid.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
media/icons/menuList.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
media/icons/minus.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
media/icons/mouse.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
media/icons/movie.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
media/icons/multiplayer.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
media/icons/musicOff.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
media/icons/musicOn.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
media/icons/next.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
media/icons/open.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
media/icons/pause.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
media/icons/phone.png
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
media/icons/plus.png
Normal file
|
After Width: | Height: | Size: 15 KiB |