procon_bypass_man-web 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.babelrc +6 -0
- data/.circleci/config.yml +73 -0
- data/.gitignore +12 -0
- data/.rspec +1 -0
- data/.rubocop.yml +26 -0
- data/CHANGELOG.md +3 -0
- data/Gemfile +18 -0
- data/Gemfile.lock +97 -0
- data/LICENSE.txt +21 -0
- data/Procfile +2 -0
- data/README.md +43 -0
- data/Rakefile +4 -0
- data/bin/console +15 -0
- data/bin/pbm_web +7 -0
- data/bin/setup +8 -0
- data/jest.config.ts +194 -0
- data/lib/procon_bypass_man/web.rb +20 -0
- data/lib/procon_bypass_man/web/db.rb +33 -0
- data/lib/procon_bypass_man/web/migration/001_create_settings_table.sql +4 -0
- data/lib/procon_bypass_man/web/models/base_model.rb +47 -0
- data/lib/procon_bypass_man/web/models/setting.rb +22 -0
- data/lib/procon_bypass_man/web/public/bundle.js +2 -0
- data/lib/procon_bypass_man/web/public/bundle.js.LICENSE.txt +57 -0
- data/lib/procon_bypass_man/web/public/index.html +1 -0
- data/lib/procon_bypass_man/web/server.rb +139 -0
- data/lib/procon_bypass_man/web/setting_parser.rb +190 -0
- data/lib/procon_bypass_man/web/storage.rb +25 -0
- data/lib/procon_bypass_man/web/version.rb +7 -0
- data/package.json +48 -0
- data/procon_bypass_man-web.gemspec +36 -0
- data/src/app.tsx +5 -0
- data/src/components/button_setting.tsx +142 -0
- data/src/components/buttons_modal.tsx +110 -0
- data/src/components/buttons_setting.tsx +67 -0
- data/src/components/installable_macros.tsx +58 -0
- data/src/components/installable_modes.tsx +57 -0
- data/src/components/macro_settings.tsx +85 -0
- data/src/components/mode_settings.tsx +62 -0
- data/src/contexts/buttons_setting.ts +2 -0
- data/src/index.html +11 -0
- data/src/lib/button_state.test.ts +110 -0
- data/src/lib/button_state.ts +52 -0
- data/src/lib/button_state_diff.test.ts +123 -0
- data/src/lib/button_state_diff.ts +63 -0
- data/src/lib/buttons_setting_converter.test.ts +185 -0
- data/src/lib/buttons_setting_converter.ts +107 -0
- data/src/lib/http_client.ts +93 -0
- data/src/pages/bpm_page.tsx +92 -0
- data/src/pages/buttons_setting_page.tsx +281 -0
- data/src/pages/global_setting_page.tsx +83 -0
- data/src/pages/home.tsx +17 -0
- data/src/pages/recoding_mode_page.tsx +15 -0
- data/src/pages/top.tsx +107 -0
- data/src/reducers/layer_reducer.ts +120 -0
- data/src/types/button.ts +2 -0
- data/src/types/buttons_setting_type.ts +63 -0
- data/src/types/layer_key.ts +2 -0
- data/src/types/pbm_stats.ts +1 -0
- data/src/types/plugin.ts +43 -0
- data/tmp/.keep +0 -0
- data/tsconfig.json +75 -0
- data/webpack.config.js +56 -0
- data/yarn.lock +6815 -0
- metadata +150 -0
@@ -0,0 +1,83 @@
|
|
1
|
+
/** @jsx jsx */
|
2
|
+
|
3
|
+
import { jsx, css } from '@emotion/react'
|
4
|
+
import React, { useState, useEffect } from "react";
|
5
|
+
import axios from 'axios';
|
6
|
+
|
7
|
+
import { HttpClient } from "../lib/http_client";
|
8
|
+
|
9
|
+
type Prop = {
|
10
|
+
};
|
11
|
+
const httpClient = new HttpClient();
|
12
|
+
|
13
|
+
export const GlobalSetting = ({}:Prop) => {
|
14
|
+
const [dirPath, setDirPath] = useState("");
|
15
|
+
const [settingPath, setSettingPath] = useState("");
|
16
|
+
const [serverResponseMessage, setServerResponseMessage] = useState("");
|
17
|
+
|
18
|
+
const inputStyle = css`
|
19
|
+
width: 400px;
|
20
|
+
`
|
21
|
+
|
22
|
+
useEffect(() => {
|
23
|
+
httpClient.getDirPath()
|
24
|
+
.then(function (response) {
|
25
|
+
setDirPath(response.data.root_path);
|
26
|
+
})
|
27
|
+
.catch(function (error) {
|
28
|
+
setServerResponseMessage("サーバとの通信に失敗しました");
|
29
|
+
console.log(error);
|
30
|
+
})
|
31
|
+
httpClient.getSettingPath()
|
32
|
+
.then(function (response) {
|
33
|
+
setSettingPath(response.data.setting_path);
|
34
|
+
})
|
35
|
+
.catch(function (error) {
|
36
|
+
console.log(error);
|
37
|
+
})
|
38
|
+
}, [])
|
39
|
+
|
40
|
+
const handleDirChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
41
|
+
setDirPath(e.target.value);
|
42
|
+
};
|
43
|
+
|
44
|
+
const handleDirSubmit = (e: React.MouseEvent<HTMLElement, MouseEvent>) => {
|
45
|
+
if (!(e.target instanceof HTMLInputElement)) {
|
46
|
+
return;
|
47
|
+
}
|
48
|
+
httpClient.postDirPath(dirPath);
|
49
|
+
setServerResponseMessage("PBMのディレクトリパスの更新に成功しました");
|
50
|
+
};
|
51
|
+
|
52
|
+
const handleSettingChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
53
|
+
setSettingPath(e.target.value);
|
54
|
+
};
|
55
|
+
|
56
|
+
const handleSettingSubmit = (e: React.MouseEvent<HTMLElement, MouseEvent>) => {
|
57
|
+
if (!(e.target instanceof HTMLInputElement)) {
|
58
|
+
return;
|
59
|
+
}
|
60
|
+
httpClient.postSettingPath(settingPath);
|
61
|
+
setServerResponseMessage("PBMの設定ファイルパスの更新に成功しました");
|
62
|
+
};
|
63
|
+
|
64
|
+
return (
|
65
|
+
<>
|
66
|
+
<h2>設定</h2>
|
67
|
+
<div>
|
68
|
+
{serverResponseMessage}
|
69
|
+
</div>
|
70
|
+
<label>PBMのディレクトリパス:
|
71
|
+
<input type="text" css={inputStyle} value={dirPath} onChange={handleDirChange} />
|
72
|
+
</label>
|
73
|
+
<input type="submit" value="更新する" onClick={handleDirSubmit} />
|
74
|
+
<hr />
|
75
|
+
|
76
|
+
<label>PBMの設定ファイルパス:
|
77
|
+
<input type="text" css={inputStyle} value={settingPath || "未設定"} onChange={handleSettingChange} />
|
78
|
+
</label>
|
79
|
+
<input type="submit" value="更新する" onClick={handleSettingSubmit} />
|
80
|
+
<hr />
|
81
|
+
</>
|
82
|
+
)
|
83
|
+
}
|
data/src/pages/home.tsx
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
/** @jsx jsx */
|
2
|
+
|
3
|
+
import { jsx, css } from '@emotion/react'
|
4
|
+
import React, { useState, useEffect } from "react";
|
5
|
+
|
6
|
+
export const Home = () => {
|
7
|
+
return (
|
8
|
+
<>
|
9
|
+
<div css={css`margin-top: 30px`}>
|
10
|
+
ソースコード: <a href="https://github.com/splaplapla/procon_bypass_man-web">
|
11
|
+
https://github.com/splaplapla/procon_bypass_man-web
|
12
|
+
</a>
|
13
|
+
</div>
|
14
|
+
</>
|
15
|
+
)
|
16
|
+
}
|
17
|
+
|
@@ -0,0 +1,15 @@
|
|
1
|
+
/** @jsx jsx */
|
2
|
+
|
3
|
+
import { jsx, css } from '@emotion/react'
|
4
|
+
import React, { useState, useEffect } from "react";
|
5
|
+
import { HttpClient } from "../lib/http_client";
|
6
|
+
|
7
|
+
const httpClient = new HttpClient();
|
8
|
+
|
9
|
+
export const RecodingModePage = () => {
|
10
|
+
return (
|
11
|
+
<>
|
12
|
+
<div></div>
|
13
|
+
</>
|
14
|
+
)
|
15
|
+
}
|
data/src/pages/top.tsx
ADDED
@@ -0,0 +1,107 @@
|
|
1
|
+
/** @jsx jsx */
|
2
|
+
|
3
|
+
import { jsx, css } from '@emotion/react'
|
4
|
+
import React, { useState, useReducer } from "react";
|
5
|
+
import {
|
6
|
+
BrowserRouter as Router,
|
7
|
+
Switch,
|
8
|
+
Route,
|
9
|
+
Link
|
10
|
+
} from "react-router-dom";
|
11
|
+
import { GlobalSetting } from "./global_setting_page";
|
12
|
+
import { BpmPage } from "./bpm_page";
|
13
|
+
import { Home } from "./home";
|
14
|
+
import { ButtonsSettingPage } from "./buttons_setting_page";
|
15
|
+
import { RecodingModePage } from "./recoding_mode_page";
|
16
|
+
import { ButtonsSettingContext } from "./../contexts/buttons_setting";
|
17
|
+
import { ButtonsInLayer, Layers, ButtonsSettingType } from "../types/buttons_setting_type";
|
18
|
+
import { buttons, Button } from "../types/button";
|
19
|
+
import { LayerReducer } from "../reducers/layer_reducer";
|
20
|
+
|
21
|
+
const ButtonsSettingProfile: React.FC = ({children}) => {
|
22
|
+
const initLayers: Layers = {
|
23
|
+
up: buttons.reduce((a, i) => { a[i] = { open: false }; return a }, {} as ButtonsInLayer),
|
24
|
+
right: buttons.reduce((a, i) => { a[i] = { open: false }; return a }, {} as ButtonsInLayer),
|
25
|
+
down: buttons.reduce((a, i) => { a[i] = { open: false }; return a }, {} as ButtonsInLayer),
|
26
|
+
left: buttons.reduce((a, i) => { a[i] = { open: false }; return a }, {} as ButtonsInLayer),
|
27
|
+
installed_macros: {},
|
28
|
+
installed_modes: {},
|
29
|
+
}
|
30
|
+
const [prefixKeys, setPrefixKeys] = useState([]);
|
31
|
+
const [loaded, setLoaded] = useState(false);
|
32
|
+
const [layers, layersDispatch] = useReducer(LayerReducer, initLayers as Layers);
|
33
|
+
const value = {
|
34
|
+
loaded,
|
35
|
+
setLoaded,
|
36
|
+
layers,
|
37
|
+
prefixKeys,
|
38
|
+
setPrefixKeys,
|
39
|
+
layersDispatch,
|
40
|
+
}
|
41
|
+
return (
|
42
|
+
<ButtonsSettingContext.Provider value={value}>
|
43
|
+
{children}
|
44
|
+
</ButtonsSettingContext.Provider>
|
45
|
+
)
|
46
|
+
}
|
47
|
+
|
48
|
+
export const Top: React.FC = () => {
|
49
|
+
const menuStyle = css`
|
50
|
+
ul {
|
51
|
+
list-style: none;
|
52
|
+
display:flex;
|
53
|
+
margin: 0;
|
54
|
+
padding: 0;
|
55
|
+
li {
|
56
|
+
padding-right: 3px;
|
57
|
+
display: block;
|
58
|
+
a {
|
59
|
+
text-decoration: none;
|
60
|
+
display:block;
|
61
|
+
padding:10px;
|
62
|
+
background-color: #333;
|
63
|
+
color: white;
|
64
|
+
}
|
65
|
+
}
|
66
|
+
}
|
67
|
+
`;
|
68
|
+
|
69
|
+
return (
|
70
|
+
<>
|
71
|
+
<Router>
|
72
|
+
<div>
|
73
|
+
<nav css={menuStyle}>
|
74
|
+
<ul>
|
75
|
+
<li>
|
76
|
+
<Link to="/">home</Link>
|
77
|
+
</li>
|
78
|
+
<li>
|
79
|
+
<Link to="/setting">設定</Link>
|
80
|
+
</li>
|
81
|
+
<li>
|
82
|
+
<Link to="/buttons_setting">ボタン設定</Link>
|
83
|
+
</li>
|
84
|
+
</ul>
|
85
|
+
</nav>
|
86
|
+
<Switch>
|
87
|
+
<Route exact path="/" >
|
88
|
+
<Home />
|
89
|
+
</Route>
|
90
|
+
<Route path="/setting">
|
91
|
+
<GlobalSetting />
|
92
|
+
</Route>
|
93
|
+
<Route path="/pbm">
|
94
|
+
<BpmPage />
|
95
|
+
</Route>
|
96
|
+
<Route path="/buttons_setting">
|
97
|
+
<ButtonsSettingProfile><ButtonsSettingPage /></ButtonsSettingProfile>
|
98
|
+
</Route>
|
99
|
+
<Route path="/recoding_mode">
|
100
|
+
<RecodingModePage />
|
101
|
+
</Route>
|
102
|
+
</Switch>
|
103
|
+
</div>
|
104
|
+
</Router>
|
105
|
+
</>
|
106
|
+
);
|
107
|
+
};
|
@@ -0,0 +1,120 @@
|
|
1
|
+
import { buttons, Button } from "../types/button";
|
2
|
+
import { LayerKey } from "../types/layer_key";
|
3
|
+
import { Layers, Flip, Remap, Macro, StructMacro, ModeTable, StructMode } from "../types/buttons_setting_type";
|
4
|
+
|
5
|
+
export const disableFlipType = Symbol('disableFlip');
|
6
|
+
export const alwaysFlipType = Symbol('alwaysFlip');
|
7
|
+
export const flipIfPressedSelfType = Symbol('flipIfPressedSelf');
|
8
|
+
export const flipIfPressedSomeButtonsType = Symbol('flipIfPressedSomeButtons');
|
9
|
+
export const ignoreButtonsInFlipingType = Symbol('ignoreButtonsInFliping');
|
10
|
+
export const remapType = Symbol('remap');
|
11
|
+
export const openMenuType = Symbol('openMenu');
|
12
|
+
export const closeMenuType = Symbol('closeMenu');
|
13
|
+
export const applyMacroType = Symbol('applyMacro');
|
14
|
+
export const installMacroType = Symbol('installedMacro');
|
15
|
+
export const uninstallMacroType = Symbol('uninstalledMacro');
|
16
|
+
export const installModeType = Symbol('uninstalledMacro');
|
17
|
+
export const uninstallModeType = Symbol('a')
|
18
|
+
export const applyModeType = Symbol('b')
|
19
|
+
|
20
|
+
|
21
|
+
type ACTION_TYPE =
|
22
|
+
| { type: typeof disableFlipType, payload: { layerKey: LayerKey, button: Button } }
|
23
|
+
| { type: typeof alwaysFlipType, payload: { layerKey: LayerKey, button: Button } }
|
24
|
+
| { type: typeof flipIfPressedSelfType, payload: { layerKey: LayerKey, button: Button } }
|
25
|
+
| { type: typeof flipIfPressedSomeButtonsType, payload: { layerKey: LayerKey, button: Button, targetButtons: Array<Button> } }
|
26
|
+
| { type: typeof ignoreButtonsInFlipingType, payload: { layerKey: LayerKey, button: Button, targetButtons: Array<Button> } }
|
27
|
+
| { type: typeof remapType, payload: { layerKey: LayerKey, button: Button, targetButtons: Array<Button> } }
|
28
|
+
| { type: typeof openMenuType, payload: { layerKey: LayerKey, button: Button } }
|
29
|
+
| { type: typeof closeMenuType, payload: { layerKey: LayerKey, button: Button } }
|
30
|
+
| { type: typeof applyMacroType, payload: { layerKey: LayerKey, button: (Button | undefined), macro: StructMacro } }
|
31
|
+
| { type: typeof installMacroType, payload: { layerKey: (LayerKey | undefined), button: (Button | undefined), installed_macro: string } }
|
32
|
+
| { type: typeof uninstallMacroType, payload: { layerKey: (LayerKey | undefined), button: (Button | undefined), installed_macro: string } }
|
33
|
+
| { type: typeof installModeType, payload: { layerKey: (LayerKey | undefined), button: (Button | undefined), installed_mode: string } }
|
34
|
+
| { type: typeof uninstallModeType, payload: { layerKey: (LayerKey | undefined), button: (Button | undefined), installed_mode: string } }
|
35
|
+
| { type: typeof applyModeType, payload: { layerKey: LayerKey, button: (Button | undefined), mode: StructMode } }
|
36
|
+
|
37
|
+
export const LayerReducer = (layers: Layers, action: ACTION_TYPE) => {
|
38
|
+
const layerKey = action.payload.layerKey as LayerKey;
|
39
|
+
const button = action.payload.button as Button;
|
40
|
+
|
41
|
+
const flip = layerKey && button && layers[layerKey][button]?.flip || {} as Flip
|
42
|
+
const remap = layerKey && button && layers[layerKey][button]?.remap || {} as Remap
|
43
|
+
|
44
|
+
switch (action.type) {
|
45
|
+
case disableFlipType:
|
46
|
+
flip.enable = false;
|
47
|
+
layers[layerKey][button] = { flip: flip, open: true }
|
48
|
+
return { ...layers };
|
49
|
+
case alwaysFlipType:
|
50
|
+
flip.if_pressed = [];
|
51
|
+
flip.enable = true;
|
52
|
+
layers[layerKey][button] = { flip: flip, open: true }
|
53
|
+
return { ...layers };
|
54
|
+
case flipIfPressedSelfType:
|
55
|
+
flip.if_pressed = [button];
|
56
|
+
flip.enable = true;
|
57
|
+
layers[layerKey][button] = { flip: flip, open: true }
|
58
|
+
return { ...layers };
|
59
|
+
case flipIfPressedSomeButtonsType:
|
60
|
+
flip.if_pressed = action.payload.targetButtons;
|
61
|
+
flip.enable = true;
|
62
|
+
layers[layerKey][button] = { flip: flip, open: true }
|
63
|
+
return { ...layers };
|
64
|
+
case ignoreButtonsInFlipingType:
|
65
|
+
flip.force_neutral = action.payload.targetButtons;
|
66
|
+
layers[layerKey][button] = { flip: flip, open: true }
|
67
|
+
return { ...layers };
|
68
|
+
case remapType:
|
69
|
+
flip.enable = false;
|
70
|
+
remap.to = action.payload.targetButtons;
|
71
|
+
layers[layerKey][button] = { flip: flip, remap: remap, open: true }
|
72
|
+
return { ...layers };
|
73
|
+
case openMenuType:
|
74
|
+
flip.enable = false;
|
75
|
+
layers[layerKey][button] = { flip: flip, open: true };
|
76
|
+
return { ...layers };
|
77
|
+
case closeMenuType:
|
78
|
+
flip.enable = false;
|
79
|
+
layers[layerKey][button] = { flip: flip, open: false }
|
80
|
+
return { ...layers };
|
81
|
+
case applyMacroType:
|
82
|
+
const structMacro = action.payload.macro
|
83
|
+
if(!structMacro) { return { ...layers } };
|
84
|
+
const macroTable = layers[layerKey].macro as Macro || {} as Macro
|
85
|
+
macroTable[structMacro.name] = structMacro.if_pressed.sort()
|
86
|
+
layers[layerKey].macro = macroTable
|
87
|
+
return { ...layers };
|
88
|
+
case installMacroType:
|
89
|
+
const installedMacro = action.payload.installed_macro
|
90
|
+
const h = { ...layers }
|
91
|
+
h.installed_macros ||= {}
|
92
|
+
h.installed_macros[installedMacro] = true
|
93
|
+
return h;
|
94
|
+
case uninstallMacroType:
|
95
|
+
const unregisterInstalledMacro = action.payload.installed_macro
|
96
|
+
const hh = { ...layers }
|
97
|
+
hh.installed_macros ||= {}
|
98
|
+
hh.installed_macros[unregisterInstalledMacro] = false
|
99
|
+
return hh;
|
100
|
+
case installModeType:
|
101
|
+
const installedMode = action.payload.installed_mode
|
102
|
+
const l = { ...layers }
|
103
|
+
l.installed_modes ||= {}
|
104
|
+
l.installed_modes[installedMode] = true
|
105
|
+
return l;
|
106
|
+
case uninstallModeType:
|
107
|
+
const uninstallMode = action.payload.installed_mode
|
108
|
+
const uml = { ...layers }
|
109
|
+
uml.installed_modes ||= {}
|
110
|
+
uml.installed_modes[uninstallMode] = false
|
111
|
+
return uml;
|
112
|
+
case applyModeType:
|
113
|
+
const applyMode = action.payload.mode;
|
114
|
+
layers[layerKey].mode = { [applyMode.name]: true};
|
115
|
+
return { ...layers };
|
116
|
+
default:
|
117
|
+
console.log("一致しないaction typeです")
|
118
|
+
return { ...layers };
|
119
|
+
}
|
120
|
+
};
|
data/src/types/button.ts
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
import { Button } from "./button";
|
2
|
+
import { LayerKey } from "./layer_key";
|
3
|
+
|
4
|
+
export type Flip = {
|
5
|
+
if_pressed?: Array<Button>,
|
6
|
+
enable: Boolean,
|
7
|
+
force_neutral?: Array<Button>,
|
8
|
+
}
|
9
|
+
|
10
|
+
export type StructMacro = {
|
11
|
+
name: string,
|
12
|
+
if_pressed: Array<Button>,
|
13
|
+
}
|
14
|
+
|
15
|
+
export type StructMode = {
|
16
|
+
name: string,
|
17
|
+
}
|
18
|
+
|
19
|
+
export type Macro = {
|
20
|
+
[key in string]: Array<Button>;
|
21
|
+
}
|
22
|
+
|
23
|
+
export type ModeTable = {
|
24
|
+
[key in string]: boolean;
|
25
|
+
}
|
26
|
+
|
27
|
+
export type Remap = {
|
28
|
+
to: Array<Button>,
|
29
|
+
}
|
30
|
+
|
31
|
+
export type ButtonInLayer = {
|
32
|
+
flip?: Flip,
|
33
|
+
macro?: Macro, // deprecated
|
34
|
+
remap?: Remap,
|
35
|
+
open: boolean,
|
36
|
+
}
|
37
|
+
|
38
|
+
type _ButtonsInLayer = {
|
39
|
+
[key in Button] : ButtonInLayer;
|
40
|
+
}
|
41
|
+
|
42
|
+
export type ButtonsInLayer = _ButtonsInLayer & {
|
43
|
+
macro?: Macro; // TODO macroTableという名前にしたい
|
44
|
+
mode?: ModeTable;
|
45
|
+
};
|
46
|
+
|
47
|
+
export type InstalledPlugin = {
|
48
|
+
[key in string]: boolean;
|
49
|
+
}
|
50
|
+
|
51
|
+
export type Layers = {
|
52
|
+
up: ButtonsInLayer,
|
53
|
+
right: ButtonsInLayer,
|
54
|
+
down: ButtonsInLayer,
|
55
|
+
left: ButtonsInLayer,
|
56
|
+
installed_macros?: InstalledPlugin,
|
57
|
+
installed_modes?: InstalledPlugin,
|
58
|
+
}
|
59
|
+
|
60
|
+
export type ButtonsSettingType = {
|
61
|
+
prefix_keys_for_changing_layer: Array<Button>;
|
62
|
+
layers: Layers;
|
63
|
+
}
|
@@ -0,0 +1 @@
|
|
1
|
+
export type PbmStats = "stopped" | "running" | "unknown" | "waiting" | "error";
|
data/src/types/plugin.ts
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
export type PluginBody = {
|
2
|
+
display_name: string;
|
3
|
+
class_namespace: string;
|
4
|
+
}
|
5
|
+
|
6
|
+
export type Plugin = {
|
7
|
+
[key in string] : {
|
8
|
+
modes: Array<PluginBody>;
|
9
|
+
macros: Array<PluginBody>;
|
10
|
+
}
|
11
|
+
}
|
12
|
+
|
13
|
+
// plugins.
|
14
|
+
export const AvailablePlugins = [
|
15
|
+
{
|
16
|
+
splatoon2: {
|
17
|
+
modes: [
|
18
|
+
{ display_name: "splatoon2.guruguru", class_namespace: "ProconBypassMan::Splatoon2::Mode::Guruguru" },
|
19
|
+
],
|
20
|
+
macros: [
|
21
|
+
{ display_name: "splatoon2.fast_return", class_namespace: "ProconBypassMan::Splatoon2::Macro::FastReturn" },
|
22
|
+
],
|
23
|
+
}
|
24
|
+
} as Plugin,
|
25
|
+
]
|
26
|
+
|
27
|
+
export const MacroNameMap = AvailablePlugins.reduce((hash, item: Plugin) => {
|
28
|
+
for (var [name, plugin] of Object.entries(item)) {
|
29
|
+
plugin.macros.forEach((macro: PluginBody) => {
|
30
|
+
hash[macro.class_namespace] = macro.display_name
|
31
|
+
})
|
32
|
+
};
|
33
|
+
return hash;
|
34
|
+
}, {} as any)
|
35
|
+
|
36
|
+
export const ModeNameMap = AvailablePlugins.reduce((hash, item: Plugin) => {
|
37
|
+
for (var [name, plugin] of Object.entries(item)) {
|
38
|
+
plugin.modes.forEach((mode: PluginBody) => {
|
39
|
+
hash[mode.class_namespace] = mode.display_name
|
40
|
+
})
|
41
|
+
};
|
42
|
+
return hash;
|
43
|
+
}, {} as any)
|