procon_bypass_man 0.1.17 → 0.1.20
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.circleci/config.yml +85 -11
- data/.rubocop.yml +2 -0
- data/CHANGELOG.md +22 -1
- data/Gemfile.lock +4 -3
- data/README.md +19 -20
- data/docs/getting_started.md +88 -0
- data/docs/setting/splatoon2_macro_sokuwari_bubble.md +52 -0
- data/docs/setting/splatoon2_recommended_setting.md +127 -0
- data/docs/upgrade_pbm.md +56 -0
- data/lib/ext/module.rb +16 -0
- data/lib/procon_bypass_man/background/jobs/report_error_reload_config_job.rb +11 -0
- data/lib/procon_bypass_man/background/jobs/report_start_reboot_job.rb +10 -0
- data/lib/procon_bypass_man/background.rb +2 -0
- data/lib/procon_bypass_man/buttons_setting_configuration/loader.rb +24 -3
- data/lib/procon_bypass_man/buttons_setting_configuration/validator.rb +12 -2
- data/lib/procon_bypass_man/buttons_setting_configuration.rb +9 -9
- data/lib/procon_bypass_man/bypass.rb +9 -8
- data/lib/procon_bypass_man/commands/bypass_command.rb +4 -11
- data/lib/procon_bypass_man/commands/connect_device_command.rb +23 -11
- data/lib/procon_bypass_man/configuration.rb +15 -1
- data/lib/procon_bypass_man/device_connector.rb +6 -33
- data/lib/procon_bypass_man/device_procon_finder.rb +65 -0
- data/lib/procon_bypass_man/never_exit_accidentally.rb +12 -0
- data/lib/procon_bypass_man/plugin/splatoon2/macro/sokuwari_for_splash_bomb.rb +22 -0
- data/lib/procon_bypass_man/plugins.rb +1 -0
- data/lib/procon_bypass_man/procon/button.rb +1 -1
- data/lib/procon_bypass_man/procon/macro.rb +89 -0
- data/lib/procon_bypass_man/procon/macro_builder.rb +123 -0
- data/lib/procon_bypass_man/procon/macro_registry.rb +2 -23
- data/lib/procon_bypass_man/procon/user_operation.rb +16 -2
- data/lib/procon_bypass_man/procon.rb +2 -0
- data/lib/procon_bypass_man/remote_pbm_action/reboot_os_action.rb +1 -0
- data/lib/procon_bypass_man/remote_pbm_action/restore_pbm_setting.rb +9 -2
- data/lib/procon_bypass_man/runner.rb +7 -7
- data/lib/procon_bypass_man/support/yaml_writer.rb +16 -0
- data/lib/procon_bypass_man/version.rb +1 -1
- data/lib/procon_bypass_man.rb +25 -24
- data/procon_bypass_man.gemspec +1 -1
- data/project_template/app.rb +5 -2
- data/project_template/setting.yml +6 -22
- data/sig/main.rbs +5 -0
- metadata +17 -4
@@ -6,7 +6,9 @@ require "procon_bypass_man/background/job_performer"
|
|
6
6
|
require "procon_bypass_man/background/jobs/base_job"
|
7
7
|
require "procon_bypass_man/background/jobs/report_event_base_job"
|
8
8
|
require "procon_bypass_man/background/jobs/report_boot_job"
|
9
|
+
require "procon_bypass_man/background/jobs/report_start_reboot_job"
|
9
10
|
require "procon_bypass_man/background/jobs/report_reload_config_job"
|
11
|
+
require "procon_bypass_man/background/jobs/report_error_reload_config_job"
|
10
12
|
require "procon_bypass_man/background/jobs/report_load_config_job"
|
11
13
|
require "procon_bypass_man/background/jobs/report_error_job"
|
12
14
|
require "procon_bypass_man/background/jobs/report_pressed_buttons_job"
|
@@ -5,6 +5,8 @@ module ProconBypassMan
|
|
5
5
|
|
6
6
|
# @return [ProconBypassMan::ButtonsSettingConfiguration]
|
7
7
|
def self.load(setting_path: )
|
8
|
+
ProconBypassMan::ButtonsSettingConfiguration.instance.setting_path = setting_path
|
9
|
+
|
8
10
|
ProconBypassMan::ButtonsSettingConfiguration.switch_new_context(:validation) do |new_instance|
|
9
11
|
yaml = YAML.load_file(setting_path) or raise "読み込みに失敗しました"
|
10
12
|
new_instance.instance_eval(yaml["setting"])
|
@@ -12,15 +14,19 @@ module ProconBypassMan
|
|
12
14
|
if validator.valid?
|
13
15
|
next
|
14
16
|
else
|
15
|
-
raise ProconBypassMan::CouldNotLoadConfigError, validator.
|
17
|
+
raise ProconBypassMan::CouldNotLoadConfigError, validator.errors_to_s
|
16
18
|
end
|
17
19
|
rescue SyntaxError
|
18
|
-
|
20
|
+
fallback_setting_if_has_backup(current_setting_path: setting_path)
|
21
|
+
raise ProconBypassMan::CouldNotLoadConfigError, "Rubyスクリプトのシンタックスエラーです"
|
22
|
+
rescue NoMethodError
|
23
|
+
fallback_setting_if_has_backup(current_setting_path: setting_path)
|
24
|
+
raise ProconBypassMan::CouldNotLoadConfigError, "Rubyスクリプトに未定義の定数・変数があります"
|
19
25
|
rescue Psych::SyntaxError
|
26
|
+
fallback_setting_if_has_backup(current_setting_path: setting_path)
|
20
27
|
raise ProconBypassMan::CouldNotLoadConfigError, "yamlのシンタックスエラーです"
|
21
28
|
end
|
22
29
|
|
23
|
-
ProconBypassMan::ButtonsSettingConfiguration.instance.setting_path = setting_path
|
24
30
|
ProconBypassMan::ButtonsSettingConfiguration.instance.reset!
|
25
31
|
ProconBypassMan.reset!
|
26
32
|
|
@@ -36,12 +42,27 @@ module ProconBypassMan
|
|
36
42
|
|
37
43
|
File.write(ProconBypassMan.digest_path, Digest::MD5.hexdigest(yaml["setting"]))
|
38
44
|
|
45
|
+
if File.exist?(ProconBypassMan.fallback_setting_path)
|
46
|
+
FileUtils.rm_rf(ProconBypassMan.fallback_setting_path)
|
47
|
+
end
|
48
|
+
|
39
49
|
ProconBypassMan::ButtonsSettingConfiguration.instance
|
40
50
|
end
|
41
51
|
|
42
52
|
def self.reload_setting
|
43
53
|
self.load(setting_path: ProconBypassMan::ButtonsSettingConfiguration.instance.setting_path)
|
44
54
|
end
|
55
|
+
|
56
|
+
def self.fallback_setting_if_has_backup(current_setting_path: )
|
57
|
+
return unless File.exist?(ProconBypassMan.fallback_setting_path)
|
58
|
+
return if current_setting_path.nil?
|
59
|
+
|
60
|
+
FileUtils.copy(
|
61
|
+
ProconBypassMan.fallback_setting_path,
|
62
|
+
current_setting_path,
|
63
|
+
)
|
64
|
+
FileUtils.rm_rf(ProconBypassMan.fallback_setting_path)
|
65
|
+
end
|
45
66
|
end
|
46
67
|
end
|
47
68
|
end
|
@@ -32,6 +32,16 @@ module ProconBypassMan
|
|
32
32
|
@errors ||= Hash.new {|h,k| h[k] = [] }
|
33
33
|
end
|
34
34
|
|
35
|
+
# @return [Array<String>]
|
36
|
+
def errors_to_s
|
37
|
+
errors.map { |_x, message|
|
38
|
+
value = <<~EOH
|
39
|
+
#{message.map { |m| "layer #{m}" }.join("\n")}
|
40
|
+
EOH
|
41
|
+
value.chomp
|
42
|
+
}.join("\n")
|
43
|
+
end
|
44
|
+
|
35
45
|
private
|
36
46
|
|
37
47
|
def validate_config_of_button_lonely
|
@@ -100,7 +110,7 @@ module ProconBypassMan
|
|
100
110
|
end
|
101
111
|
|
102
112
|
if(const = Module.const_get(key.to_s))
|
103
|
-
if not const.respond_to?(:binaries) && mode.call
|
113
|
+
if not (const.respond_to?(:binaries) && mode.call)
|
104
114
|
@errors[:mode] << "モード #{key}を読み込めませんでした。"
|
105
115
|
end
|
106
116
|
end
|
@@ -116,7 +126,7 @@ module ProconBypassMan
|
|
116
126
|
end
|
117
127
|
|
118
128
|
if(const = Module.const_get(key.to_s))
|
119
|
-
if not const.respond_to?(:steps) && macro.call
|
129
|
+
if not (const.respond_to?(:steps) && macro.call)
|
120
130
|
@errors[:macro] << "マクロ #{key}を読み込めませんでした。"
|
121
131
|
end
|
122
132
|
end
|
@@ -10,8 +10,6 @@ module ProconBypassMan
|
|
10
10
|
:setting_path,
|
11
11
|
:mode_plugins,
|
12
12
|
:macro_plugins,
|
13
|
-
:context,
|
14
|
-
:current_context_key,
|
15
13
|
:neutral_position
|
16
14
|
|
17
15
|
def self.instance
|
@@ -27,22 +25,22 @@ module ProconBypassMan
|
|
27
25
|
@@context[current_context_key] = val
|
28
26
|
end
|
29
27
|
|
30
|
-
def self.switch_new_context(
|
31
|
-
@@context[
|
28
|
+
def self.switch_new_context(new_context_key)
|
29
|
+
@@context[new_context_key] = new
|
32
30
|
previous_key = current_context_key
|
33
31
|
if block_given?
|
34
|
-
@@current_context_key =
|
35
|
-
value = yield(@@context[
|
36
|
-
@@current_context_key = previous_key
|
32
|
+
@@current_context_key = new_context_key
|
33
|
+
value = yield(@@context[new_context_key])
|
37
34
|
return value
|
38
35
|
else
|
39
|
-
@@current_context_key =
|
36
|
+
@@current_context_key = new_context_key
|
40
37
|
end
|
38
|
+
ensure
|
39
|
+
@@current_context_key = previous_key
|
41
40
|
end
|
42
41
|
|
43
42
|
def initialize
|
44
43
|
reset!
|
45
|
-
self.class.instance = self
|
46
44
|
end
|
47
45
|
|
48
46
|
module ManualMode
|
@@ -103,6 +101,8 @@ module ProconBypassMan
|
|
103
101
|
def reset!
|
104
102
|
@prefix_keys_for_changing_layer = []
|
105
103
|
self.mode_plugins = {}
|
104
|
+
# プロセスを一度起動するとsetting_pathは変わらない、という想定なので適当に扱う. resetでは初期化しない
|
105
|
+
# self.setting_path = nil
|
106
106
|
self.macro_plugins = {}
|
107
107
|
self.layers = {
|
108
108
|
up: Layer.new,
|
@@ -5,6 +5,7 @@ class ProconBypassMan::Bypass
|
|
5
5
|
|
6
6
|
class BypassValue < Struct.new(:binary, :sent)
|
7
7
|
def to_text
|
8
|
+
return unless binary
|
8
9
|
"#{binary.unpack.first} #{'x' unless sent}"
|
9
10
|
end
|
10
11
|
end
|
@@ -31,16 +32,16 @@ class ProconBypassMan::Bypass
|
|
31
32
|
self.bypass_value.binary = ProconBypassMan::Domains::InboundProconBinary.new(binary: input)
|
32
33
|
rescue IO::EAGAINWaitReadable
|
33
34
|
monitor.record(:eagain_wait_readable_on_read)
|
34
|
-
sleep(0.001)
|
35
|
-
retry
|
36
35
|
end
|
37
36
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
37
|
+
if input
|
38
|
+
begin
|
39
|
+
self.procon.write_nonblock(input)
|
40
|
+
self.bypass_value.sent = true
|
41
|
+
rescue IO::EAGAINWaitReadable
|
42
|
+
monitor.record(:eagain_wait_readable_on_write)
|
43
|
+
break
|
44
|
+
end
|
44
45
|
end
|
45
46
|
end
|
46
47
|
|
@@ -28,19 +28,12 @@ class ProconBypassMan::BypassCommand
|
|
28
28
|
monitor2 = ProconBypassMan::IOMonitor.new(label: "procon -> switch")
|
29
29
|
ProconBypassMan.logger.info "Thread1を起動します"
|
30
30
|
t1 = Thread.new do
|
31
|
-
timer = ProconBypassMan::SafeTimeout.new(timeout: Time.now + 10)
|
32
31
|
bypass = ProconBypassMan::Bypass.new(gadget: @gadget, procon: @procon, monitor: monitor1)
|
33
32
|
loop do
|
34
33
|
break if $will_terminate_token
|
35
|
-
timer.throw_if_timeout!
|
36
34
|
bypass.send_gadget_to_procon!
|
37
|
-
sleep(0.
|
38
|
-
rescue
|
39
|
-
ProconBypassMan.logger.info "10秒経過したのでThread1を終了します"
|
40
|
-
monitor1.shutdown
|
41
|
-
puts "10秒経過したのでThread1を終了します"
|
42
|
-
break
|
43
|
-
rescue Errno::EIO, Errno::ENODEV, Errno::EPROTO, IOError => e
|
35
|
+
sleep(0.02)
|
36
|
+
rescue Errno::EIO, Errno::ENODEV, Errno::EPROTO, IOError, Errno::ESHUTDOWN => e
|
44
37
|
ProconBypassMan::SendErrorCommand.execute(error: "Switchとの切断されました.終了処理を開始します. #{e.full_message}")
|
45
38
|
Process.kill "TERM", Process.ppid
|
46
39
|
rescue Errno::ETIMEDOUT => e
|
@@ -62,7 +55,7 @@ class ProconBypassMan::BypassCommand
|
|
62
55
|
rescue EOFError => e
|
63
56
|
ProconBypassMan::SendErrorCommand.execute(error: "Proconが切断されました。終了処理を開始します. #{e.full_message}")
|
64
57
|
Process.kill "TERM", Process.ppid
|
65
|
-
rescue Errno::EIO, Errno::ENODEV, Errno::EPROTO, IOError => e
|
58
|
+
rescue Errno::EIO, Errno::ENODEV, Errno::EPROTO, IOError, Errno::ESHUTDOWN => e
|
66
59
|
ProconBypassMan::SendErrorCommand.execute(error: "Proconが切断されました。終了処理を開始します2. #{e.full_message}")
|
67
60
|
Process.kill "TERM", Process.ppid
|
68
61
|
end
|
@@ -80,7 +73,7 @@ class ProconBypassMan::BypassCommand
|
|
80
73
|
[t1, t2].each(&:join)
|
81
74
|
@gadget&.close
|
82
75
|
@procon&.close
|
83
|
-
exit 1
|
76
|
+
exit 1 # child processなのでexitしていい
|
84
77
|
end
|
85
78
|
end
|
86
79
|
end
|
@@ -1,16 +1,28 @@
|
|
1
1
|
class ProconBypassMan::ConnectDeviceCommand
|
2
|
+
class NotFoundProconError < StandardError; end
|
3
|
+
|
2
4
|
# @return [void]
|
3
5
|
def self.execute!
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
6
|
+
unless has_required_files?
|
7
|
+
raise ProconBypassMan::NotFoundRequiredFilesError, "there is not /sys/kernel/config/usb_gadget/procon"
|
8
|
+
end
|
9
|
+
|
10
|
+
begin
|
11
|
+
gadget, procon = ProconBypassMan::DeviceConnector.connect
|
12
|
+
rescue ProconBypassMan::DeviceConnector::NotFoundProconError => e
|
13
|
+
ProconBypassMan.logger.error e
|
14
|
+
gadget&.close
|
15
|
+
procon&.close
|
16
|
+
raise ProconBypassMan::ConnectDeviceCommand::NotFoundProconError
|
17
|
+
rescue ProconBypassMan::SafeTimeout::Timeout
|
18
|
+
ProconBypassMan.logger.error "デバイスとの通信でタイムアウトが起きて接続ができませんでした。"
|
19
|
+
gadget&.close
|
20
|
+
procon&.close
|
21
|
+
raise ProconBypassMan::EternalConnectionError
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.has_required_files?
|
26
|
+
Dir.exist?("/sys/kernel/config/usb_gadget/procon")
|
15
27
|
end
|
16
28
|
end
|
@@ -38,10 +38,19 @@ class ProconBypassMan::Configuration
|
|
38
38
|
def device_id
|
39
39
|
ENV["DEBUG_DEVICE_ID"] || ProconBypassMan::WriteDeviceIdCommand.execute
|
40
40
|
end
|
41
|
+
|
42
|
+
# @return [Boolean]
|
43
|
+
def never_exit_accidentally
|
44
|
+
config.never_exit_accidentally
|
45
|
+
end
|
46
|
+
|
47
|
+
def fallback_setting_path
|
48
|
+
"/tmp/procon_bypass_man_fallback_setting.yaml"
|
49
|
+
end
|
41
50
|
end
|
42
51
|
|
43
52
|
attr_accessor :enable_critical_error_logging
|
44
|
-
attr_writer :verbose_bypass_log, :raw_setting, :enable_reporting_pressed_buttons
|
53
|
+
attr_writer :verbose_bypass_log, :raw_setting, :enable_reporting_pressed_buttons, :never_exit_accidentally
|
45
54
|
|
46
55
|
def root=(path)
|
47
56
|
@root = path
|
@@ -158,4 +167,9 @@ class ProconBypassMan::Configuration
|
|
158
167
|
def enable_reporting_pressed_buttons
|
159
168
|
@enable_reporting_pressed_buttons ||= false
|
160
169
|
end
|
170
|
+
|
171
|
+
# @return [Boolean]
|
172
|
+
def never_exit_accidentally
|
173
|
+
@never_exit_accidentally || false
|
174
|
+
end
|
161
175
|
end
|
@@ -263,46 +263,19 @@ class ProconBypassMan::DeviceConnector
|
|
263
263
|
@procon
|
264
264
|
end
|
265
265
|
|
266
|
-
def is_available_device?(path)
|
267
|
-
return false if !File.exist?(path)
|
268
|
-
|
269
|
-
system('echo > /sys/kernel/config/usb_gadget/procon/UDC')
|
270
|
-
system('ls /sys/class/udc > /sys/kernel/config/usb_gadget/procon/UDC')
|
271
|
-
sleep 0.5
|
272
|
-
|
273
|
-
file = File.open(path, "w+")
|
274
|
-
begin
|
275
|
-
file.read_nonblock(64)
|
276
|
-
rescue EOFError
|
277
|
-
file.close
|
278
|
-
return false
|
279
|
-
rescue IO::EAGAINWaitReadable
|
280
|
-
file.close
|
281
|
-
return true
|
282
|
-
end
|
283
|
-
end
|
284
|
-
|
285
|
-
def to_bin(string)
|
286
|
-
string.unpack "H*"
|
287
|
-
end
|
288
|
-
|
289
266
|
def init_devices
|
290
267
|
if @initialized_devices
|
291
268
|
return
|
292
269
|
end
|
293
270
|
|
294
|
-
|
295
|
-
|
296
|
-
ProconBypassMan.logger.info "proconのデバイスファイルは#{
|
297
|
-
@procon = File.open(PROCON_PATH, "w+b")
|
298
|
-
@gadget = File.open('/dev/hidg0', "w+b")
|
299
|
-
when is_available_device?(PROCON2_PATH)
|
300
|
-
ProconBypassMan.logger.info "proconのデバイスファイルは#{PROCON2_PATH}を使います"
|
301
|
-
@procon = File.open(PROCON2_PATH, "w+b")
|
302
|
-
@gadget = File.open('/dev/hidg0', "w+b")
|
271
|
+
if path = ProconBypassMan::DeviceProconFinder.find
|
272
|
+
@procon = File.open(path, "w+b")
|
273
|
+
ProconBypassMan.logger.info "proconのデバイスファイルは#{path}を使います"
|
303
274
|
else
|
304
|
-
raise
|
275
|
+
raise(ProconBypassMan::DeviceConnector::NotFoundProconError)
|
305
276
|
end
|
277
|
+
@gadget = File.open('/dev/hidg0', "w+b")
|
278
|
+
|
306
279
|
system('echo > /sys/kernel/config/usb_gadget/procon/UDC')
|
307
280
|
system('ls /sys/class/udc > /sys/kernel/config/usb_gadget/procon/UDC')
|
308
281
|
sleep 0.5
|
@@ -0,0 +1,65 @@
|
|
1
|
+
class ProconBypassMan::DeviceProconFinder
|
2
|
+
HID_NAME = "Nintendo Co., Ltd. Pro Controller"
|
3
|
+
|
4
|
+
def self.find
|
5
|
+
new.find
|
6
|
+
end
|
7
|
+
|
8
|
+
# @return [String, NilClass]
|
9
|
+
def find
|
10
|
+
find_device_path
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
# @return [String , NilClass]
|
16
|
+
def find_device_path
|
17
|
+
if(line = device_from_shell) && (hidraw_name = line.match(/(hidraw\d+)\s+/)[1])
|
18
|
+
"/dev/#{hidraw_name}"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# @return [String , NilClass]
|
23
|
+
def device_from_shell
|
24
|
+
shell_output.split("\n").detect { |o| o.include?(HID_NAME) }
|
25
|
+
end
|
26
|
+
|
27
|
+
# @return [String]
|
28
|
+
def shell_output
|
29
|
+
`bash -c '#{get_list_shell}'`
|
30
|
+
end
|
31
|
+
|
32
|
+
def get_list_shell
|
33
|
+
<<~SHELL
|
34
|
+
#!/bin/bash
|
35
|
+
|
36
|
+
FILES=/dev/hidraw*
|
37
|
+
for f in $FILES
|
38
|
+
do
|
39
|
+
FILE=${f##*/}
|
40
|
+
DEVICE="$(cat /sys/class/hidraw/${FILE}/device/uevent | grep HID_NAME | cut -d '=' -f2)"
|
41
|
+
printf "%s %s\n" $FILE "$DEVICE"
|
42
|
+
done
|
43
|
+
SHELL
|
44
|
+
end
|
45
|
+
|
46
|
+
# これいる?
|
47
|
+
def is_available_device?(path)
|
48
|
+
return false if !File.exist?(path)
|
49
|
+
|
50
|
+
system('echo > /sys/kernel/config/usb_gadget/procon/UDC')
|
51
|
+
system('ls /sys/class/udc > /sys/kernel/config/usb_gadget/procon/UDC')
|
52
|
+
sleep 0.5
|
53
|
+
|
54
|
+
file = File.open(path, "w+")
|
55
|
+
begin
|
56
|
+
file.read_nonblock(64)
|
57
|
+
rescue EOFError
|
58
|
+
file.close
|
59
|
+
return false
|
60
|
+
rescue IO::EAGAINWaitReadable
|
61
|
+
file.close
|
62
|
+
return true
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module ProconBypassMan
|
2
|
+
module Plugin
|
3
|
+
module Splatoon2
|
4
|
+
module Macro
|
5
|
+
module SokuwariForSplashBomb
|
6
|
+
def self.display_name
|
7
|
+
:sokuwari_for_splash_bomb
|
8
|
+
end
|
9
|
+
|
10
|
+
# procon_bypass_man: 0.1.18以上が必要
|
11
|
+
def self.steps
|
12
|
+
[ :toggle_r_for_0_2sec,
|
13
|
+
:toggle_thumbr_for_0_14sec,
|
14
|
+
:toggle_thumbr_and_toggle_zr_for_0_34sec,
|
15
|
+
:toggle_r_for_1sec,
|
16
|
+
].freeze
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -3,6 +3,7 @@ require_relative "plugin/splatoon2/macro/fast_return"
|
|
3
3
|
require_relative "plugin/splatoon2/macro/jump_to_right_key"
|
4
4
|
require_relative "plugin/splatoon2/macro/jump_to_up_key"
|
5
5
|
require_relative "plugin/splatoon2/macro/jump_to_left_key"
|
6
|
+
require_relative "plugin/splatoon2/macro/sokuwari_for_splash_bomb"
|
6
7
|
require_relative "plugin/splatoon2/mode/guruguru"
|
7
8
|
|
8
9
|
module ProconBypassMan
|
@@ -4,7 +4,7 @@ class ProconBypassMan::Procon::Button
|
|
4
4
|
attr_accessor :byte_position, :bit_position
|
5
5
|
|
6
6
|
def initialize(key)
|
7
|
-
b = ProconBypassMan::Procon::ButtonCollection::BUTTONS_MAP[key] or raise(UnknownButtonFoundError,
|
7
|
+
b = ProconBypassMan::Procon::ButtonCollection::BUTTONS_MAP[key] or raise(UnknownButtonFoundError, "#{key}は定義にないボタンです")
|
8
8
|
self.byte_position = b[:byte_position]
|
9
9
|
self.bit_position = b[:bit_position]
|
10
10
|
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
class ProconBypassMan::Procon::Macro
|
2
|
+
class NestedStep
|
3
|
+
def initialize(value)
|
4
|
+
@hash = value
|
5
|
+
unless @hash[:end_at]
|
6
|
+
@hash[:end_at] = (Time.now + @hash[:continue_for]).round(4)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def over_end_at?
|
11
|
+
(@hash[:end_at] < Time.now).tap do |result|
|
12
|
+
if result
|
13
|
+
ProconBypassMan.logger.debug { "[Macro] nested step is finished(#{@hash})" }
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def next_step
|
19
|
+
incr_step_index!
|
20
|
+
|
21
|
+
debug_incr_called_count!
|
22
|
+
if step = current_step
|
23
|
+
return step
|
24
|
+
else
|
25
|
+
reset_step_index!
|
26
|
+
return current_step
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def current_step
|
33
|
+
@hash[:steps][step_index]
|
34
|
+
end
|
35
|
+
|
36
|
+
def step_index
|
37
|
+
@hash[:step_index]
|
38
|
+
end
|
39
|
+
|
40
|
+
def incr_step_index!
|
41
|
+
if step_index
|
42
|
+
@hash[:step_index] += 1
|
43
|
+
else
|
44
|
+
@hash[:step_index] = 0
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def reset_step_index!
|
49
|
+
@hash[:step_index] = 0
|
50
|
+
end
|
51
|
+
|
52
|
+
def debug_incr_called_count!
|
53
|
+
@hash[:debug_called_count] ||= 0
|
54
|
+
@hash[:debug_called_count] += 1
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
attr_accessor :name, :steps
|
59
|
+
|
60
|
+
def initialize(name: , steps: )
|
61
|
+
self.name = name
|
62
|
+
self.steps = steps
|
63
|
+
end
|
64
|
+
|
65
|
+
def next_step
|
66
|
+
step = steps.first
|
67
|
+
if step.is_a?(Symbol)
|
68
|
+
return steps.shift
|
69
|
+
end
|
70
|
+
|
71
|
+
if step.is_a?(Hash)
|
72
|
+
nested_step = NestedStep.new(step)
|
73
|
+
if nested_step.over_end_at?
|
74
|
+
steps.shift # NestedStepを破棄する
|
75
|
+
return next_step
|
76
|
+
else
|
77
|
+
return nested_step.next_step
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def finished?
|
83
|
+
steps.empty?
|
84
|
+
end
|
85
|
+
|
86
|
+
def ongoing?
|
87
|
+
!finished?
|
88
|
+
end
|
89
|
+
end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
class ProconBypassMan::Procon::MacroBuilder
|
2
|
+
class SubjectMerger
|
3
|
+
def self.merge(subjects)
|
4
|
+
if subjects.size == 1
|
5
|
+
return subjects.first.to_steps
|
6
|
+
end
|
7
|
+
|
8
|
+
base = subjects.first
|
9
|
+
remain = subjects[1..-1]
|
10
|
+
remain.map { |x| base.to_steps.zip(x.to_steps) }.first
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class Subject
|
15
|
+
def initialize(value)
|
16
|
+
@button =
|
17
|
+
if match = value.match(/_(\w+)\z/)
|
18
|
+
match[1]
|
19
|
+
else
|
20
|
+
:unknown
|
21
|
+
end
|
22
|
+
@type =
|
23
|
+
if value.start_with?("toggle_")
|
24
|
+
:toggle
|
25
|
+
else
|
26
|
+
:pressing
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def toggle?
|
31
|
+
@type == :toggle
|
32
|
+
end
|
33
|
+
|
34
|
+
def pressing?
|
35
|
+
not toggle?
|
36
|
+
end
|
37
|
+
|
38
|
+
def to_steps
|
39
|
+
case @type
|
40
|
+
when :toggle
|
41
|
+
[@button.to_sym, :none]
|
42
|
+
when :pressing
|
43
|
+
[@button.to_sym, @button.to_sym]
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
RESERVED_WORD_NONE = :none
|
49
|
+
RESERVED_WORDS = {
|
50
|
+
RESERVED_WORD_NONE => true,
|
51
|
+
}
|
52
|
+
|
53
|
+
def initialize(steps)
|
54
|
+
@steps = steps.map(&:to_s)
|
55
|
+
end
|
56
|
+
|
57
|
+
# @return [Arary<Symbol>]
|
58
|
+
def build
|
59
|
+
steps = @steps.map { |step|
|
60
|
+
if is_reserved?(step: step) || v1_format?(step: step)
|
61
|
+
step.to_sym
|
62
|
+
elsif value = build_if_v2_format?(step: step)
|
63
|
+
value
|
64
|
+
else
|
65
|
+
nil
|
66
|
+
end
|
67
|
+
}
|
68
|
+
steps.compact.flatten
|
69
|
+
end
|
70
|
+
|
71
|
+
private
|
72
|
+
|
73
|
+
def is_reserved?(step: )
|
74
|
+
RESERVED_WORDS[step.to_sym]
|
75
|
+
end
|
76
|
+
|
77
|
+
def v1_format?(step: )
|
78
|
+
if is_button(step)
|
79
|
+
step
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def build_if_v2_format?(step: )
|
84
|
+
# 時間指定なし
|
85
|
+
if(match = step.match(%r!\Atoggle_(\w+)\z!)) && (button_candidate = match[1]) && is_button(button_candidate)
|
86
|
+
button = button_candidate
|
87
|
+
return [button.to_sym, :none]
|
88
|
+
end
|
89
|
+
|
90
|
+
# 時間指定あり
|
91
|
+
if %r!^(pressing_|toggle_)! =~ step && (subjects = step.scan(%r!pressing_[^_]+|toggle_[^_]+!)) && (match = step.match(%r!_for_([\d_]+)(sec)?\z!))
|
92
|
+
sec = match[1]
|
93
|
+
return [
|
94
|
+
{ continue_for: to_num(sec),
|
95
|
+
steps: SubjectMerger.merge(subjects.map { |x| Subject.new(x) }),
|
96
|
+
}
|
97
|
+
]
|
98
|
+
end
|
99
|
+
|
100
|
+
# no-op command
|
101
|
+
if(match = step.match(%r!wait_for_([\d_]+)(sec)?\z!))
|
102
|
+
sec = match[1]
|
103
|
+
return [
|
104
|
+
{ continue_for: to_num(sec),
|
105
|
+
steps: [:none],
|
106
|
+
}
|
107
|
+
]
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
# @return [Boolean]
|
112
|
+
def is_button(step)
|
113
|
+
!!ProconBypassMan::Procon::ButtonCollection::BUTTONS_MAP[step.to_sym]
|
114
|
+
end
|
115
|
+
|
116
|
+
def to_num(value)
|
117
|
+
if value.include?("_")
|
118
|
+
value.sub("_", ".").to_f
|
119
|
+
else
|
120
|
+
value.to_i
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|