diff --git a/lib/ui/command.rb b/lib/ui/command.rb deleted file mode 100644 index 76e7a4a..0000000 --- a/lib/ui/command.rb +++ /dev/null @@ -1,158 +0,0 @@ -# frozen_string_literal: true - -class IMICFPS - class Commands - module Style - def self.error(string) - "#{string}" - end - - def self.warn(string) - "#{string}" - end - - def self.notice(string) - "#{string}" - end - - def self.highlight(string, color = "5555ff") - "#{string}" - end - end - - class Command - def self.inherited(subclass) - @list ||= [] - @commands ||= [] - @list << subclass - end - - def self.setup - @list ||= [] - @commands = [] - @list.each do |subclass| - cmd = subclass.new - if @commands.detect { |c| c.command == cmd.command } - raise "Command '#{cmd.command}' from '#{cmd.class}' already exists!" - end - - @commands << cmd - end - end - - def self.use(command, arguments, console) - found_command = @commands.detect { |cmd| cmd.command == command.to_sym } - - if found_command - found_command.handle(arguments, console) - else - console.stdin("Command #{Style.error(command)} not found.") - end - end - - def self.find(command) - @commands.detect { |cmd| cmd.command == command.to_sym } - end - - def self.list_commands - @commands - end - - def initialize - @store = {} - @subcommands = [] - - setup - end - - def setup - end - - def subcommand(command, type) - if @subcommands.detect { |subcmd| subcmd.command == command.to_sym } - raise "Subcommand '#{command}' for '#{self.command}' already exists!" - end - - @subcommands << SubCommand.new(self, command, type) - end - - def get(key) - @store[key] - end - - def set(key, value) - @store[key] = value - end - - def group - raise NotImplementedError - end - - def command - raise NotImplementedError - end - - def handle(arguments, console) - raise NotImplementedError - end - - def autocomplete(console) - split = console.text_input.text.split(" ") - - if @subcommands.size.positive? - if !console.text_input.text.end_with?(" ") && split.size == 2 - list = console.abbrev_search(@subcommands.map { |cmd| cmd.command.to_s }, split.last) - - if list.size == 1 - console.text_input.text = "#{split.first} #{list.first} " - else - return unless list.size.positive? - - console.stdin(list.map { |cmd| Commands::Style.highlight(cmd) }.join(", ").to_s) - end - - # List available options on subcommand - elsif (console.text_input.text.end_with?(" ") && split.size == 2) || !console.text_input.text.end_with?(" ") && split.size == 3 - subcommand = @subcommands.detect { |cmd| cmd.command.to_s == (split[1]) } - - if subcommand - if split.size == 2 - console.stdin("Available options: #{subcommand.values.map { |value| Commands::Style.highlight(value) }.join(',')}") - else - list = console.abbrev_search(subcommand.values, split.last) - if list.size == 1 - console.text_input.text = "#{split.first} #{split[1]} #{list.first} " - elsif list.size.positive? - console.stdin("Available options: #{list.map { |value| Commands::Style.highlight(value) }.join(',')}") - end - end - end - - # List available subcommands if command was entered and has only a space after it - elsif console.text_input.text.end_with?(" ") && split.size == 1 - console.stdin("Available subcommands: #{@subcommands.map { |cmd| Commands::Style.highlight(cmd.command) }.join(', ')}") - end - end - end - - def handle_subcommand(arguments, console) - if arguments.size.zero? - console.stdin(usage) - return - end - subcommand = arguments.delete_at(0) - - found_command = @subcommands.detect { |cmd| cmd.command == subcommand.to_sym } - if found_command - found_command.handle(arguments, console) - else - console.stdin("Unknown subcommand #{Style.error(subcommand)} for #{Style.highlight(command)}") - end - end - - def usage - raise NotImplementedError - end - end - end -end diff --git a/lib/ui/commands/connect_command.rb b/lib/ui/commands/connect_command.rb index 2bc652e..2e8ff85 100644 --- a/lib/ui/commands/connect_command.rb +++ b/lib/ui/commands/connect_command.rb @@ -2,7 +2,7 @@ class IMICFPS class Commands - class ConnectCommand < Command + class ConnectCommand < CyberarmEngine::Console::Command def group :global end @@ -15,7 +15,7 @@ class IMICFPS end def usage - "Connect to a server.\n#{Style.highlight('connect')} #{Style.notice('[example.com:56789]')}" + "Connect to a server.\n#{Console::Style.highlight('connect')} #{Style.notice('example.com[:56789]')}" end end end diff --git a/lib/ui/commands/debug_command.rb b/lib/ui/commands/debug_command.rb index 23da6e0..61d5b8e 100644 --- a/lib/ui/commands/debug_command.rb +++ b/lib/ui/commands/debug_command.rb @@ -2,7 +2,7 @@ class IMICFPS class Commands - class DebugCommand < Command + class DebugCommand < CyberarmEngine::Console::Command def group :global end diff --git a/lib/ui/commands/disconnect_command.rb b/lib/ui/commands/disconnect_command.rb index c29cddf..6f50534 100644 --- a/lib/ui/commands/disconnect_command.rb +++ b/lib/ui/commands/disconnect_command.rb @@ -2,7 +2,7 @@ class IMICFPS class Commands - class DisconnectCommand < Command + class DisconnectCommand < CyberarmEngine::Console::Command def group :global end diff --git a/lib/ui/commands/fps_command.rb b/lib/ui/commands/fps_command.rb index 23111fb..1e77324 100644 --- a/lib/ui/commands/fps_command.rb +++ b/lib/ui/commands/fps_command.rb @@ -2,7 +2,7 @@ class IMICFPS class Commands - class FPSCommand < Command + class FPSCommand < CyberarmEngine::Console::Command def group :global end @@ -13,26 +13,26 @@ class IMICFPS def handle(arguments, console) if arguments.size > 1 - console.stdin("to many arguments for #{Style.highlight(command.to_s)}, got #{Style.error(arguments.size)} expected #{Style.notice(1)}.") + console.stdin("to many arguments for #{Console::Style.highlight(command.to_s)}, got #{Console::Style.error(arguments.size)} expected #{Console::Style.notice(1)}.") return end case arguments.last when "", nil - console.stdin("#{Style.highlight('fps')}: #{$window.config.get(:options, :fps)}") + console.stdin("#{Console::Style.highlight('fps')}: #{$window.config.get(:options, :fps)}") when "on" var = $window.config[:options, :fps] = true - console.stdin("fps => #{Style.highlight(var)}") + console.stdin("fps => #{Console::Style.highlight(var)}") when "off" var = $window.config[:options, :fps] = false - console.stdin("fps => #{Style.highlight(var)}") + console.stdin("fps => #{Console::Style.highlight(var)}") else - console.stdin("Invalid argument for #{Style.highlight(command.to_s)}, got #{Style.error(arguments.last)} expected #{Style.notice('on')}, or #{Style.notice('off')}.") + console.stdin("Invalid argument for #{Console::Style.highlight(command.to_s)}, got #{Console::Style.error(arguments.last)} expected #{Console::Style.notice('on')}, or #{Console::Style.notice('off')}.") end end def usage - "#{Style.highlight('fps')} #{Style.notice('[on|off]')}" + "#{Console::Style.highlight('fps')} #{Style.notice('[on|off]')}" end end end diff --git a/lib/ui/commands/help_command.rb b/lib/ui/commands/help_command.rb deleted file mode 100644 index 351a49f..0000000 --- a/lib/ui/commands/help_command.rb +++ /dev/null @@ -1,43 +0,0 @@ -# frozen_string_literal: true - -class IMICFPS - class Commands - class HelpCommand < Command - def group - :global - end - - def command - :help - end - - def handle(arguments, console) - console.stdin(usage(arguments.first)) - end - - def autocomplete(console) - split = console.text_input.text.split(" ") - if !console.text_input.text.start_with?(" ") && split.size == 2 - list = console.abbrev_search(Commands::Command.list_commands.map { |cmd| cmd.command.to_s }, split.last) - if list.size == 1 - console.text_input.text = "#{split.first} #{list.first} " - elsif list.size > 1 - console.stdin(list.map { |cmd| Style.highlight(cmd) }.join(", ")) - end - end - end - - def usage(command = nil) - if command - if cmd = Command.find(command) - cmd.usage - else - "#{Style.error(command)} is not a command" - end - else - "Available commands:\n#{Command.list_commands.map { |cmd| Style.highlight(cmd.command).to_s }.join(', ')}" - end - end - end - end -end diff --git a/lib/ui/commands/hud_command.rb b/lib/ui/commands/hud_command.rb index e1a8412..a72f52d 100644 --- a/lib/ui/commands/hud_command.rb +++ b/lib/ui/commands/hud_command.rb @@ -2,7 +2,7 @@ class IMICFPS class Commands - class HUDCommand < Command + class HUDCommand < CyberarmEngine::Console::Command def group :global end @@ -17,26 +17,26 @@ class IMICFPS def handle(arguments, console) if arguments.size > 1 - console.stdin("to many arguments for #{Style.highlight(command.to_s)}, got #{Style.error(arguments.size)} expected #{Style.notice(1)}.") + console.stdin("to many arguments for #{Console::Style.highlight(command.to_s)}, got #{Console::Style.error(arguments.size)} expected #{Console::Style.notice(1)}.") return end case arguments.last when "", nil - console.stdin("#{Style.highlight(command.to_s)}: #{$window.config.get(:options, command)}") + console.stdin("#{Console::Style.highlight(command.to_s)}: #{$window.config.get(:options, command)}") when "on" var = $window.config[:options, command] = true - console.stdin("fps => #{Style.highlight(var)}") + console.stdin("#{command} => #{Console::Style.highlight(var)}") when "off" var = $window.config[:options, command] = false - console.stdin("fps => #{Style.highlight(var)}") + console.stdin("#{command} => #{Console::Style.highlight(var)}") else - console.stdin("Invalid argument for #{Style.highlight(command.to_s)}, got #{Style.error(arguments.last)} expected #{Style.notice('on')}, or #{Style.notice('off')}.") + console.stdin("Invalid argument for #{Console::Style.highlight(command.to_s)}, got #{Console::Style.error(arguments.last)} expected #{Console::Style.notice('on')}, or #{Console::Style.notice('off')}.") end end def usage - "#{Style.highlight('hud')} #{Style.notice('[on|off]')}" + "#{Console::Style.highlight('hud')} #{Console::Style.notice('[on|off]')}" end end end diff --git a/lib/ui/commands/reload_shader_command.rb b/lib/ui/commands/reload_shader_command.rb index 4309f3e..a4fbaf7 100644 --- a/lib/ui/commands/reload_shader_command.rb +++ b/lib/ui/commands/reload_shader_command.rb @@ -2,7 +2,7 @@ class IMICFPS class Commands - class ReloadShaderCommand < Command + class ReloadShaderCommand < CyberarmEngine::Console::Command def group :reload_shader end @@ -13,7 +13,7 @@ class IMICFPS def handle(arguments, console) if arguments.size > 2 - console.stdin("to many arguments for #{Style.highlight(command.to_s)}, got #{Style.error(arguments.size)} expected #{Style.notice(1)}.") + console.stdin("to many arguments for #{Console::Style.highlight(command.to_s)}, got #{Console::Style.error(arguments.size)} expected #{Console::Style.notice(1)}.") return end @@ -51,9 +51,9 @@ class IMICFPS string = $stdout.string if shader.compiled? - console.stdin("#{Style.notice('Successfully reloaded shader')}: #{shader.name}") + console.stdin("#{Console::Style.notice('Successfully reloaded shader')}: #{shader.name}") else - console.stdin(Style.error("Failed to reload #{shader.name}").to_s) + console.stdin(Console::Style.error("Failed to reload #{shader.name}").to_s) console.stdin(string) end ensure @@ -62,7 +62,7 @@ class IMICFPS end def usage - "#{Style.highlight(command)} #{Style.notice('vertex_name [fragment_name]')}" + "#{Console::Style.highlight(command)} #{Console::Style.notice('vertex_name [fragment_name]')}" end end end diff --git a/lib/ui/commands/renderer_info_command.rb b/lib/ui/commands/renderer_info_command.rb index b44c7b1..0a804de 100644 --- a/lib/ui/commands/renderer_info_command.rb +++ b/lib/ui/commands/renderer_info_command.rb @@ -2,7 +2,7 @@ class IMICFPS class Commands - class RendererInfoCommand < Command + class RendererInfoCommand < CyberarmEngine::Console::Command def group :global end @@ -12,14 +12,14 @@ class IMICFPS end def handle(_arguments, console) - console.stdin("OpenGL Vendor: #{Style.notice(glGetString(GL_VENDOR))}") - console.stdin("OpenGL Renderer: #{Style.notice(glGetString(GL_RENDERER))}") - console.stdin("OpenGL Version: #{Style.notice(glGetString(GL_VERSION))}") - console.stdin("OpenGL Shader Language Version: #{Style.notice(glGetString(GL_SHADING_LANGUAGE_VERSION))}") + console.stdin("OpenGL Vendor: #{Console::Style.notice(glGetString(GL_VENDOR))}") + console.stdin("OpenGL Renderer: #{Console::Style.notice(glGetString(GL_RENDERER))}") + console.stdin("OpenGL Version: #{Console::Style.notice(glGetString(GL_VERSION))}") + console.stdin("OpenGL Shader Language Version: #{Console::Style.notice(glGetString(GL_SHADING_LANGUAGE_VERSION))}") end def usage - "#{Style.highlight('renderer_info')} #{Style.notice('Returns OpenGL renderer information')}" + "#{Console::Style.highlight('renderer_info')} #{Console::Style.notice('Returns OpenGL renderer information')}" end end end diff --git a/lib/ui/console.rb b/lib/ui/console.rb deleted file mode 100644 index 0edc7fa..0000000 --- a/lib/ui/console.rb +++ /dev/null @@ -1,252 +0,0 @@ -# frozen_string_literal: true - -class IMICFPS - class Console - Z = 100_000 - PADDING = 2 - include CommonMethods - - attr_reader :text_input - - def initialize - @text_input = Gosu::TextInput.new - @width = window.width / 4 * 3 - @height = window.height / 4 * 3 - - @input = Text.new("", x: 4, y: @height - (PADDING * 2), z: Console::Z + 1, font: MONOSPACE_FONT) - @input.y -= @input.height - - @history = Text.new( - "=== #{IMICFPS::NAME} v#{IMICFPS::VERSION} (#{IMICFPS::RELEASE_NAME}) ===\n\n", - x: 4, z: Console::Z + 1, font: MONOSPACE_FONT, border: true, border_color: Gosu::Color::BLACK) - update_history_y - - @command_history = [] - @command_history_index = 0 - - @memory = "" - - @background_color = Gosu::Color.rgba(0, 0, 0, 200) - @foreground_color = Gosu::Color.rgba(100, 100, 100, 100) - @input_color = Gosu::Color.rgba(100, 100, 100, 200) - - @showing_cursor = false - @active_text_input = nil - - @show_caret = true - @caret_last_change = Gosu.milliseconds - @caret_interval = 250 - @caret_color = Gosu::Color::WHITE - @selection_color = Gosu::Color.new(0x5522ff22) - end - - def draw - # Background/Border - draw_rect(0, 0, @width, @height, @background_color, Console::Z) - # Foregound/History - draw_rect(PADDING, PADDING, @width - (PADDING * 2), @height - (PADDING * 2), @foreground_color, Console::Z) - # Text bar - draw_rect(2, @input.y, @width - (PADDING * 2), @input.height, @input_color, Console::Z) - - @history.draw - @input.draw - # Caret - if @show_caret - draw_rect(@input.x + caret_from_left, @input.y, Console::PADDING, @input.height, @caret_color, Console::Z + 2) - end - # Caret selection - if caret_start != caret_end - if caret_start < @text_input.selection_start - draw_rect(@input.x + caret_from_left, @input.y, caret_selection_width, @input.height, @selection_color, Console::Z) - else - draw_rect((@input.x + caret_from_left) - caret_selection_width, @input.y, caret_selection_width, @input.height, @selection_color, Console::Z) - end - end - end - - def caret_from_left - return 0 if @text_input.caret_pos.zero? - - @input.textobject.text_width(@text_input.text[0..@text_input.caret_pos - 1]) - end - - def caret_selection_width - @input.textobject.text_width(@text_input.text[caret_start..(caret_end - 1)]) - end - - def caret_pos - @text_input.caret_pos - end - - def caret_start - @text_input.selection_start < @text_input.caret_pos ? @text_input.selection_start : @text_input.caret_pos - end - - def caret_end - @text_input.selection_start > @text_input.caret_pos ? @text_input.selection_start : @text_input.caret_pos - end - - def update - if Gosu.milliseconds - @caret_last_change >= @caret_interval - @caret_last_change = Gosu.milliseconds - @show_caret = !@show_caret - end - - if @width != window.width || @height != @height - @width = window.width / 4 * 3 - @height = window.height / 4 * 3 - - @input.y = @height - (PADDING * 2 + @input.height) - update_history_y - end - - @input.text = @text_input.text - end - - def button_down(id) - case id - when Gosu::KbEnter, Gosu::KbReturn - return unless @text_input.text.length.positive? - - @history.text += "\n> #{@text_input.text}" - @command_history << @text_input.text - @command_history_index = @command_history.size - update_history_y - handle_command - @text_input.text = "" - - when Gosu::KbUp - @command_history_index -= 1 - @command_history_index = 0 if @command_history_index.negative? - @text_input.text = @command_history[@command_history_index] - - when Gosu::KbDown - @command_history_index += 1 - if @command_history_index > @command_history.size - 1 - @text_input.text = "" unless @command_history_index > @command_history.size - @command_history_index = @command_history.size - else - @text_input.text = @command_history[@command_history_index] - end - - when Gosu::KbTab - split = @text_input.text.split(" ") - - if !@text_input.text.end_with?(" ") && split.size == 1 - list = abbrev_search(Commands::Command.list_commands.map { |cmd| cmd.command.to_s }, @text_input.text) - - if list.size == 1 - @text_input.text = "#{list.first} " - elsif list.size.positive? - stdin("\n#{list.map { |cmd| Commands::Style.highlight(cmd) }.join(', ')}") - end - elsif split.size.positive? && cmd = Commands::Command.find(split.first) - cmd.autocomplete(self) - end - - when Gosu::KbBacktick - # Remove backtick character from input - @text_input.text = if @text_input.text.size > 1 - @text_input.text[0..@text_input.text.size - 2] - else - "" - end - - # Copy - when Gosu::KbC - if control_down? && shift_down? - @memory = @text_input.text[caret_start..caret_end - 1] if caret_start != caret_end - p @memory - elsif control_down? - @text_input.text = "" - end - - # Paste - when Gosu::KbV - if control_down? && shift_down? - string = @text_input.text.chars.insert(caret_pos, @memory).join - _caret_pos = caret_pos - @text_input.text = string - @text_input.caret_pos = _caret_pos + @memory.length - @text_input.selection_start = _caret_pos + @memory.length - end - - # Cut - when Gosu::KbX - if control_down? && shift_down? - @memory = @text_input.text[caret_start..caret_end - 1] if caret_start != caret_end - string = @text_input.text.chars - Array(caret_start..caret_end - 1).each_with_index do |i, j| - string.delete_at(i - j) - end - - @text_input.text = string.join - end - - # Delete word to left of caret - when Gosu::KbW - if control_down? - split = @text_input.text.split(" ") - split.delete(split.last) - @text_input.text = split.join(" ") - end - - # Clear history - when Gosu::KbL - @history.text = "" if control_down? - end - end - - def button_up(id) - end - - def update_history_y - @history.y = @height - (PADDING * 2) - @input.height - (@history.text.lines.count * @history.textobject.height) - end - - def handle_command - string = @text_input.text - split = string.split(" ") - command = split.first - arguments = split.length.positive? ? split[1..split.length - 1] : [] - - IMICFPS::Commands::Command.use(command, arguments, self) - end - - def abbrev_search(array, text) - return [] unless text.length.positive? - - list = [] - Abbrev.abbrev(array).each do |abbrev, value| - next unless abbrev&.start_with?(text) - - list << value - end - - list.uniq - end - - def stdin(string) - @history.text += "\n#{string}" - update_history_y - end - - def focus - InputMapper.reset_keys - - @active_text_input = window.text_input - window.text_input = @text_input - - @showing_cursor = window.needs_cursor - window.needs_cursor = true - - @show_caret = true - @caret_last_change = Gosu.milliseconds - end - - def blur - window.text_input = @active_text_input - window.needs_cursor = @showing_cursor - end - end -end diff --git a/lib/ui/subcommand.rb b/lib/ui/subcommand.rb deleted file mode 100644 index b3758f5..0000000 --- a/lib/ui/subcommand.rb +++ /dev/null @@ -1,100 +0,0 @@ -# frozen_string_literal: true - -class IMICFPS - class Commands - class Command - class SubCommand - def initialize(parent, command, type) - @parent = parent - @command = command - @type = type - end - - attr_reader :command - - def handle(arguments, console) - if arguments.size > 1 - console.stdin("to many arguments for #{Style.highlight(command.to_s)}, got #{Style.error(arguments.size)} expected #{Style.notice(1)}.") - return - end - - case @type - when :boolean - case arguments.last - when "", nil - var = @parent.get(command.to_sym) || false - console.stdin("#{command}: #{Style.highlight(var)}") - when "on" - var = @parent.set(command.to_sym, true) - console.stdin("#{command} => #{Style.highlight(var)}") - when "off" - var = @parent.set(command.to_sym, false) - console.stdin("#{command} => #{Style.highlight(var)}") - else - console.stdin("Invalid argument for #{Style.highlight(command.to_s)}, got #{Style.error(arguments.last)} expected #{Style.notice('on')}, or #{Style.notice('off')}.") - end - when :string - case arguments.last - when "", nil - var = @parent.get(command.to_sym) || "\"\"" - console.stdin("#{command}: #{Style.highlight(var)}") - else - var = @parent.set(command.to_sym, arguments.last) - console.stdin("#{command} => #{Style.highlight(var)}") - end - when :integer - case arguments.last - when "", nil - var = @parent.get(command.to_sym) || "nil" - console.stdin("#{command}: #{Style.highlight(var)}") - else - begin - var = @parent.set(command.to_sym, Integer(arguments.last)) - console.stdin("#{command} => #{Style.highlight(var)}") - rescue ArgumentError - console.stdin("Error: #{Style.error("Expected an integer, got '#{arguments.last}'")}") - end - end - when :decimal - case arguments.last - when "", nil - var = @parent.get(command.to_sym) || "nil" - console.stdin("#{command}: #{Style.highlight(var)}") - else - begin - var = @parent.set(command.to_sym, Float(arguments.last)) - console.stdin("#{command} => #{Style.highlight(var)}") - rescue ArgumentError - console.stdin("Error: #{Style.error("Expected a decimal or integer, got '#{arguments.last}'")}") - end - end - else - raise RuntimeError - end - end - - def values - case @type - when :boolean - %w[on off] - else - [] - end - end - - def usage - case @type - when :boolean - "#{Style.highlight(command)} #{Style.notice('[on|off]')}" - when :string - "#{Style.highlight(command)} #{Style.notice('[string]')}" - when :integer - "#{Style.highlight(command)} #{Style.notice('[0]')}" - when :decimal - "#{Style.highlight(command)} #{Style.notice('[0.0]')}" - end - end - end - end - end -end diff --git a/lib/window.rb b/lib/window.rb index 05bf088..1eb6808 100644 --- a/lib/window.rb +++ b/lib/window.rb @@ -22,7 +22,8 @@ class IMICFPS @config = CyberarmEngine::ConfigFile.new(file: "#{IMICFPS::GAME_ROOT_PATH}/data/config.json") @show_console = false @console = Console.new - Commands::Command.setup + CyberarmEngine::Console::Command.setup + @console.stdin("=== #{IMICFPS::NAME} v#{IMICFPS::VERSION} (#{IMICFPS::RELEASE_NAME}) ===\n\n") SettingsMenu.set_defaults @renderer = Renderer.new @@ -105,7 +106,7 @@ class IMICFPS end if id == Gosu::KbBacktick - @show_console ? @console.blur : @console.focus + @show_console ? @console.blur : @console.focus && InputMapper.reset_keys @show_console = !@show_console end end