6 Commits

10 changed files with 373 additions and 172 deletions

27
Gemfile
View File

@@ -1,15 +1,26 @@
source "https://rubygems.org"
# "standard lib" gems
gem "base64"
gem "rexml"
gem "logger"
# networking libs
gem "async-http"
gem "async-websocket"
# "game" library gem
gem "cyberarm_engine"
gem "sdl2-bindings"
gem "libui", platforms: [:windows]
# misc. libs
gem "digest-crc"
gem "ircparser"
gem "rexml"
gem "rubyzip"
# file selection dialogs on windows (SDL3 has these built-in, but we're on SDL2)
gem "libui", platforms: [:windows]
# misc. windows only gems
gem "win32-process", platforms: [:windows]
gem "win32-security", platforms: [:windows]
@@ -18,9 +29,9 @@ gem "win32-security", platforms: [:windows]
# use `bundle _x.y.z_ COMMAND` to use this one...
# NOTE: Releasy needs to be installed as a system gem i.e. `rake install`
# NOTE: contents of the `gemhome` folder in the packaged folder need to be moved into the lib/ruby/gems\<RUBY_VERSION> folder
# group :windows_packaging do
# gem "bundler", "~>2.4.3"
# gem "rake"
# gem "ocran"
# gem "releasy"#, path: "../releasy"
# end
# group :windows_packaging do
# gem "bundler", "~>2.4.3"
# gem "rake"
# gem "ocran"
# gem "releasy"#, path: "../releasy"
# end

View File

@@ -1,13 +1,13 @@
GEM
remote: https://rubygems.org/
specs:
async (2.35.2)
async (2.38.1)
console (~> 1.29)
fiber-annotation
io-event (~> 1.11)
metrics (~> 0.12)
traces (~> 0.18)
async-http (0.94.0)
async-http (0.94.2)
async (>= 2.10.2)
async-pool (~> 0.11)
io-endpoint (~> 0.14)
@@ -18,7 +18,7 @@ GEM
protocol-http2 (~> 0.22)
protocol-url (~> 0.2)
traces (~> 0.10)
async-pool (0.11.1)
async-pool (0.11.2)
async (>= 2.0)
async-websocket (0.30.0)
async-http (~> 0.76)
@@ -26,11 +26,11 @@ GEM
protocol-rack (~> 0.7)
protocol-websocket (~> 0.17)
base64 (0.3.0)
console (1.34.2)
console (1.34.3)
fiber-annotation
fiber-local (~> 1.1)
json
cyberarm_engine (0.25.0)
cyberarm_engine (0.25.1)
gosu (~> 1.1)
digest-crc (0.7.0)
rake (>= 12.0.0, < 14.0.0)
@@ -43,29 +43,30 @@ GEM
fiber-storage (1.0.1)
fiddle (1.1.8)
gosu (1.4.6)
io-endpoint (0.16.0)
io-event (1.14.2)
io-endpoint (0.17.2)
io-event (1.14.4)
io-stream (0.11.1)
ircparser (1.0.0)
json (2.18.0)
json (2.19.2)
libui (0.2.0-x64-mingw-ucrt)
fiddle
logger (1.7.0)
metrics (0.15.0)
protocol-hpack (1.5.1)
protocol-http (0.58.0)
protocol-http1 (0.36.0)
protocol-http (0.60.0)
protocol-http1 (0.37.0)
protocol-http (~> 0.58)
protocol-http2 (0.24.0)
protocol-hpack (~> 1.4)
protocol-http (~> 0.47)
protocol-rack (0.21.0)
protocol-rack (0.22.0)
io-stream (>= 0.10)
protocol-http (~> 0.58)
rack (>= 1.0)
protocol-url (0.4.0)
protocol-websocket (0.20.2)
protocol-http (~> 0.2)
rack (3.2.4)
rack (3.2.5)
rake (13.3.1)
rexml (3.4.4)
rubyzip (3.2.2)
@@ -90,6 +91,7 @@ DEPENDENCIES
digest-crc
ircparser
libui
logger
rexml
rubyzip
sdl2-bindings
@@ -97,4 +99,4 @@ DEPENDENCIES
win32-security
BUNDLED WITH
2.6.8
4.0.3

View File

@@ -76,7 +76,7 @@ class W3DHub
end
def save_config(config = @config)
File.write(CONFIG_PATH, config.to_json)
File.write(CONFIG_PATH, JSON.pretty_generate(config))
end
end
end

View File

@@ -61,10 +61,8 @@ class W3DHub
prefill: Store.settings[:server_list_username],
accept_callback: accept_callback,
cancel_callback: cancel_callback,
# See: https://gitlab.com/danpaul88/brenbot/-/blob/master/Source/renlog.pm#L136-175
valid_callback: proc do |entry|
entry.length > 1 && entry.length < 30 && (entry =~ /(:|!|&|%| )/i).nil? &&
(entry =~ /[\001\002\037]/).nil? && (entry =~ /\\/).nil?
entry.length.between?(3, 40) && (entry =~ /^[a-z0-9_\-\[\]]+$/i)
end
)
end
@@ -123,7 +121,6 @@ class W3DHub
process_info = Process.create(**hash)
pid = process_info.process_id
status = -1
until (status = Process.get_exitcode(pid))
if block

View File

@@ -2,7 +2,7 @@ class W3DHub
class HardwareSurvey
attr_reader :data
def initialize
def initialize(displays_only: false)
@data = {
displays: [],
system: {
@@ -26,8 +26,6 @@ class W3DHub
}
}
# Hardware survey only works on Windows atm
if Gem::win_platform?
lib_dir = File.dirname($LOADED_FEATURES.find { |file| file.include?("gosu.so") })
SDL.load_lib("#{lib_dir}64/SDL2.dll")
@@ -36,11 +34,13 @@ class W3DHub
end
query_displays
unless displays_only
query_motherboard
query_operating_system
query_cpus
query_ram
query_gpus
end
@data.freeze
end
@@ -68,8 +68,8 @@ class W3DHub
end
def query_motherboard
return unless Gem::win_platform?
if Gem::win_platform?
begin
Win32::Registry::HKEY_LOCAL_MACHINE.open("HARDWARE\\DESCRIPTION\\System\\BIOS", Win32::Registry::KEY_READ) do |reg|
@data[:system][:motherboard][:manufacturer] = safe_reg(reg, "SystemManufacturer")
@data[:system][:motherboard][:model] = safe_reg(reg, "SystemProductName")
@@ -84,10 +84,16 @@ class W3DHub
@data[:system][:motherboard][:bios_release_date] = "Unknown"
@data[:system][:motherboard][:bios_version] = "Unknown"
end
else # unix
@data[:system][:motherboard][:manufacturer] = safe_file("/sys/devices/virtual/dmi/id/board_vendor")
@data[:system][:motherboard][:model] = safe_file("/sys/devices/virtual/dmi/id/board_name")
@data[:system][:motherboard][:bios_version] = safe_file("/sys/devices/virtual/dmi/id/board_version")
end
end
def query_operating_system
return unless Gem::win_platform?
if Gem::win_platform?
begin
Win32::Registry::HKEY_LOCAL_MACHINE.open("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", Win32::Registry::KEY_READ) do |reg|
@data[:system][:operating_system][:name] = safe_reg(reg, "ProductName")
@data[:system][:operating_system][:build] = safe_reg(reg, "CurrentBuild")
@@ -100,6 +106,14 @@ class W3DHub
@data[:system][:operating_system][:version] = "Unknown"
@data[:system][:operating_system][:edition] = "Unknown"
end
else # unix
release_info = query_release_info
@data[:system][:operating_system][:name] = release_info["pretty_name"] || release_info["name"] || "Unknown"
@data[:system][:operating_system][:build] = release_info["version_codename"] || release_info["build_id"] || "Unknown"
@data[:system][:operating_system][:version] = release_info["version_id"] || release_info["build_id"] || "Unknown"
@data[:system][:operating_system][:edition] = release_info["id"] || release_info["id_like"] || "Unknown"
end
end
def query_cpus
if Gem::win_platform?
@@ -122,6 +136,16 @@ class W3DHub
end
rescue Win32::Registry::Error
end
else
cpu_info = query_cpu_info
cpu_info.each do |cpu|
@data[:system][:cpus] << {
manufacturer: cpu["manufacturer"] || "Unknown",
model: cpu["model"] || "Unknown",
mhz: cpu["mhz"] || "Unknown",
family: cpu["family"] || "Unknown"
}
end
end
instruction_sets = %w[ HasRDTSC HasAltiVec HasMMX Has3DNow HasSSE HasSSE2 HasSSE3 HasSSE41 HasSSE42 HasAVX HasAVX2 HasAVX512F HasARMSIMD HasNEON ] # HasLSX HasLASX # These cause a crash atm
@@ -140,8 +164,8 @@ class W3DHub
end
def query_gpus
return unless Gem::win_platform?
if Gem::win_platform?
begin
Win32::Registry::HKEY_LOCAL_MACHINE.open("SYSTEM\\ControlSet001\\Control\\Class\\{4d36e968-e325-11ce-bfc1-08002be10318}", Win32::Registry::KEY_READ) do |reg|
i = 0
@@ -179,11 +203,149 @@ class W3DHub
end
rescue Win32::Registry::Error
end
else # unix
gpu_info = query_glx_info
gpu_info.each do |gpu|
@data[:system][:gpus] << {
manufacturer: gpu["manufacturer"] || "Unknown",
model: gpu["model"] || "Unknown",
vram: gpu["vram"].to_i,
driver_date: gpu["driver_date"] || "Unknown",
driver_version: gpu["driver_version"] || "Unknown"
}
end
end
end
def safe_reg(reg, key, default_value = "Unknown")
reg[key]
rescue Win32::Registry::Error
default_value
end
def safe_file(path, default_value = "Unknown")
value = File.read(path).to_s.strip
return default_value if value.downcase == "default string"
value
rescue
default_value
end
def query_release_info
hash = {}
File.open("/etc/os-release") do |f|
f.each_line do |line|
line = line.strip
key, value = line.split("=", 2)
value.gsub!('"', "")
hash[key.downcase] = value
end
end
hash
rescue
hash
end
def query_cpu_info
cpus = []
cpu = {}
File.open("/proc/cpuinfo") do |f|
f.each_line do |line|
line = line.strip
if line.empty?
cpu["family"] = format(
"%s Family %s Model %s Stepping %s",
cpu["manufacturer"] || "Unknown",
cpu["_family"] || "Unknown",
cpu["_model"] || "Unknown",
cpu["_stepping"] || "Unknown",
)
cpus << cpu
cpu = {}
next
end
key, value = line.split(":", 2).map(&:strip)
case key.downcase
when "vendor_id"
cpu["manufacturer"] = value
when "model name"
cpu["model"] = value
when "cpu mhz"
cpu["mhz"] = value
when "cpu family"
cpu["_family"] = value
when "model"
cpu["_model"] = value
when "stepping"
cpu["_stepping"] = value
end
end
end
cpus
rescue
cpus
end
def query_glx_info
gpus = []
glxinfo = `glxinfo`
return gpus if glxinfo.empty?
gpu = {}
glxinfo.lines do |line|
line = line.strip
next if line.empty?
key, value = line.split(":", 2).map(&:strip)
mesa_info = false
gpu_memory_info = false
case key.downcase
when "opengl vendor string"
if mesa_info
gpus << gpu
gpu = {}
break
end
when /extended renderer info \(GLX_MESA_query_renderer\)/i
# Joy and happiness
mesa_info = true
when /Memory info \(GL_NVX_gpu_memory_info\)/i
# Happiness and joy
gpu_memory_info = true
when "vendor", "opengl vendor string"
gpu["manufacturer"] = value
when "device", "opengl renderer string"
gpu["model"] = value
when "version"
gpu["driver_version"] = value
when "video memory", "dedicated video memory"
gpu["vram"] = value.gsub(/[\D]+/, "")
when "opengl version string"
gpus << gpu
gpu = {}
break
end
end
gpus
end
end
end

View File

@@ -123,7 +123,6 @@ class W3DHub
background_image_path = Cache.package_path(game.category, game.id, "background.png", "")
if File.exist?(background_image_path)
States::Interface.instance&.instance_variable_get(:"@interface_container")&.style&.background_image = get_image(background_image_path)
States::Interface.instance&.instance_variable_get(:"@interface_container")&.style&.default[:background_image] = get_image(background_image_path)
end
# Game Stuff

View File

@@ -271,9 +271,8 @@ class W3DHub
def stylize_selected_server(server_container)
server_container.style.background = @selected_color
server_container.style.default[:background] = @selected_color
server_container.style.hover[:background] = @selected_color
server_container.style.active[:background] = @selected_color
server_container.style.hover.background = @selected_color
server_container.style.active.background = @selected_color
end
def reorder_server_list
@@ -284,11 +283,11 @@ class W3DHub
end.reverse!.each_with_index do |child, i|
next if @selected_server_container && child == @selected_server_container
child.style.hover[:background] = 0xaa_555566
child.style.hover[:active] = 0xaa_555588
child.style.hover.background = 0xaa_555566
child.style.active.background = 0xaa_555588
child.style.default[:background] = 0xaa_333333 if i.even?
child.style.default[:background] = 0x00_000000 if i.odd?
child.style.background = 0xaa_333333 if i.even?
child.style.background = 0x00_000000 if i.odd?
end
@server_list_container.recalculate

View File

@@ -78,7 +78,7 @@ class W3DHub
end
def save_settings
File.write(SETTINGS_FILE_PATH, @settings.to_json)
File.write(SETTINGS_FILE_PATH, JSON.pretty_generate(@settings))
end
def save_application_cache(json)

View File

@@ -230,7 +230,7 @@ class W3DHub
Api.on_thread(:_applications) do |applications|
if applications
Store.applications = applications
Store.settings.save_application_cache(applications.data.to_json)
Store.settings.save_application_cache(JSON.pretty_generate(applications.data))
@tasks[:applications][:complete] = true
else
# FIXME: Failed to retreive!

View File

@@ -23,6 +23,7 @@ class W3DHub
@service_status = @options[:service_status]
@applications = @options[:applications]
@account_expire = Gosu.milliseconds
@applications_expire = Gosu.milliseconds + APPLICATIONS_UPDATE_INTERVAL # ten minutes
@server_list_expire = Gosu.milliseconds + SERVER_LIST_UPDATE_INTERVAL # 5 minutes
@@ -59,25 +60,21 @@ class W3DHub
link I18n.t(:"interface.servers").upcase, text_size: 34, font: BOLD_FONT, margin_left: 12 do
@interface_container.style.background_image = DEFAULT_BACKGROUND_IMAGE
@interface_container.style.default[:background_image] = DEFAULT_BACKGROUND_IMAGE
page(W3DHub::Pages::ServerBrowser)
end
link I18n.t(:"interface.community").upcase, text_size: 34, font: BOLD_FONT, margin_left: 12 do
@interface_container.style.background_image = DEFAULT_BACKGROUND_IMAGE
@interface_container.style.default[:background_image] = DEFAULT_BACKGROUND_IMAGE
page(W3DHub::Pages::Community)
end
link I18n.t(:"interface.downloads").upcase, text_size: 34, font: BOLD_FONT, margin_left: 12 do
@interface_container.style.background_image = DEFAULT_BACKGROUND_IMAGE
@interface_container.style.default[:background_image] = DEFAULT_BACKGROUND_IMAGE
page(W3DHub::Pages::DownloadManager)
end
link I18n.t(:"interface.settings").upcase, text_size: 34, font: BOLD_FONT, margin_left: 12 do
@interface_container.style.background_image = DEFAULT_BACKGROUND_IMAGE
@interface_container.style.default[:background_image] = DEFAULT_BACKGROUND_IMAGE
page(W3DHub::Pages::Settings)
end
end
@@ -132,6 +129,13 @@ class W3DHub
end
hide_application_taskbar
every(3_000) do
# NOTE: each method called, internally checks whether it should act.
refresh_account_token
refresh_applications
refresh_server_list
end
end
def draw
@@ -146,36 +150,6 @@ class W3DHub
@page&.update
update_interface_task_status(@interface_task_update_pending) if @interface_task_update_pending
if Gosu.milliseconds >= @applications_expire
@applications_expire = Gosu.milliseconds + 30_000
Api.on_thread(:_applications) do |applications|
if applications
@applications_expire = Gosu.milliseconds + APPLICATIONS_UPDATE_INTERVAL # ten minutes
Store.applications = applications
# TODO: Signal Games and ServerBrowser that applications have been updated
end
end
end
if Gosu.milliseconds >= @server_list_expire
@server_list_expire = Gosu.milliseconds + 30_000
Api.on_thread(:server_list, 2) do |list|
if list
@server_list_expire = Gosu.milliseconds + SERVER_LIST_UPDATE_INTERVAL # five minutes
Store.server_list_last_fetch = Gosu.milliseconds
Api::ServerListUpdater.instance.refresh_server_list(list)
BackgroundWorker.foreground_job(-> {}, ->(_) { States::Interface.instance&.update_server_browser(nil, :refresh_all) })
end
end
end
end
def button_down(id)
@@ -274,6 +248,63 @@ class W3DHub
end
end
end
def refresh_account_token
return if Gosu.milliseconds < @account_expire
return unless account = Store.account
@account_expire = Gosu.milliseconds + 30_000
if (account.access_token_expiry - Time.now) / 60 <= 60 * 3 # Refresh if token expires within 3 hours
logger.info(LOG_TAG) { "Refreshing user login..." }
Api.on_thread(:refresh_user_login, account.refresh_token) do |refreshed_account|
if refreshed_account
Store.account = refreshed_account
Store.settings[:account][:data] = refreshed_account
else
Store.settings[:account] = {}
end
Store.settings.save_settings
end
end
end
def refresh_applications
return if Gosu.milliseconds < @applications_expire
@applications_expire = Gosu.milliseconds + 30_000
Api.on_thread(:_applications) do |applications|
if applications
@applications_expire = Gosu.milliseconds + APPLICATIONS_UPDATE_INTERVAL # ten minutes
Store.applications = applications
# TODO: Signal Games and ServerBrowser that applications have been updated
end
end
end
def refresh_server_list
return if Gosu.milliseconds < @server_list_expire
@server_list_expire = Gosu.milliseconds + 30_000
Api.on_thread(:server_list, 2) do |list|
if list
@server_list_expire = Gosu.milliseconds + SERVER_LIST_UPDATE_INTERVAL # five minutes
Store.server_list_last_fetch = Gosu.milliseconds
Api::ServerListUpdater.instance.refresh_server_list(list)
BackgroundWorker.foreground_job(-> {}, ->(_) { States::Interface.instance&.update_server_browser(nil, :refresh_all) })
end
end
end
end
end
end