diff --git a/lib/backend.rb b/lib/backend.rb index 0e78b64..d3c9070 100644 --- a/lib/backend.rb +++ b/lib/backend.rb @@ -41,12 +41,14 @@ module TAC def upload_config if @tacnet.connected? - @tacnet.puts(TAC::TACNET::PacketHandler.packet_dump_config(json)) + json = JSON.dump(@config) + @tacnet.puts(TAC::TACNET::PacketHandler.packet_upload_config(json)) end end def download_config if @tacnet.connected? + @tacnet.puts(TAC::TACNET::PacketHandler.packet_download_config) end end diff --git a/lib/dialogs/confirm_dialog.rb b/lib/dialogs/confirm_dialog.rb index 771ed69..f65f9b6 100644 --- a/lib/dialogs/confirm_dialog.rb +++ b/lib/dialogs/confirm_dialog.rb @@ -10,9 +10,9 @@ module TAC close end button "Okay", width: 0.475, text_size: 18 do - @options[:callback_method].call - close + + @options[:callback_method].call end end end diff --git a/lib/states/boot.rb b/lib/states/boot.rb new file mode 100644 index 0000000..247327e --- /dev/null +++ b/lib/states/boot.rb @@ -0,0 +1,36 @@ +module TAC + class States + class Boot < CyberarmEngine::GuiState + def setup + stack width: 1.0, height: 1.0 do + background [TAC::Palette::TIMECRAFTERS_PRIMARY, TAC::Palette::TIMECRAFTERS_SECONDARY, TAC::Palette::TIMECRAFTERS_TERTIARY, TAC::Palette::TIMECRAFTERS_PRIMARY] + end + + @title_font = CyberarmEngine::Text.new(TAC::NAME, z: 100, size: 72, shadow: true, shadow_size: 3, font: THEME[:Label][:font]) + @logo = Gosu::Image.new("#{TAC::ROOT_PATH}/media/logo.png") + + @animator = CyberarmEngine::Animator.new(start_time: 0, duration: 3_000, from: 0, to: 255) + @transition_color = Gosu::Color.new(0x00_000000) + end + + def draw + super + + @title_font.draw + @logo.draw(window.width / 2 - @logo.width / 2, window.height / 2 - @logo.height / 2, 99) + Gosu.draw_rect(0, 0, window.width, window.height, @transition_color, 10_00) + end + + def update + super + + @title_font.x = window.width / 2 - @title_font.width / 2 + @title_font.y = window.height / 2 - (@logo.height / 2 + @title_font.height) + + @transition_color.alpha = @animator.transition(0, 255, :sine) + + push_state(Editor) if @transition_color.alpha >= 255 + end + end + end +end \ No newline at end of file diff --git a/lib/states/editor.rb b/lib/states/editor.rb index fa82659..c627d2a 100644 --- a/lib/states/editor.rb +++ b/lib/states/editor.rb @@ -37,7 +37,7 @@ module TAC window.backend.upload_config end button "▼", text_size: 18, margin_left: 10, tip: "Download remote config, if connected." do - push_state(Dialog::ConfirmDialog, title: "Are you sure?", message: "Replace local config with\n remote config?", callback_method: proc { window.backend.download_config }) + window.backend.download_config end end end @@ -57,7 +57,7 @@ module TAC when :connected, :connecting window.backend.tacnet.close when :not_connected, :connection_error - window.backend.tacnet.connect("localhost") + window.backend.tacnet.connect("localhost")#("192.168.1.5") end end button "Status", text_size: 18, width: 0.475 do @@ -77,8 +77,8 @@ module TAC button "+", text_size: 18 do push_state(TAC::Dialog::NamePromptDialog, title: "Create Group", callback_method: method(:create_group)) end - button "Clone", text_size: 18 - button "Create Preset", text_size: 18 + button "Clone", text_size: 18, tip: "Clone currently selected group" + button "Create Preset", text_size: 18, tip: "Save group as preset" end @groups_list = stack width: 1.0 do @@ -95,8 +95,8 @@ module TAC push_state(TAC::Dialog::AlertDialog, title: "Error", message: "Unable to create action,\nno group selected.") end end - button "Clone", text_size: 18 - button "Create Preset", text_size: 18 + button "Clone", text_size: 18, tip: "Clone currently selected action" + button "Create Preset", text_size: 18, tip: "Save action as preset" end @actions_list = stack width: 1.0 do diff --git a/lib/tacnet/client.rb b/lib/tacnet/client.rb index f8b8eea..74c3b91 100644 --- a/lib/tacnet/client.rb +++ b/lib/tacnet/client.rb @@ -3,6 +3,7 @@ module TAC class Client TAG = "TACNET|Client" CHUNK_SIZE = 4096 + PACKET_TAIL = "\r\n\n" attr_reader :uuid, :read_queue, :write_queue, :socket, :packets_sent, :packets_received, @@ -105,7 +106,7 @@ module TAC def write(message) begin - @socket.puts("#{message}\r\n\n") + @socket.puts("#{message}#{PACKET_TAIL}") rescue => error @last_socket_error = error @socket_error = true @@ -115,18 +116,14 @@ module TAC end def read - message = "" - begin - data = @socket.readpartial(CHUNK_SIZE) - message += data + message = @socket.gets rescue => error @last_socket_error = error @socket_error = true message = "" - break - end until message.end_with?("\r\n\n") + end return message.strip diff --git a/lib/tacnet/connection.rb b/lib/tacnet/connection.rb index 2454af5..cfacd18 100644 --- a/lib/tacnet/connection.rb +++ b/lib/tacnet/connection.rb @@ -9,10 +9,10 @@ module TAC @client = nil - @last_sync_time = 0 + @last_sync_time = Gosu.milliseconds @sync_interval = SYNC_INTERVAL - @last_heartbeat_sent = 0 + @last_heartbeat_sent = Gosu.milliseconds @heartbeat_interval = HEARTBEAT_INTERVAL @connection_handler = proc do @@ -63,6 +63,8 @@ module TAC @client.puts(PacketHandler.packet_heartbeat) end + + sleep @sync_interval / 1000.0 end end diff --git a/lib/tacnet/packet.rb b/lib/tacnet/packet.rb index 2f04208..9a67bcf 100644 --- a/lib/tacnet/packet.rb +++ b/lib/tacnet/packet.rb @@ -1,26 +1,27 @@ module TAC class TACNET class Packet - PROTOCOL_VERSION = 0 + PROTOCOL_VERSION = 1 PROTOCOL_HEADER_SEPERATOR = "|" PROTOCOL_HEARTBEAT = "heartbeat" PACKET_TYPES = { handshake: 0, heartbeat: 1, - dump_config: 2, + download_config: 2, + upload_config: 3, - add_group: 3, - update_group: 4, - delete_group: 5, + add_group: 20, + update_group: 21, + delete_group: 22, - add_action: 6, - update_action: 7, - delete_action: 8, + add_action: 30, + update_action: 31, + delete_action: 32, - add_variable: 9, - update_variable: 10, - delete_variable: 11, + add_variable: 40, + update_variable: 41, + delete_variable: 42, } def self.from_stream(message) diff --git a/lib/tacnet/packet_handler.rb b/lib/tacnet/packet_handler.rb index bdfae1f..3fcd1d2 100644 --- a/lib/tacnet/packet_handler.rb +++ b/lib/tacnet/packet_handler.rb @@ -22,8 +22,10 @@ module TAC handle_handshake(packet) when :heartbeat handle_heartbeat(packet) - when :dump_config - handle_dump_config(packet) + when :download_config + handle_download_config(packet) + when :upload_config + handle_upload_config(packet) else log.d(TAG, "No hand off available for packet type: #{packet.type}") end @@ -39,16 +41,49 @@ module TAC def handle_heartbeat(packet) end - def handle_dump_config(packet) + def handle_upload_config(packet) begin - hash = JSON.parse(packet.body) + data = JSON.parse(packet.body, symbolize_names: true) if @host_is_a_connection - File.open("#{TAC::ROOT_PATH}/data/config.json", "w") { |f| f.write packet.body } + if data.is_a?(Array) + # OLDEST CONFIG, upgrade? + $window.push_state(TAC::Dialog::AlertDialog, title: "Invalid Config", message: "Remote config to old.") - $window.backend.update_config + elsif data.is_a?(Hash) && data.dig(:config, :spec_version) == TAC::CONFIG_SPEC_VERSION + $window.push_state(TAC::Dialog::ConfirmDialog, title: "Replace Config", message: "Replace local config\nwith remote config?", callback_method: proc { + File.open("#{TAC::ROOT_PATH}/data/config.json", "w") { |f| f.write packet.body } + + $window.backend.update_config + }) + + elsif data.is_a?(Hash) && data.dig(:config, :spec_version) < TAC::CONFIG_SPEC_VERSION + # OLD CONFIG, Upgrade? + $window.push_state(TAC::Dialog::ConfirmDialog, title: "Upgrade Config", message: "Remote config is an older\nspec version.\nTry to upgrade?", callback_method: proc {}) + + elsif data.is_a?(Hash) && data.dig(:config, :spec_version) > TAC::CONFIG_SPEC_VERSION + # NEWER CONFIG, Error Out + $window.push_state(TAC::Dialog::AlertDialog, title: "Invalid Config", message: "Client outdated, check for\nupdates.\nSupported config spec:\nv#{TAC::CONFIG_SPEC_VERSION} got v#{data.dig(:config, :spec_version)}") + + else + # CONFIG is unknown + $window.push_state(TAC::Dialog::AlertDialog, title: "Invalid Config", message: "Remote config is not supported.") + end + end + rescue JSON::ParserError => e + log.e(TAG, "JSON parsing error: #{e}") + end + end + + def handle_download_config(packet) + if @host_is_a_connection + json = JSON.dump($window.backend.config) + $window.backend.tacnet.puts(PacketHandler.packet_upload_config(json)) + else + if $server.active_client && $server.active_client.connected? + json = File.read(TAC::CONFIG_PATH) + $server.active_client.puts(PacketHandler.packet_upload_config(json)) end - rescue JSON::ParserError end end @@ -60,10 +95,14 @@ module TAC Packet.create(Packet::PACKET_TYPES[:heartbeat], Packet::PROTOCOL_HEARTBEAT) end - def self.packet_dump_config(string) + def self.packet_download_config + Packet.create(Packet::PACKET_TYPES[:download_config], "") + end + + def self.packet_upload_config(string) string = string.gsub("\n", " ") - Packet.create(Packet::PACKET_TYPES[:dump_config], string) + Packet.create(Packet::PACKET_TYPES[:upload_config], string) end end end diff --git a/lib/tacnet/server.rb b/lib/tacnet/server.rb index faadbb7..116a323 100644 --- a/lib/tacnet/server.rb +++ b/lib/tacnet/server.rb @@ -6,6 +6,8 @@ module TAC :packets_sent, :packets_received, :data_sent, :data_received, :client_last_packets_sent, :client_last_packets_received, :client_last_data_sent, :client_last_data_received def initialize(port = DEFAULT_PORT) + $server = self + @port = port @socket = nil @@ -16,10 +18,10 @@ module TAC @packets_sent, @packets_received, @client_last_packets_sent, @client_last_packets_received = 0, 0, 0, 0 @data_sent, @data_received, @client_last_data_sent, @client_last_data_received = 0, 0, 0, 0 - @last_sync_time = 0 + @last_sync_time = Gosu.milliseconds @sync_interval = SYNC_INTERVAL - @last_heartbeat_sent = 0 + @last_heartbeat_sent = Gosu.milliseconds @heartbeat_interval = HEARTBEAT_INTERVAL @client_handler_proc = proc do @@ -72,7 +74,7 @@ module TAC config = File.read(TAC::CONFIG_PATH) @active_client.puts(PacketHandler.packet_handshake(@active_client.uuid)) - @active_client.puts(PacketHandler.packet_dump_config(config)) + @active_client.puts(PacketHandler.packet_upload_config(config)) log.i(TAG, "Client connected!") @@ -111,6 +113,8 @@ module TAC @active_client.puts(PacketHandler.packet_heartbeat) end + + sleep @sync_interval / 1000.0 end end diff --git a/lib/window.rb b/lib/window.rb index c5015bb..2e40716 100644 --- a/lib/window.rb +++ b/lib/window.rb @@ -6,7 +6,7 @@ module TAC self.caption = "#{TAC::NAME} v#{TAC::VERSION} (#{TAC::RELEASE_NAME})" @backend = Backend.new - push_state(TAC::States::Editor) + push_state(TAC::States::Boot) end def needs_cursor? diff --git a/media/LICENSE b/media/FONT_LICENSE similarity index 100% rename from media/LICENSE rename to media/FONT_LICENSE diff --git a/media/logo.png b/media/logo.png new file mode 100644 index 0000000..b5bc0c0 Binary files /dev/null and b/media/logo.png differ diff --git a/timecrafters_action_configurator.rb b/timecrafters_action_configurator.rb index c44e90e..c12c7e5 100644 --- a/timecrafters_action_configurator.rb +++ b/timecrafters_action_configurator.rb @@ -9,6 +9,7 @@ require_relative "lib/window" require_relative "lib/version" require_relative "lib/storage" require_relative "lib/backend" +require_relative "lib/states/boot" require_relative "lib/states/editor" require_relative "lib/states/manage_presets" require_relative "lib/theme"