procon_bypass_man 0.1.16.1 → 0.1.19.1

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.
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