procon_bypass_man 0.1.16.1 → 0.1.19.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +86 -11
  3. data/.github/workflows/release.yml +2 -2
  4. data/.rubocop.yml +2 -0
  5. data/CHANGELOG.md +18 -0
  6. data/Gemfile +1 -0
  7. data/Gemfile.lock +7 -3
  8. data/README.md +25 -17
  9. data/Steepfile +31 -17
  10. data/docs/getting_started.md +60 -0
  11. data/docs/setting/left-analogstick-cap.md +60 -0
  12. data/docs/setting/splatoon2_macro_sokuwari_bubble.md +52 -0
  13. data/docs/setting/splatoon2_recommended_setting.md +40 -0
  14. data/docs/upgrade_pbm.md +56 -0
  15. data/lib/ext/module.rb +16 -0
  16. data/lib/procon_bypass_man/buttons_setting_configuration/layer.rb +33 -7
  17. data/lib/procon_bypass_man/buttons_setting_configuration/loader.rb +4 -1
  18. data/lib/procon_bypass_man/buttons_setting_configuration/validator.rb +36 -0
  19. data/lib/procon_bypass_man/buttons_setting_configuration.rb +34 -21
  20. data/lib/procon_bypass_man/commands/bypass_command.rb +2 -2
  21. data/lib/procon_bypass_man/domains/binary/base.rb +14 -0
  22. data/lib/procon_bypass_man/domains/binary/inbound_procon_binary.rb +0 -14
  23. data/lib/procon_bypass_man/domains/binary/processing_procon_binary.rb +2 -16
  24. data/lib/procon_bypass_man/plugin/splatoon2/macro/fast_return.rb +1 -1
  25. data/lib/procon_bypass_man/plugin/splatoon2/macro/jump_to_left_key.rb +1 -1
  26. data/lib/procon_bypass_man/plugin/splatoon2/macro/jump_to_right_key.rb +1 -1
  27. data/lib/procon_bypass_man/plugin/splatoon2/macro/jump_to_up_key.rb +1 -1
  28. data/lib/procon_bypass_man/plugin/splatoon2/macro/sokuwari_for_splash_bomb.rb +22 -0
  29. data/lib/procon_bypass_man/plugin/splatoon2/version.rb +1 -1
  30. data/lib/procon_bypass_man/plugins.rb +1 -0
  31. data/lib/procon_bypass_man/procon/button.rb +1 -1
  32. data/lib/procon_bypass_man/procon/button_collection.rb +8 -0
  33. data/lib/procon_bypass_man/procon/macro.rb +89 -0
  34. data/lib/procon_bypass_man/procon/macro_builder.rb +123 -0
  35. data/lib/procon_bypass_man/procon/macro_registry.rb +9 -27
  36. data/lib/procon_bypass_man/procon/mode_registry.rb +4 -4
  37. data/lib/procon_bypass_man/procon/press_button_aware.rb +6 -5
  38. data/lib/procon_bypass_man/procon/user_operation.rb +16 -2
  39. data/lib/procon_bypass_man/procon/value_objects/analog_stick.rb +1 -1
  40. data/lib/procon_bypass_man/procon.rb +6 -4
  41. data/lib/procon_bypass_man/remote_pbm_action/restore_pbm_setting.rb +3 -3
  42. data/lib/procon_bypass_man/support/compress_array.rb +5 -0
  43. data/lib/procon_bypass_man/support/http_client.rb +4 -0
  44. data/lib/procon_bypass_man/support/on_memory_cache.rb +3 -1
  45. data/lib/procon_bypass_man/support/server_pool.rb +4 -0
  46. data/lib/procon_bypass_man/support/yaml_writer.rb +16 -0
  47. data/lib/procon_bypass_man/version.rb +1 -1
  48. data/lib/procon_bypass_man/websocket/pbm_job_client.rb +13 -2
  49. data/lib/procon_bypass_man.rb +2 -0
  50. data/procon_bypass_man.gemspec +1 -1
  51. data/project_template/app.rb +3 -2
  52. data/project_template/setting.yml +4 -11
  53. data/sig/main.rbs +213 -42
  54. data/sig/on_memory_cache.rbs +16 -0
  55. metadata +16 -5
@@ -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
@@ -1,39 +1,21 @@
1
1
  class ProconBypassMan::Procon::MacroRegistry
2
- class Macro
3
- attr_accessor :name, :steps
4
-
5
- def initialize(name: , steps: )
6
- self.name = name
7
- self.steps = steps
8
- end
9
-
10
- def next_step
11
- steps.shift
12
- end
13
-
14
- def finished?
15
- steps.empty?
16
- end
17
-
18
- def ongoing?
19
- !finished?
20
- end
21
- end
22
-
23
2
  PRESETS = {
24
3
  null: [],
25
4
  }
26
5
 
27
- def self.install_plugin(klass)
28
- if plugins[klass.name]
29
- raise "すでに登録済みです"
6
+ def self.install_plugin(klass, steps: nil)
7
+ if plugins[klass.to_s.to_sym]
8
+ raise "#{klass} macro is already registered"
30
9
  end
31
- plugins[klass.name] = klass.steps
10
+
11
+ plugins[klass.to_s.to_sym] = ->{
12
+ ProconBypassMan::Procon::MacroBuilder.new(steps || klass.steps).build
13
+ }
32
14
  end
33
15
 
34
16
  def self.load(name)
35
- steps = PRESETS[name] || plugins[name] || raise("unknown macro")
36
- Macro.new(name: name, steps: steps.dup)
17
+ steps = PRESETS[name] || plugins[name].call || raise("unknown macro")
18
+ ProconBypassMan::Procon::Macro.new(name: name, steps: steps.dup)
37
19
  end
38
20
 
39
21
  def self.reset!
@@ -23,14 +23,14 @@ class ProconBypassMan::Procon::ModeRegistry
23
23
  }
24
24
 
25
25
  def self.install_plugin(klass)
26
- if plugins[klass.name.to_sym]
27
- raise "すでに登録済みです"
26
+ if plugins[klass.to_s.to_sym]
27
+ raise "#{klass} mode is already registered"
28
28
  end
29
- plugins[klass.name.to_sym] = klass.binaries
29
+ plugins[klass.to_s.to_sym] = ->{ klass.binaries }
30
30
  end
31
31
 
32
32
  def self.load(name)
33
- b = PRESETS[name] || plugins[name] || raise("unknown mode")
33
+ b = PRESETS[name] || plugins[name]&.call || raise("#{name} is unknown mode")
34
34
  Mode.new(name: name, binaries: b.dup)
35
35
  end
36
36
 
@@ -1,14 +1,15 @@
1
1
  class ProconBypassMan::PressButtonAware
2
+ BIT_ON = '1'.freeze
3
+
2
4
  def initialize(binary)
3
5
  @binary = binary
4
6
  end
5
7
 
8
+ # @param [Symbol]
9
+ # @return [Boolean]
6
10
  def pressing_button?(button)
7
11
  button_obj = ProconBypassMan::Procon::Button.new(button)
8
- @binary[
9
- button_obj.byte_position
10
- ].unpack("H*").first.to_i(16).to_s(2).reverse[
11
- button_obj.bit_position
12
- ] == '1'
12
+ byte = @binary[button_obj.byte_position].unpack("C").first.to_s(2).reverse
13
+ byte[button_obj.bit_position] == BIT_ON
13
14
  end
14
15
  end
@@ -33,9 +33,23 @@ class ProconBypassMan::Procon::UserOperation
33
33
  binary.write_as_press_button(button)
34
34
  end
35
35
 
36
- # @param [Symbol] button
36
+ # @param [Symbol, Array<Symbol>] button
37
37
  def press_button_only(button)
38
- binary.write_as_press_button_only(button)
38
+ if button.is_a?(Array)
39
+ binary.set_no_action!
40
+ button.uniq.each do |b|
41
+ unless ProconBypassMan::Procon::MacroBuilder::RESERVED_WORD_NONE == b
42
+ binary.write_as_press_button(b)
43
+ end
44
+ end
45
+ return
46
+ end
47
+
48
+ if ProconBypassMan::Procon::MacroBuilder::RESERVED_WORD_NONE == button
49
+ binary.set_no_action!
50
+ else
51
+ binary.write_as_press_button_only(button)
52
+ end
39
53
  end
40
54
 
41
55
  # @return [void]
@@ -5,7 +5,7 @@ class ProconBypassMan::Procon::AnalogStick
5
5
  def initialize(binary: )
6
6
  @neutral_position = ProconBypassMan::ButtonsSettingConfiguration.instance.neutral_position
7
7
  bytes = binary[ProconBypassMan::Procon::ButtonCollection::LEFT_ANALOG_STICK.fetch(:byte_position)]
8
- byte6, byte7, byte8 = bytes.each_char.map { |x| x.unpack("H*").first.to_i(16).to_s(2).rjust(8, "0") }
8
+ byte6, byte7, byte8 = bytes.each_char.map { |x| x.unpack("C").first.to_s(2).rjust(8, "0") }
9
9
 
10
10
  self.bin_x = "#{byte7[4..7]}#{byte6}"
11
11
  self.bin_y = "#{byte8}#{byte7[0..3]}"
@@ -1,7 +1,9 @@
1
1
  class ProconBypassMan::Procon
2
2
  require "procon_bypass_man/procon/consts"
3
3
  require "procon_bypass_man/procon/mode_registry"
4
+ require "procon_bypass_man/procon/macro"
4
5
  require "procon_bypass_man/procon/macro_registry"
6
+ require "procon_bypass_man/procon/macro_builder"
5
7
  require "procon_bypass_man/procon/layer_changer"
6
8
  require "procon_bypass_man/procon/button_collection"
7
9
  require "procon_bypass_man/procon/user_operation"
@@ -102,12 +104,12 @@ class ProconBypassMan::Procon
102
104
  user_operation.unpress_button(button)
103
105
  end
104
106
 
105
- current_layer.left_analog_stick_caps.each do |buttons, options|
106
- if buttons.nil? || user_operation.pressing_all_buttons?(buttons)
107
- options[:force_neutral]&.each do |force_neutral_button|
107
+ current_layer.left_analog_stick_caps.each do |config|
108
+ if config[:if_pressed].nil? || user_operation.pressing_all_buttons?(config[:if_pressed])
109
+ config[:force_neutral]&.each do |force_neutral_button|
108
110
  user_operation.unpress_button(force_neutral_button)
109
111
  end
110
- user_operation.apply_left_analog_stick_cap(cap: options[:cap])
112
+ user_operation.apply_left_analog_stick_cap(cap: config[:cap])
111
113
  end
112
114
  end
113
115
 
@@ -6,9 +6,9 @@ module ProconBypassMan
6
6
  require "pbmenv"
7
7
  ProconBypassMan.logger.info "execute RestorePbmSettingAction!"
8
8
  setting = args.dig("setting") or raise(ProconBypassMan::RemotePbmAction::NeedPbmVersionError, "settingが必要です, #{args.inspect}")
9
- File.write(
10
- ProconBypassMan::ButtonsSettingConfiguration.instance.setting_path,
11
- setting.to_yaml,
9
+ ProconBypassMan::YamlWriter.write(
10
+ path: ProconBypassMan::ButtonsSettingConfiguration.instance.setting_path,
11
+ content: setting,
12
12
  )
13
13
  ProconBypassMan.hot_reload!
14
14
  end
@@ -54,3 +54,8 @@ module ProconBypassMan
54
54
  end
55
55
  end
56
56
  end
57
+
58
+
59
+ if $0 == __FILE__
60
+ ProconBypassMan::CompressArray.new([''])
61
+ end
@@ -100,3 +100,7 @@ module ProconBypassMan
100
100
  end
101
101
  end
102
102
  end
103
+
104
+ if $0 == __FILE__
105
+ ProconBypassMan::HttpClient.new(path: '/', server_pool: nil, retry_on_connection_error: false).get(response_body: '')
106
+ end
@@ -1,6 +1,8 @@
1
1
  class ProconBypassMan::OnMemoryCache
2
2
  class CacheValue
3
- attr_accessor :expired_at, :value
3
+ # @param [Time]
4
+ attr_accessor :expired_at
5
+ attr_accessor :value
4
6
 
5
7
  def initialize(expired_at: , value: )
6
8
  self.expired_at = expired_at
@@ -40,3 +40,7 @@ module ProconBypassMan
40
40
  end
41
41
  end
42
42
  end
43
+
44
+ if $0 == __FILE__
45
+ ProconBypassMan::ServerPool.new(servers: ['http://example.com'])
46
+ end
@@ -0,0 +1,16 @@
1
+ class ProconBypassMan::YamlWriter
2
+ # @return [void]
3
+ def self.write(path: , content: )
4
+ File.write(
5
+ path,
6
+ content.transform_values { |x|
7
+ case x
8
+ when String
9
+ x.gsub("\r\n", "\n")
10
+ else
11
+ x
12
+ end
13
+ }.to_yaml
14
+ )
15
+ end
16
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ProconBypassMan
4
- VERSION = "0.1.16.1"
4
+ VERSION = "0.1.19.1"
5
5
  end
@@ -32,7 +32,9 @@ module ProconBypassMan
32
32
  }
33
33
 
34
34
  client.received do |data|
35
- validate_and_run(data: data)
35
+ ProconBypassMan.logger.info(data)
36
+
37
+ dispatch(data: data, client: client)
36
38
  rescue => e
37
39
  ProconBypassMan::SendErrorCommand.execute(error: e)
38
40
  end
@@ -51,11 +53,20 @@ module ProconBypassMan
51
53
  end
52
54
  end
53
55
 
56
+ # @param [Hash] data
57
+ def self.dispatch(data: , client: )
58
+ pbm_job_hash = data.dig("message")
59
+ if pbm_job_hash['action'] == "ping"
60
+ client.perform('pong', { device_id: ProconBypassMan.device_id, message: 'hello from pbm' })
61
+ else
62
+ validate_and_run(data: data)
63
+ end
64
+ end
65
+
54
66
  # @raise [ProconBypassMan::RemotePbmActionObject::ValidationError]
55
67
  # @param [Hash] data
56
68
  # @return [Void]
57
69
  def self.validate_and_run(data: )
58
- ProconBypassMan.logger.debug { data }
59
70
  pbm_job_hash = data.dig("message")
60
71
  begin
61
72
  pbm_job_object = ProconBypassMan::RemotePbmActionObject.new(action: pbm_job_hash["action"],
@@ -7,11 +7,13 @@ require "securerandom"
7
7
  require 'em/pure_ruby'
8
8
  require "action_cable_client"
9
9
  require "ext/em_pure_ruby"
10
+ require "ext/module"
10
11
 
11
12
  require_relative "procon_bypass_man/version"
12
13
  require_relative "procon_bypass_man/remote_pbm_action"
13
14
  require_relative "procon_bypass_man/support/signal_handler"
14
15
  require_relative "procon_bypass_man/support/callbacks"
16
+ require_relative "procon_bypass_man/support/yaml_writer"
15
17
  require_relative "procon_bypass_man/support/safe_timeout"
16
18
  require_relative "procon_bypass_man/support/compress_array"
17
19
  require_relative "procon_bypass_man/support/uptime"
@@ -8,7 +8,7 @@ Gem::Specification.new do |spec|
8
8
  spec.authors = ["jiikko"]
9
9
  spec.email = ["n905i.1214@gmail.com"]
10
10
 
11
- spec.summary = "An extension for Nintendo Switch Pro Controller"
11
+ spec.summary = "A programmable converter for Nintendo Switch Pro Controller"
12
12
  spec.description = spec.summary
13
13
  spec.homepage = "https://github.com/splaplapla/procon_bypass_man"
14
14
  spec.license = "MIT"
@@ -5,14 +5,15 @@ require 'bundler/inline'
5
5
  gemfile do
6
6
  source 'https://rubygems.org'
7
7
  git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
8
- gem 'procon_bypass_man', '0.1.16.1'
8
+ gem 'procon_bypass_man', '0.1.19.1'
9
9
  end
10
10
 
11
11
  ProconBypassMan.configure do |config|
12
12
  config.root = File.expand_path(__dir__)
13
13
  config.logger = Logger.new("#{ProconBypassMan.root}/app.log", 5, 1024 * 1024 * 10)
14
14
  config.logger.level = :debug
15
- # config.api_servers = ['https://...']
15
+ # webからProconBypassManを操作できるwebサービス
16
+ # config.api_servers = ['https://pbm-cloud.herokuapp.com']
16
17
  config.enable_critical_error_logging = true
17
18
  end
18
19
 
@@ -1,35 +1,28 @@
1
1
  version: 1.0
2
2
  setting: |-
3
- fast_return = ProconBypassMan::Plugin::Splatoon2::Macro::FastReturn
4
- guruguru = ProconBypassMan::Plugin::Splatoon2::Mode::Guruguru
5
-
6
- install_macro_plugin fast_return
3
+ install_macro_plugin ProconBypassMan::Plugin::Splatoon2::Macro::FastReturn
7
4
  install_macro_plugin ProconBypassMan::Plugin::Splatoon2::Macro::JumpToUpKey
8
5
  install_macro_plugin ProconBypassMan::Plugin::Splatoon2::Macro::JumpToRightKey
9
6
  install_macro_plugin ProconBypassMan::Plugin::Splatoon2::Macro::JumpToLeftKey
10
- install_mode_plugin guruguru
7
+ install_mode_plugin ProconBypassMan::Plugin::Splatoon2::Mode::Guruguru
11
8
 
12
9
  prefix_keys_for_changing_layer [:zr, :zl, :l]
13
10
 
14
11
  layer :up, mode: :manual do
15
- # flip :zr, if_pressed: :zr, force_neutral: :zl
16
12
  flip :zr, if_pressed: :zr, force_neutral: :zl
17
13
  flip :zl, if_pressed: [:y, :b, :zl]
18
14
  flip :a, if_pressed: [:a]
19
15
  flip :down, if_pressed: :down
20
- macro fast_return.name, if_pressed: [:y, :b, :down]
16
+ macro ProconBypassMan::Plugin::Splatoon2::Macro::FastReturn, if_pressed: [:y, :b, :down]
21
17
  macro ProconBypassMan::Plugin::Splatoon2::Macro::JumpToUpKey, if_pressed: [:y, :b, :up]
22
18
  macro ProconBypassMan::Plugin::Splatoon2::Macro::JumpToRightKey, if_pressed: [:y, :b, :right]
23
19
  macro ProconBypassMan::Plugin::Splatoon2::Macro::JumpToLeftKey, if_pressed: [:y, :b, :left]
24
20
  remap :l, to: :zr
25
21
  end
26
- layer :right, mode: guruguru.name
22
+ layer :right, mode: ProconBypassMan::Plugin::Splatoon2::Mode::Guruguru
27
23
  layer :left do
28
- # flip :zr, if_pressed: :zr, force_neutral: :zl
29
24
  remap :l, to: :zr
30
25
  end
31
26
  layer :down do
32
- # flip :zl
33
- # flip :zr, if_pressed: :zr, force_neutral: :zl, flip_interval: "1F"
34
27
  remap :l, to: :zr
35
28
  end