cyberarm_engine 0.24.3 → 0.24.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +8 -8
- data/.rubocop.yml +7 -7
- data/.travis.yml +5 -5
- data/Gemfile +6 -6
- data/Gemfile.lock +24 -0
- data/LICENSE.txt +21 -21
- data/README.md +74 -74
- data/Rakefile +10 -10
- data/assets/shaders/fragment/g_buffer.glsl +30 -30
- data/assets/shaders/fragment/lighting.glsl +115 -69
- data/assets/shaders/include/light_struct.glsl +11 -11
- data/assets/shaders/include/material_struct.glsl +16 -16
- data/assets/shaders/vertex/g_buffer.glsl +28 -28
- data/assets/shaders/vertex/lighting.glsl +24 -24
- data/bin/console +14 -14
- data/bin/setup +8 -8
- data/cyberarm_engine.gemspec +36 -36
- data/lib/cyberarm_engine/animator.rb +219 -219
- data/lib/cyberarm_engine/background.rb +180 -179
- data/lib/cyberarm_engine/background_image.rb +93 -93
- data/lib/cyberarm_engine/background_nine_slice.rb +142 -142
- data/lib/cyberarm_engine/bounding_box.rb +150 -150
- data/lib/cyberarm_engine/builtin/intro_state.rb +130 -130
- data/lib/cyberarm_engine/cache/download_manager.rb +123 -123
- data/lib/cyberarm_engine/cache.rb +4 -4
- data/lib/cyberarm_engine/common.rb +128 -128
- data/lib/cyberarm_engine/config_file.rb +46 -46
- data/lib/cyberarm_engine/console/command.rb +157 -157
- data/lib/cyberarm_engine/console/commands/help_command.rb +43 -43
- data/lib/cyberarm_engine/console/subcommand.rb +99 -99
- data/lib/cyberarm_engine/console.rb +248 -248
- data/lib/cyberarm_engine/game_object.rb +244 -244
- data/lib/cyberarm_engine/game_state.rb +124 -124
- data/lib/cyberarm_engine/gosu_ext/draw_arc.rb +97 -97
- data/lib/cyberarm_engine/gosu_ext/draw_circle.rb +30 -30
- data/lib/cyberarm_engine/gosu_ext/draw_path.rb +17 -17
- data/lib/cyberarm_engine/model/material.rb +21 -21
- data/lib/cyberarm_engine/model/{model_object.rb → mesh.rb} +131 -131
- data/lib/cyberarm_engine/model/parser.rb +74 -74
- data/lib/cyberarm_engine/model/parsers/collada_parser.rb +138 -138
- data/lib/cyberarm_engine/model/parsers/wavefront_parser.rb +154 -154
- data/lib/cyberarm_engine/model.rb +216 -213
- data/lib/cyberarm_engine/model_cache.rb +31 -31
- data/lib/cyberarm_engine/notification.rb +82 -82
- data/lib/cyberarm_engine/notification_manager.rb +241 -241
- data/lib/cyberarm_engine/opengl/light.rb +52 -50
- data/lib/cyberarm_engine/opengl/orthographic_camera.rb +46 -46
- data/lib/cyberarm_engine/opengl/perspective_camera.rb +41 -38
- data/lib/cyberarm_engine/opengl/renderer/bounding_box_renderer.rb +249 -249
- data/lib/cyberarm_engine/opengl/renderer/g_buffer.rb +167 -165
- data/lib/cyberarm_engine/opengl/renderer/opengl_renderer.rb +307 -304
- data/lib/cyberarm_engine/opengl/renderer/renderer.rb +33 -33
- data/lib/cyberarm_engine/opengl/shader.rb +408 -406
- data/lib/cyberarm_engine/opengl/texture.rb +69 -69
- data/lib/cyberarm_engine/opengl.rb +53 -40
- data/lib/cyberarm_engine/ray.rb +56 -56
- data/lib/cyberarm_engine/stats.rb +200 -200
- data/lib/cyberarm_engine/text.rb +260 -260
- data/lib/cyberarm_engine/timer.rb +23 -23
- data/lib/cyberarm_engine/transform.rb +296 -296
- data/lib/cyberarm_engine/trees/aabb_node.rb +126 -0
- data/lib/cyberarm_engine/trees/aabb_tree.rb +55 -0
- data/lib/cyberarm_engine/trees/aabb_tree_debug.rb +29 -0
- data/lib/cyberarm_engine/ui/border_canvas.rb +102 -102
- data/lib/cyberarm_engine/ui/dsl.rb +142 -142
- data/lib/cyberarm_engine/ui/element.rb +662 -662
- data/lib/cyberarm_engine/ui/elements/button.rb +100 -100
- data/lib/cyberarm_engine/ui/elements/check_box.rb +54 -54
- data/lib/cyberarm_engine/ui/elements/container.rb +404 -410
- data/lib/cyberarm_engine/ui/elements/edit_box.rb +179 -179
- data/lib/cyberarm_engine/ui/elements/edit_line.rb +297 -297
- data/lib/cyberarm_engine/ui/elements/flow.rb +15 -15
- data/lib/cyberarm_engine/ui/elements/image.rb +72 -72
- data/lib/cyberarm_engine/ui/elements/list_box.rb +79 -79
- data/lib/cyberarm_engine/ui/elements/menu.rb +27 -27
- data/lib/cyberarm_engine/ui/elements/menu_item.rb +6 -6
- data/lib/cyberarm_engine/ui/elements/progress.rb +93 -93
- data/lib/cyberarm_engine/ui/elements/radio.rb +6 -6
- data/lib/cyberarm_engine/ui/elements/slider.rb +107 -107
- data/lib/cyberarm_engine/ui/elements/stack.rb +11 -11
- data/lib/cyberarm_engine/ui/elements/text_block.rb +216 -216
- data/lib/cyberarm_engine/ui/elements/toggle_button.rb +67 -67
- data/lib/cyberarm_engine/ui/event.rb +54 -54
- data/lib/cyberarm_engine/ui/gui_state.rb +321 -321
- data/lib/cyberarm_engine/ui/style.rb +50 -50
- data/lib/cyberarm_engine/ui/theme.rb +225 -225
- data/lib/cyberarm_engine/vector.rb +312 -312
- data/lib/cyberarm_engine/version.rb +4 -4
- data/lib/cyberarm_engine/window.rb +195 -195
- data/lib/cyberarm_engine.rb +70 -78
- data/mrbgem.rake +29 -29
- metadata +8 -7
@@ -1,128 +1,128 @@
|
|
1
|
-
module CyberarmEngine
|
2
|
-
module Common
|
3
|
-
def push_state(klass, options = {})
|
4
|
-
window.push_state(klass, options)
|
5
|
-
end
|
6
|
-
|
7
|
-
def current_state
|
8
|
-
window.current_state
|
9
|
-
end
|
10
|
-
|
11
|
-
def previous_state(state = nil)
|
12
|
-
raise "Only available for CyberarmEngine::GameState and subclasses" unless is_a?(CyberarmEngine::GameState) || state.is_a?(CyberarmEngine::GameState)
|
13
|
-
|
14
|
-
i = window.states.index(state || self)
|
15
|
-
window.states[i - 1] unless (i - 1).negative?
|
16
|
-
end
|
17
|
-
|
18
|
-
def pop_state
|
19
|
-
window.pop_state
|
20
|
-
end
|
21
|
-
|
22
|
-
def shift_state
|
23
|
-
window.shift_state
|
24
|
-
end
|
25
|
-
|
26
|
-
def show_cursor
|
27
|
-
window.show_cursor
|
28
|
-
end
|
29
|
-
|
30
|
-
def show_cursor=(boolean)
|
31
|
-
window.show_cursor = boolean
|
32
|
-
end
|
33
|
-
|
34
|
-
def find_element_by_tag(container, tag, list = [])
|
35
|
-
return unless container
|
36
|
-
|
37
|
-
container.children.each do |child|
|
38
|
-
list << child if child.style.tag == tag
|
39
|
-
|
40
|
-
find_element_by_tag(child, tag, list) if child.is_a?(CyberarmEngine::Element::Container)
|
41
|
-
end
|
42
|
-
|
43
|
-
list.first
|
44
|
-
end
|
45
|
-
|
46
|
-
def draw_rect(x, y, width, height, color, z = 0, mode = :default)
|
47
|
-
Gosu.draw_rect(x, y, width, height, color, z, mode)
|
48
|
-
end
|
49
|
-
|
50
|
-
def fill(color, z = 0)
|
51
|
-
draw_rect(0, 0, window.width, window.height, color, z)
|
52
|
-
end
|
53
|
-
|
54
|
-
def lighten(color, amount = 25)
|
55
|
-
if color.respond_to?(:alpha)
|
56
|
-
Gosu::Color.rgba(color.red + amount, color.green + amount, color.blue + amount, color.alpha)
|
57
|
-
else
|
58
|
-
Gosu::Color.rgb(color.red + amount, color.green + amount, color.blue + amount)
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
def darken(color, amount = 25)
|
63
|
-
if color.respond_to?(:alpha)
|
64
|
-
Gosu::Color.rgba(color.red - amount, color.green - amount, color.blue - amount, color.alpha)
|
65
|
-
else
|
66
|
-
Gosu::Color.rgb(color.red - amount, color.green - amount, color.blue - amount)
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
def opacity(color, ratio = 1.0)
|
71
|
-
alpha = 255 * ratio
|
72
|
-
|
73
|
-
Gosu::Color.rgba(color.red, color.green, color.blue, alpha)
|
74
|
-
end
|
75
|
-
|
76
|
-
def get_asset(path, hash, klass, retro = false, tileable = false)
|
77
|
-
asset = nil
|
78
|
-
hash.detect do |_asset, instance|
|
79
|
-
if _asset == path
|
80
|
-
asset = instance
|
81
|
-
true
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
unless asset
|
86
|
-
instance = nil
|
87
|
-
instance = if klass == Gosu::Image
|
88
|
-
klass.new(path, retro: retro, tileable: tileable)
|
89
|
-
else
|
90
|
-
klass.new(path)
|
91
|
-
end
|
92
|
-
|
93
|
-
hash[path] = instance
|
94
|
-
asset = instance
|
95
|
-
end
|
96
|
-
|
97
|
-
asset
|
98
|
-
end
|
99
|
-
|
100
|
-
def get_image(path, retro: false, tileable: false)
|
101
|
-
get_asset(path, Window::IMAGES, Gosu::Image, retro, tileable)
|
102
|
-
end
|
103
|
-
|
104
|
-
def get_sample(path)
|
105
|
-
get_asset(path, Window::SAMPLES, Gosu::Sample)
|
106
|
-
end
|
107
|
-
|
108
|
-
def get_song(path)
|
109
|
-
get_asset(path, Window::SONGS, Gosu::Song)
|
110
|
-
end
|
111
|
-
|
112
|
-
def window
|
113
|
-
CyberarmEngine::Window.instance
|
114
|
-
end
|
115
|
-
|
116
|
-
def control_down?
|
117
|
-
Gosu.button_down?(Gosu::KB_LEFT_CONTROL) || Gosu.button_down?(Gosu::KB_RIGHT_CONTROL)
|
118
|
-
end
|
119
|
-
|
120
|
-
def shift_down?
|
121
|
-
Gosu.button_down?(Gosu::KB_LEFT_SHIFT) || Gosu.button_down?(Gosu::KB_RIGHT_SHIFT)
|
122
|
-
end
|
123
|
-
|
124
|
-
def alt_down?
|
125
|
-
Gosu.button_down?(Gosu::KB_LEFT_ALT) || Gosu.button_down?(Gosu::KB_RIGHT_ALT)
|
126
|
-
end
|
127
|
-
end
|
128
|
-
end
|
1
|
+
module CyberarmEngine
|
2
|
+
module Common
|
3
|
+
def push_state(klass, options = {})
|
4
|
+
window.push_state(klass, options)
|
5
|
+
end
|
6
|
+
|
7
|
+
def current_state
|
8
|
+
window.current_state
|
9
|
+
end
|
10
|
+
|
11
|
+
def previous_state(state = nil)
|
12
|
+
raise "Only available for CyberarmEngine::GameState and subclasses" unless is_a?(CyberarmEngine::GameState) || state.is_a?(CyberarmEngine::GameState)
|
13
|
+
|
14
|
+
i = window.states.index(state || self)
|
15
|
+
window.states[i - 1] unless (i - 1).negative?
|
16
|
+
end
|
17
|
+
|
18
|
+
def pop_state
|
19
|
+
window.pop_state
|
20
|
+
end
|
21
|
+
|
22
|
+
def shift_state
|
23
|
+
window.shift_state
|
24
|
+
end
|
25
|
+
|
26
|
+
def show_cursor
|
27
|
+
window.show_cursor
|
28
|
+
end
|
29
|
+
|
30
|
+
def show_cursor=(boolean)
|
31
|
+
window.show_cursor = boolean
|
32
|
+
end
|
33
|
+
|
34
|
+
def find_element_by_tag(container, tag, list = [])
|
35
|
+
return unless container
|
36
|
+
|
37
|
+
container.children.each do |child|
|
38
|
+
list << child if child.style.tag == tag
|
39
|
+
|
40
|
+
find_element_by_tag(child, tag, list) if child.is_a?(CyberarmEngine::Element::Container)
|
41
|
+
end
|
42
|
+
|
43
|
+
list.first
|
44
|
+
end
|
45
|
+
|
46
|
+
def draw_rect(x, y, width, height, color, z = 0, mode = :default)
|
47
|
+
Gosu.draw_rect(x, y, width, height, color, z, mode)
|
48
|
+
end
|
49
|
+
|
50
|
+
def fill(color, z = 0)
|
51
|
+
draw_rect(0, 0, window.width, window.height, color, z)
|
52
|
+
end
|
53
|
+
|
54
|
+
def lighten(color, amount = 25)
|
55
|
+
if color.respond_to?(:alpha)
|
56
|
+
Gosu::Color.rgba(color.red + amount, color.green + amount, color.blue + amount, color.alpha)
|
57
|
+
else
|
58
|
+
Gosu::Color.rgb(color.red + amount, color.green + amount, color.blue + amount)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def darken(color, amount = 25)
|
63
|
+
if color.respond_to?(:alpha)
|
64
|
+
Gosu::Color.rgba(color.red - amount, color.green - amount, color.blue - amount, color.alpha)
|
65
|
+
else
|
66
|
+
Gosu::Color.rgb(color.red - amount, color.green - amount, color.blue - amount)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def opacity(color, ratio = 1.0)
|
71
|
+
alpha = 255 * ratio
|
72
|
+
|
73
|
+
Gosu::Color.rgba(color.red, color.green, color.blue, alpha)
|
74
|
+
end
|
75
|
+
|
76
|
+
def get_asset(path, hash, klass, retro = false, tileable = false)
|
77
|
+
asset = nil
|
78
|
+
hash.detect do |_asset, instance|
|
79
|
+
if _asset == path
|
80
|
+
asset = instance
|
81
|
+
true
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
unless asset
|
86
|
+
instance = nil
|
87
|
+
instance = if klass == Gosu::Image
|
88
|
+
klass.new(path, retro: retro, tileable: tileable)
|
89
|
+
else
|
90
|
+
klass.new(path)
|
91
|
+
end
|
92
|
+
|
93
|
+
hash[path] = instance
|
94
|
+
asset = instance
|
95
|
+
end
|
96
|
+
|
97
|
+
asset
|
98
|
+
end
|
99
|
+
|
100
|
+
def get_image(path, retro: false, tileable: false)
|
101
|
+
get_asset(path, Window::IMAGES, Gosu::Image, retro, tileable)
|
102
|
+
end
|
103
|
+
|
104
|
+
def get_sample(path)
|
105
|
+
get_asset(path, Window::SAMPLES, Gosu::Sample)
|
106
|
+
end
|
107
|
+
|
108
|
+
def get_song(path)
|
109
|
+
get_asset(path, Window::SONGS, Gosu::Song)
|
110
|
+
end
|
111
|
+
|
112
|
+
def window
|
113
|
+
CyberarmEngine::Window.instance
|
114
|
+
end
|
115
|
+
|
116
|
+
def control_down?
|
117
|
+
Gosu.button_down?(Gosu::KB_LEFT_CONTROL) || Gosu.button_down?(Gosu::KB_RIGHT_CONTROL)
|
118
|
+
end
|
119
|
+
|
120
|
+
def shift_down?
|
121
|
+
Gosu.button_down?(Gosu::KB_LEFT_SHIFT) || Gosu.button_down?(Gosu::KB_RIGHT_SHIFT)
|
122
|
+
end
|
123
|
+
|
124
|
+
def alt_down?
|
125
|
+
Gosu.button_down?(Gosu::KB_LEFT_ALT) || Gosu.button_down?(Gosu::KB_RIGHT_ALT)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
@@ -1,46 +1,46 @@
|
|
1
|
-
module CyberarmEngine
|
2
|
-
class ConfigFile
|
3
|
-
def initialize(file:)
|
4
|
-
@file = file
|
5
|
-
|
6
|
-
if File.exist?(@file)
|
7
|
-
deserialize
|
8
|
-
else
|
9
|
-
@data = {}
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
|
-
def []=(*keys, value)
|
14
|
-
last_key = keys.last
|
15
|
-
|
16
|
-
if keys.size == 1
|
17
|
-
hash = @data
|
18
|
-
else
|
19
|
-
keys.pop
|
20
|
-
hash = @data[keys.shift] ||= {}
|
21
|
-
|
22
|
-
keys.each do |key|
|
23
|
-
hash = hash[key] ||= {}
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
hash[last_key] = value
|
28
|
-
end
|
29
|
-
|
30
|
-
def get(*keys)
|
31
|
-
@data.dig(*keys)
|
32
|
-
end
|
33
|
-
|
34
|
-
def serialize
|
35
|
-
JSON.dump(@data)
|
36
|
-
end
|
37
|
-
|
38
|
-
def deserialize
|
39
|
-
@data = JSON.parse(File.read(@file), symbolize_names: true)
|
40
|
-
end
|
41
|
-
|
42
|
-
def save!
|
43
|
-
File.open(@file, "w") { |f| f.write(serialize) }
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
1
|
+
module CyberarmEngine
|
2
|
+
class ConfigFile
|
3
|
+
def initialize(file:)
|
4
|
+
@file = file
|
5
|
+
|
6
|
+
if File.exist?(@file)
|
7
|
+
deserialize
|
8
|
+
else
|
9
|
+
@data = {}
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def []=(*keys, value)
|
14
|
+
last_key = keys.last
|
15
|
+
|
16
|
+
if keys.size == 1
|
17
|
+
hash = @data
|
18
|
+
else
|
19
|
+
keys.pop
|
20
|
+
hash = @data[keys.shift] ||= {}
|
21
|
+
|
22
|
+
keys.each do |key|
|
23
|
+
hash = hash[key] ||= {}
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
hash[last_key] = value
|
28
|
+
end
|
29
|
+
|
30
|
+
def get(*keys)
|
31
|
+
@data.dig(*keys)
|
32
|
+
end
|
33
|
+
|
34
|
+
def serialize
|
35
|
+
JSON.dump(@data)
|
36
|
+
end
|
37
|
+
|
38
|
+
def deserialize
|
39
|
+
@data = JSON.parse(File.read(@file), symbolize_names: true)
|
40
|
+
end
|
41
|
+
|
42
|
+
def save!
|
43
|
+
File.open(@file, "w") { |f| f.write(serialize) }
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -1,158 +1,158 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module CyberarmEngine
|
4
|
-
class Console
|
5
|
-
module Style
|
6
|
-
def self.error(string)
|
7
|
-
"<c=ff5555>#{string}</c>"
|
8
|
-
end
|
9
|
-
|
10
|
-
def self.warn(string)
|
11
|
-
"<c=ff7700>#{string}</c>"
|
12
|
-
end
|
13
|
-
|
14
|
-
def self.notice(string)
|
15
|
-
"<c=55ff55>#{string}</c>"
|
16
|
-
end
|
17
|
-
|
18
|
-
def self.highlight(string, color = "5555ff")
|
19
|
-
"<c=#{color}>#{string}</c>"
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
class Command
|
24
|
-
def self.inherited(subclass)
|
25
|
-
@list ||= []
|
26
|
-
@commands ||= []
|
27
|
-
@list << subclass
|
28
|
-
end
|
29
|
-
|
30
|
-
def self.setup
|
31
|
-
@list ||= []
|
32
|
-
@commands = []
|
33
|
-
@list.each do |subclass|
|
34
|
-
cmd = subclass.new
|
35
|
-
if @commands.detect { |c| c.command == cmd.command }
|
36
|
-
raise "Command '#{cmd.command}' from '#{cmd.class}' already exists!"
|
37
|
-
end
|
38
|
-
|
39
|
-
@commands << cmd
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
def self.use(command, arguments, console)
|
44
|
-
found_command = @commands.detect { |cmd| cmd.command == command.to_sym }
|
45
|
-
|
46
|
-
if found_command
|
47
|
-
found_command.handle(arguments, console)
|
48
|
-
else
|
49
|
-
console.stdin("Command #{Style.error(command)} not found.")
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
def self.find(command)
|
54
|
-
@commands.detect { |cmd| cmd.command == command.to_sym }
|
55
|
-
end
|
56
|
-
|
57
|
-
def self.list_commands
|
58
|
-
@commands
|
59
|
-
end
|
60
|
-
|
61
|
-
def initialize
|
62
|
-
@store = {}
|
63
|
-
@subcommands = []
|
64
|
-
|
65
|
-
setup
|
66
|
-
end
|
67
|
-
|
68
|
-
def setup
|
69
|
-
end
|
70
|
-
|
71
|
-
def subcommand(command, type)
|
72
|
-
if @subcommands.detect { |subcmd| subcmd.command == command.to_sym }
|
73
|
-
raise "Subcommand '#{command}' for '#{self.command}' already exists!"
|
74
|
-
end
|
75
|
-
|
76
|
-
@subcommands << SubCommand.new(self, command, type)
|
77
|
-
end
|
78
|
-
|
79
|
-
def get(key)
|
80
|
-
@store[key]
|
81
|
-
end
|
82
|
-
|
83
|
-
def set(key, value)
|
84
|
-
@store[key] = value
|
85
|
-
end
|
86
|
-
|
87
|
-
def group
|
88
|
-
raise NotImplementedError
|
89
|
-
end
|
90
|
-
|
91
|
-
def command
|
92
|
-
raise NotImplementedError
|
93
|
-
end
|
94
|
-
|
95
|
-
def handle(arguments, console)
|
96
|
-
raise NotImplementedError
|
97
|
-
end
|
98
|
-
|
99
|
-
def autocomplete(console)
|
100
|
-
split = console.text_input.text.split(" ")
|
101
|
-
|
102
|
-
if @subcommands.size.positive?
|
103
|
-
if !console.text_input.text.end_with?(" ") && split.size == 2
|
104
|
-
list = console.abbrev_search(@subcommands.map { |cmd| cmd.command.to_s }, split.last)
|
105
|
-
|
106
|
-
if list.size == 1
|
107
|
-
console.text_input.text = "#{split.first} #{list.first} "
|
108
|
-
else
|
109
|
-
return unless list.size.positive?
|
110
|
-
|
111
|
-
console.stdin(list.map { |cmd| Console::Style.highlight(cmd) }.join(", ").to_s)
|
112
|
-
end
|
113
|
-
|
114
|
-
# List available options on subcommand
|
115
|
-
elsif (console.text_input.text.end_with?(" ") && split.size == 2) || !console.text_input.text.end_with?(" ") && split.size == 3
|
116
|
-
subcommand = @subcommands.detect { |cmd| cmd.command.to_s == (split[1]) }
|
117
|
-
|
118
|
-
if subcommand
|
119
|
-
if split.size == 2
|
120
|
-
console.stdin("Available options: #{subcommand.values.map { |value| Console::Style.highlight(value) }.join(',')}")
|
121
|
-
else
|
122
|
-
list = console.abbrev_search(subcommand.values, split.last)
|
123
|
-
if list.size == 1
|
124
|
-
console.text_input.text = "#{split.first} #{split[1]} #{list.first} "
|
125
|
-
elsif list.size.positive?
|
126
|
-
console.stdin("Available options: #{list.map { |value| Console::Style.highlight(value) }.join(',')}")
|
127
|
-
end
|
128
|
-
end
|
129
|
-
end
|
130
|
-
|
131
|
-
# List available subcommands if command was entered and has only a space after it
|
132
|
-
elsif console.text_input.text.end_with?(" ") && split.size == 1
|
133
|
-
console.stdin("Available subcommands: #{@subcommands.map { |cmd| Console::Style.highlight(cmd.command) }.join(', ')}")
|
134
|
-
end
|
135
|
-
end
|
136
|
-
end
|
137
|
-
|
138
|
-
def handle_subcommand(arguments, console)
|
139
|
-
if arguments.size.zero?
|
140
|
-
console.stdin(usage)
|
141
|
-
return
|
142
|
-
end
|
143
|
-
subcommand = arguments.delete_at(0)
|
144
|
-
|
145
|
-
found_command = @subcommands.detect { |cmd| cmd.command == subcommand.to_sym }
|
146
|
-
if found_command
|
147
|
-
found_command.handle(arguments, console)
|
148
|
-
else
|
149
|
-
console.stdin("Unknown subcommand #{Style.error(subcommand)} for #{Style.highlight(command)}")
|
150
|
-
end
|
151
|
-
end
|
152
|
-
|
153
|
-
def usage
|
154
|
-
raise NotImplementedError
|
155
|
-
end
|
156
|
-
end
|
157
|
-
end
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CyberarmEngine
|
4
|
+
class Console
|
5
|
+
module Style
|
6
|
+
def self.error(string)
|
7
|
+
"<c=ff5555>#{string}</c>"
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.warn(string)
|
11
|
+
"<c=ff7700>#{string}</c>"
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.notice(string)
|
15
|
+
"<c=55ff55>#{string}</c>"
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.highlight(string, color = "5555ff")
|
19
|
+
"<c=#{color}>#{string}</c>"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class Command
|
24
|
+
def self.inherited(subclass)
|
25
|
+
@list ||= []
|
26
|
+
@commands ||= []
|
27
|
+
@list << subclass
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.setup
|
31
|
+
@list ||= []
|
32
|
+
@commands = []
|
33
|
+
@list.each do |subclass|
|
34
|
+
cmd = subclass.new
|
35
|
+
if @commands.detect { |c| c.command == cmd.command }
|
36
|
+
raise "Command '#{cmd.command}' from '#{cmd.class}' already exists!"
|
37
|
+
end
|
38
|
+
|
39
|
+
@commands << cmd
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.use(command, arguments, console)
|
44
|
+
found_command = @commands.detect { |cmd| cmd.command == command.to_sym }
|
45
|
+
|
46
|
+
if found_command
|
47
|
+
found_command.handle(arguments, console)
|
48
|
+
else
|
49
|
+
console.stdin("Command #{Style.error(command)} not found.")
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.find(command)
|
54
|
+
@commands.detect { |cmd| cmd.command == command.to_sym }
|
55
|
+
end
|
56
|
+
|
57
|
+
def self.list_commands
|
58
|
+
@commands
|
59
|
+
end
|
60
|
+
|
61
|
+
def initialize
|
62
|
+
@store = {}
|
63
|
+
@subcommands = []
|
64
|
+
|
65
|
+
setup
|
66
|
+
end
|
67
|
+
|
68
|
+
def setup
|
69
|
+
end
|
70
|
+
|
71
|
+
def subcommand(command, type)
|
72
|
+
if @subcommands.detect { |subcmd| subcmd.command == command.to_sym }
|
73
|
+
raise "Subcommand '#{command}' for '#{self.command}' already exists!"
|
74
|
+
end
|
75
|
+
|
76
|
+
@subcommands << SubCommand.new(self, command, type)
|
77
|
+
end
|
78
|
+
|
79
|
+
def get(key)
|
80
|
+
@store[key]
|
81
|
+
end
|
82
|
+
|
83
|
+
def set(key, value)
|
84
|
+
@store[key] = value
|
85
|
+
end
|
86
|
+
|
87
|
+
def group
|
88
|
+
raise NotImplementedError
|
89
|
+
end
|
90
|
+
|
91
|
+
def command
|
92
|
+
raise NotImplementedError
|
93
|
+
end
|
94
|
+
|
95
|
+
def handle(arguments, console)
|
96
|
+
raise NotImplementedError
|
97
|
+
end
|
98
|
+
|
99
|
+
def autocomplete(console)
|
100
|
+
split = console.text_input.text.split(" ")
|
101
|
+
|
102
|
+
if @subcommands.size.positive?
|
103
|
+
if !console.text_input.text.end_with?(" ") && split.size == 2
|
104
|
+
list = console.abbrev_search(@subcommands.map { |cmd| cmd.command.to_s }, split.last)
|
105
|
+
|
106
|
+
if list.size == 1
|
107
|
+
console.text_input.text = "#{split.first} #{list.first} "
|
108
|
+
else
|
109
|
+
return unless list.size.positive?
|
110
|
+
|
111
|
+
console.stdin(list.map { |cmd| Console::Style.highlight(cmd) }.join(", ").to_s)
|
112
|
+
end
|
113
|
+
|
114
|
+
# List available options on subcommand
|
115
|
+
elsif (console.text_input.text.end_with?(" ") && split.size == 2) || !console.text_input.text.end_with?(" ") && split.size == 3
|
116
|
+
subcommand = @subcommands.detect { |cmd| cmd.command.to_s == (split[1]) }
|
117
|
+
|
118
|
+
if subcommand
|
119
|
+
if split.size == 2
|
120
|
+
console.stdin("Available options: #{subcommand.values.map { |value| Console::Style.highlight(value) }.join(',')}")
|
121
|
+
else
|
122
|
+
list = console.abbrev_search(subcommand.values, split.last)
|
123
|
+
if list.size == 1
|
124
|
+
console.text_input.text = "#{split.first} #{split[1]} #{list.first} "
|
125
|
+
elsif list.size.positive?
|
126
|
+
console.stdin("Available options: #{list.map { |value| Console::Style.highlight(value) }.join(',')}")
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
# List available subcommands if command was entered and has only a space after it
|
132
|
+
elsif console.text_input.text.end_with?(" ") && split.size == 1
|
133
|
+
console.stdin("Available subcommands: #{@subcommands.map { |cmd| Console::Style.highlight(cmd.command) }.join(', ')}")
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
def handle_subcommand(arguments, console)
|
139
|
+
if arguments.size.zero?
|
140
|
+
console.stdin(usage)
|
141
|
+
return
|
142
|
+
end
|
143
|
+
subcommand = arguments.delete_at(0)
|
144
|
+
|
145
|
+
found_command = @subcommands.detect { |cmd| cmd.command == subcommand.to_sym }
|
146
|
+
if found_command
|
147
|
+
found_command.handle(arguments, console)
|
148
|
+
else
|
149
|
+
console.stdin("Unknown subcommand #{Style.error(subcommand)} for #{Style.highlight(command)}")
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
def usage
|
154
|
+
raise NotImplementedError
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
158
|
end
|