sonolus-bandori-engine 0.7.1 → 1.0.0
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.
- package/dist/EngineConfiguration +0 -0
- package/dist/EngineData +0 -0
- package/dist/Resource.cjs +20 -0
- package/dist/{Resource.d.ts → Resource.d.cts} +9 -9
- package/dist/bestdori/convert.cjs +278 -0
- package/dist/bestdori/convert.d.cts +3 -0
- package/dist/bestdori/index.cjs +2 -0
- package/dist/bestdori/index.d.cts +39 -0
- package/dist/{index.js → index.cjs} +42 -47
- package/dist/{index.d.ts → index.d.cts} +30 -32
- package/package.json +15 -19
- package/LICENSE.txt +0 -21
- package/README.md +0 -86
- package/dist/Resource.js +0 -24
- package/dist/archetypes.json +0 -1
- package/dist/convert.d.ts +0 -52
- package/dist/convert.js +0 -257
package/dist/EngineConfiguration
CHANGED
|
Binary file
|
package/dist/EngineData
CHANGED
|
Binary file
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Resource = void 0;
|
|
4
|
+
const node_crypto_1 = require("node:crypto");
|
|
5
|
+
const node_fs_1 = require("node:fs");
|
|
6
|
+
const node_path_1 = require("node:path");
|
|
7
|
+
class Resource {
|
|
8
|
+
constructor(path) {
|
|
9
|
+
this.path = (0, node_path_1.resolve)(__dirname, path);
|
|
10
|
+
}
|
|
11
|
+
get hash() {
|
|
12
|
+
this._hash ??= (0, node_crypto_1.createHash)('sha1').update(this.buffer).digest('hex');
|
|
13
|
+
return this._hash;
|
|
14
|
+
}
|
|
15
|
+
get buffer() {
|
|
16
|
+
this._buffer ??= (0, node_fs_1.readFileSync)(this.path);
|
|
17
|
+
return this._buffer;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
exports.Resource = Resource;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
/// <reference types="node" />
|
|
2
|
-
export declare class Resource {
|
|
3
|
-
readonly path: string;
|
|
4
|
-
private _hash?;
|
|
5
|
-
private _buffer?;
|
|
6
|
-
constructor(path: string);
|
|
7
|
-
get hash(): string;
|
|
8
|
-
get buffer(): Buffer;
|
|
9
|
-
}
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
export declare class Resource {
|
|
3
|
+
readonly path: string;
|
|
4
|
+
private _hash?;
|
|
5
|
+
private _buffer?;
|
|
6
|
+
constructor(path: string);
|
|
7
|
+
get hash(): string;
|
|
8
|
+
get buffer(): Buffer;
|
|
9
|
+
}
|
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.bestdoriToLevelData = void 0;
|
|
4
|
+
const sonolus_core_1 = require("sonolus-core");
|
|
5
|
+
function bestdoriToLevelData(chart, bgmOffset = 0) {
|
|
6
|
+
const entities = [];
|
|
7
|
+
const beatToIntermediates = new Map();
|
|
8
|
+
const intermediateToRef = new Map();
|
|
9
|
+
const intermediateToEntity = new Map();
|
|
10
|
+
let i = 0;
|
|
11
|
+
const getRef = (intermediate) => {
|
|
12
|
+
let ref = intermediateToRef.get(intermediate);
|
|
13
|
+
if (ref)
|
|
14
|
+
return ref;
|
|
15
|
+
ref = (i++).toString(36);
|
|
16
|
+
intermediateToRef.set(intermediate, ref);
|
|
17
|
+
const entity = intermediateToEntity.get(intermediate);
|
|
18
|
+
if (entity)
|
|
19
|
+
entity.ref = ref;
|
|
20
|
+
return ref;
|
|
21
|
+
};
|
|
22
|
+
const append = (intermediate) => {
|
|
23
|
+
const entity = {
|
|
24
|
+
archetype: intermediate.archetype,
|
|
25
|
+
data: [],
|
|
26
|
+
};
|
|
27
|
+
if (intermediate.sim) {
|
|
28
|
+
const beat = intermediate.data[sonolus_core_1.EngineArchetypeDataName.Beat];
|
|
29
|
+
if (typeof beat !== 'number')
|
|
30
|
+
throw 'Unexpected beat';
|
|
31
|
+
const intermediates = beatToIntermediates.get(beat);
|
|
32
|
+
if (intermediates) {
|
|
33
|
+
intermediates.push(intermediate);
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
beatToIntermediates.set(beat, [intermediate]);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
const ref = intermediateToRef.get(intermediate);
|
|
40
|
+
if (ref)
|
|
41
|
+
entity.ref = ref;
|
|
42
|
+
intermediateToEntity.set(intermediate, entity);
|
|
43
|
+
entities.push(entity);
|
|
44
|
+
for (const [name, value] of Object.entries(intermediate.data)) {
|
|
45
|
+
if (typeof value === 'number') {
|
|
46
|
+
entity.data.push({
|
|
47
|
+
name,
|
|
48
|
+
value,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
entity.data.push({
|
|
53
|
+
name,
|
|
54
|
+
ref: getRef(value),
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
append({
|
|
60
|
+
archetype: 'Initialization',
|
|
61
|
+
data: {},
|
|
62
|
+
sim: false,
|
|
63
|
+
});
|
|
64
|
+
append({
|
|
65
|
+
archetype: 'InputManager',
|
|
66
|
+
data: {},
|
|
67
|
+
sim: false,
|
|
68
|
+
});
|
|
69
|
+
append({
|
|
70
|
+
archetype: 'Stage',
|
|
71
|
+
data: {},
|
|
72
|
+
sim: false,
|
|
73
|
+
});
|
|
74
|
+
const objects = repair(chart);
|
|
75
|
+
for (const object of objects) {
|
|
76
|
+
handlers[object.type](object, append);
|
|
77
|
+
}
|
|
78
|
+
for (const intermediates of beatToIntermediates.values()) {
|
|
79
|
+
for (let i = 1; i < intermediates.length; i++) {
|
|
80
|
+
append({
|
|
81
|
+
archetype: 'SimLine',
|
|
82
|
+
data: {
|
|
83
|
+
a: intermediates[i - 1],
|
|
84
|
+
b: intermediates[i],
|
|
85
|
+
},
|
|
86
|
+
sim: false,
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return {
|
|
91
|
+
bgmOffset,
|
|
92
|
+
entities,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
exports.bestdoriToLevelData = bestdoriToLevelData;
|
|
96
|
+
const bpm = (object, append) => append({
|
|
97
|
+
archetype: sonolus_core_1.EngineArchetypeName.BpmChange,
|
|
98
|
+
data: {
|
|
99
|
+
[sonolus_core_1.EngineArchetypeDataName.Beat]: object.beat,
|
|
100
|
+
[sonolus_core_1.EngineArchetypeDataName.Bpm]: object.bpm,
|
|
101
|
+
},
|
|
102
|
+
sim: false,
|
|
103
|
+
});
|
|
104
|
+
const single = (object, append) => append({
|
|
105
|
+
archetype: object.flick ? 'FlickNote' : 'TapNote',
|
|
106
|
+
data: {
|
|
107
|
+
[sonolus_core_1.EngineArchetypeDataName.Beat]: object.beat,
|
|
108
|
+
lane: object.lane - 3,
|
|
109
|
+
},
|
|
110
|
+
sim: true,
|
|
111
|
+
});
|
|
112
|
+
const directional = (object, append) => append({
|
|
113
|
+
archetype: 'DirectionalFlickNote',
|
|
114
|
+
data: {
|
|
115
|
+
[sonolus_core_1.EngineArchetypeDataName.Beat]: object.beat,
|
|
116
|
+
lane: object.lane - 3,
|
|
117
|
+
direction: object.direction === 'Left' ? -1 : 1,
|
|
118
|
+
size: object.width,
|
|
119
|
+
},
|
|
120
|
+
sim: true,
|
|
121
|
+
});
|
|
122
|
+
const longAndSlide = (object, append) => {
|
|
123
|
+
let start;
|
|
124
|
+
let head;
|
|
125
|
+
const connectors = [];
|
|
126
|
+
const connectorArchetype = object.connections
|
|
127
|
+
.slice(1, -1)
|
|
128
|
+
.some((connection) => connection.hidden)
|
|
129
|
+
? 'CurvedSlideConnector'
|
|
130
|
+
: 'StraightSlideConnector';
|
|
131
|
+
for (const [i, connection] of object.connections.entries()) {
|
|
132
|
+
if (i === 0) {
|
|
133
|
+
start = head = {
|
|
134
|
+
archetype: 'SlideStartNote',
|
|
135
|
+
data: {
|
|
136
|
+
[sonolus_core_1.EngineArchetypeDataName.Beat]: connection.beat,
|
|
137
|
+
lane: connection.lane - 3,
|
|
138
|
+
},
|
|
139
|
+
sim: true,
|
|
140
|
+
};
|
|
141
|
+
append(start);
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
if (!start)
|
|
145
|
+
throw 'Unexpected missing start';
|
|
146
|
+
if (!head)
|
|
147
|
+
throw 'Unexpected missing head';
|
|
148
|
+
if (i === object.connections.length - 1) {
|
|
149
|
+
const tail = {
|
|
150
|
+
archetype: connection.flick ? 'SlideEndFlickNote' : 'SlideEndNote',
|
|
151
|
+
data: {
|
|
152
|
+
[sonolus_core_1.EngineArchetypeDataName.Beat]: connection.beat,
|
|
153
|
+
lane: connection.lane - 3,
|
|
154
|
+
prev: start,
|
|
155
|
+
},
|
|
156
|
+
sim: true,
|
|
157
|
+
};
|
|
158
|
+
if (connection.flick) {
|
|
159
|
+
tail.data.long =
|
|
160
|
+
object.connections.length === 2 && head.data.lane === tail.data.lane ? 1 : 0;
|
|
161
|
+
}
|
|
162
|
+
append(tail);
|
|
163
|
+
connectors.push({
|
|
164
|
+
archetype: connectorArchetype,
|
|
165
|
+
data: {
|
|
166
|
+
start,
|
|
167
|
+
head,
|
|
168
|
+
tail,
|
|
169
|
+
},
|
|
170
|
+
sim: false,
|
|
171
|
+
});
|
|
172
|
+
for (const connector of connectors) {
|
|
173
|
+
connector.data.end = tail;
|
|
174
|
+
append(connector);
|
|
175
|
+
}
|
|
176
|
+
connectors.length = 0;
|
|
177
|
+
continue;
|
|
178
|
+
}
|
|
179
|
+
if (connection.hidden) {
|
|
180
|
+
const tail = {
|
|
181
|
+
archetype: 'IgnoredNote',
|
|
182
|
+
data: {
|
|
183
|
+
[sonolus_core_1.EngineArchetypeDataName.Beat]: connection.beat,
|
|
184
|
+
lane: connection.lane - 3,
|
|
185
|
+
},
|
|
186
|
+
sim: false,
|
|
187
|
+
};
|
|
188
|
+
append(tail);
|
|
189
|
+
connectors.push({
|
|
190
|
+
archetype: connectorArchetype,
|
|
191
|
+
data: {
|
|
192
|
+
start,
|
|
193
|
+
head,
|
|
194
|
+
tail,
|
|
195
|
+
},
|
|
196
|
+
sim: false,
|
|
197
|
+
});
|
|
198
|
+
head = tail;
|
|
199
|
+
continue;
|
|
200
|
+
}
|
|
201
|
+
const tail = {
|
|
202
|
+
archetype: 'SlideTickNote',
|
|
203
|
+
data: {
|
|
204
|
+
[sonolus_core_1.EngineArchetypeDataName.Beat]: connection.beat,
|
|
205
|
+
lane: connection.lane - 3,
|
|
206
|
+
prev: start,
|
|
207
|
+
},
|
|
208
|
+
sim: false,
|
|
209
|
+
};
|
|
210
|
+
append(tail);
|
|
211
|
+
connectors.push({
|
|
212
|
+
archetype: connectorArchetype,
|
|
213
|
+
data: {
|
|
214
|
+
start,
|
|
215
|
+
head,
|
|
216
|
+
tail,
|
|
217
|
+
},
|
|
218
|
+
sim: false,
|
|
219
|
+
});
|
|
220
|
+
for (const connector of connectors) {
|
|
221
|
+
connector.data.end = tail;
|
|
222
|
+
append(connector);
|
|
223
|
+
}
|
|
224
|
+
connectors.length = 0;
|
|
225
|
+
start = head = tail;
|
|
226
|
+
}
|
|
227
|
+
};
|
|
228
|
+
const system = () => {
|
|
229
|
+
// noop
|
|
230
|
+
};
|
|
231
|
+
const handlers = {
|
|
232
|
+
BPM: bpm,
|
|
233
|
+
Single: single,
|
|
234
|
+
Directional: directional,
|
|
235
|
+
Long: longAndSlide,
|
|
236
|
+
Slide: longAndSlide,
|
|
237
|
+
System: system,
|
|
238
|
+
};
|
|
239
|
+
const repair = (objects) => {
|
|
240
|
+
const replace = (o, n) => objects.splice(objects.indexOf(o), 1, n);
|
|
241
|
+
const remove = (o) => objects.splice(objects.indexOf(o), 1);
|
|
242
|
+
for (const object of objects) {
|
|
243
|
+
switch (object.type) {
|
|
244
|
+
case 'Long':
|
|
245
|
+
case 'Slide': {
|
|
246
|
+
object.connections.sort((a, b) => a.beat - b.beat);
|
|
247
|
+
const visibleConnections = object.connections.filter((connection) => !connection.hidden);
|
|
248
|
+
switch (visibleConnections.length) {
|
|
249
|
+
case 0:
|
|
250
|
+
remove(object);
|
|
251
|
+
break;
|
|
252
|
+
case 1: {
|
|
253
|
+
const connection = visibleConnections[0];
|
|
254
|
+
const single = {
|
|
255
|
+
type: 'Single',
|
|
256
|
+
lane: connection.lane,
|
|
257
|
+
beat: connection.beat,
|
|
258
|
+
};
|
|
259
|
+
if (connection.flick)
|
|
260
|
+
single.flick = connection.flick;
|
|
261
|
+
replace(object, single);
|
|
262
|
+
break;
|
|
263
|
+
}
|
|
264
|
+
default:
|
|
265
|
+
while (object.connections[0].hidden) {
|
|
266
|
+
object.connections.shift();
|
|
267
|
+
}
|
|
268
|
+
while (object.connections[object.connections.length - 1].hidden) {
|
|
269
|
+
object.connections.pop();
|
|
270
|
+
}
|
|
271
|
+
break;
|
|
272
|
+
}
|
|
273
|
+
break;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
return objects;
|
|
278
|
+
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export type BestdoriChart = ChartObject[];
|
|
2
|
+
export type ChartObject = SingleObject | DirectionalObject | SlideObject | LongObject | BPMObject | SystemObject;
|
|
3
|
+
type ObjectBase = {
|
|
4
|
+
beat: number;
|
|
5
|
+
};
|
|
6
|
+
type NoteBase = ObjectBase & {
|
|
7
|
+
lane: number;
|
|
8
|
+
flick?: true;
|
|
9
|
+
skill?: true;
|
|
10
|
+
charge?: true;
|
|
11
|
+
};
|
|
12
|
+
export type SingleObject = NoteBase & {
|
|
13
|
+
type: 'Single';
|
|
14
|
+
};
|
|
15
|
+
export type DirectionalObject = NoteBase & {
|
|
16
|
+
type: 'Directional';
|
|
17
|
+
direction: 'Left' | 'Right';
|
|
18
|
+
width: number;
|
|
19
|
+
};
|
|
20
|
+
export type SlideObject = {
|
|
21
|
+
type: 'Slide';
|
|
22
|
+
connections: Connection[];
|
|
23
|
+
};
|
|
24
|
+
export type LongObject = {
|
|
25
|
+
type: 'Long';
|
|
26
|
+
connections: Connection[];
|
|
27
|
+
};
|
|
28
|
+
export type Connection = NoteBase & {
|
|
29
|
+
hidden?: true;
|
|
30
|
+
};
|
|
31
|
+
export type BPMObject = ObjectBase & {
|
|
32
|
+
type: 'BPM';
|
|
33
|
+
bpm: number;
|
|
34
|
+
};
|
|
35
|
+
export type SystemObject = ObjectBase & {
|
|
36
|
+
type: 'System';
|
|
37
|
+
data: string;
|
|
38
|
+
};
|
|
39
|
+
export {};
|
|
@@ -1,47 +1,42 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
4
|
-
const
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
exports.
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
'
|
|
32
|
-
'',
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
'',
|
|
36
|
-
'
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
exports.
|
|
42
|
-
exports.
|
|
43
|
-
exports.engineThumbnail = new Resource_1.Resource('thumbnail.png');
|
|
44
|
-
function fromBestdori(chart) {
|
|
45
|
-
return (0, convert_1.fromBestdori)(chart, archetypes);
|
|
46
|
-
}
|
|
47
|
-
exports.fromBestdori = fromBestdori;
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.engineThumbnail = exports.engineData = exports.engineConfiguration = exports.engineInfo = exports.version = exports.bestdoriToLevelData = void 0;
|
|
4
|
+
const Resource_cjs_1 = require("./Resource.cjs");
|
|
5
|
+
var convert_cjs_1 = require("./bestdori/convert.cjs");
|
|
6
|
+
Object.defineProperty(exports, "bestdoriToLevelData", { enumerable: true, get: function () { return convert_cjs_1.bestdoriToLevelData; } });
|
|
7
|
+
exports.version = '1.0.0';
|
|
8
|
+
exports.engineInfo = {
|
|
9
|
+
name: 'bandori',
|
|
10
|
+
version: 8,
|
|
11
|
+
title: {
|
|
12
|
+
en: 'BanG Dream!',
|
|
13
|
+
ja: 'バンドリ!',
|
|
14
|
+
ko: '뱅드림!',
|
|
15
|
+
zhs: 'BanG Dream!',
|
|
16
|
+
zht: 'BanG Dream!',
|
|
17
|
+
},
|
|
18
|
+
subtitle: {
|
|
19
|
+
en: 'BanG Dream! Girls Band Party!',
|
|
20
|
+
ja: 'バンドリ! ガールズバンドパーティ!',
|
|
21
|
+
ko: '뱅드림! 걸즈 밴드 파티!',
|
|
22
|
+
zhs: 'BanG Dream! 少女乐团派对!',
|
|
23
|
+
zht: 'BanG Dream! 少女樂團派對',
|
|
24
|
+
},
|
|
25
|
+
author: {
|
|
26
|
+
en: 'Burrito',
|
|
27
|
+
},
|
|
28
|
+
description: {
|
|
29
|
+
en: [
|
|
30
|
+
'A recreation of BanG Dream! Girls Band Party engine in Sonolus.',
|
|
31
|
+
'',
|
|
32
|
+
'Version:',
|
|
33
|
+
exports.version,
|
|
34
|
+
'',
|
|
35
|
+
'GitHub Repository:',
|
|
36
|
+
'https://github.com/NonSpicyBurrito/sonolus-bandori-engine',
|
|
37
|
+
].join('\n'),
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
exports.engineConfiguration = new Resource_cjs_1.Resource('EngineConfiguration');
|
|
41
|
+
exports.engineData = new Resource_cjs_1.Resource('EngineData');
|
|
42
|
+
exports.engineThumbnail = new Resource_cjs_1.Resource('thumbnail.png');
|
|
@@ -1,32 +1,30 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
export declare const
|
|
5
|
-
|
|
6
|
-
readonly
|
|
7
|
-
readonly
|
|
8
|
-
|
|
9
|
-
readonly
|
|
10
|
-
readonly
|
|
11
|
-
readonly
|
|
12
|
-
readonly
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
readonly
|
|
17
|
-
readonly
|
|
18
|
-
readonly
|
|
19
|
-
readonly
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
export declare const
|
|
30
|
-
export declare const
|
|
31
|
-
export declare const engineThumbnail: Resource;
|
|
32
|
-
export declare function fromBestdori(chart: ChartObject[]): LevelData;
|
|
1
|
+
import { Resource } from './Resource.cjs';
|
|
2
|
+
export { bestdoriToLevelData } from './bestdori/convert.cjs';
|
|
3
|
+
export declare const version = "1.0.0";
|
|
4
|
+
export declare const engineInfo: {
|
|
5
|
+
readonly name: "bandori";
|
|
6
|
+
readonly version: 8;
|
|
7
|
+
readonly title: {
|
|
8
|
+
readonly en: "BanG Dream!";
|
|
9
|
+
readonly ja: "バンドリ!";
|
|
10
|
+
readonly ko: "뱅드림!";
|
|
11
|
+
readonly zhs: "BanG Dream!";
|
|
12
|
+
readonly zht: "BanG Dream!";
|
|
13
|
+
};
|
|
14
|
+
readonly subtitle: {
|
|
15
|
+
readonly en: "BanG Dream! Girls Band Party!";
|
|
16
|
+
readonly ja: "バンドリ! ガールズバンドパーティ!";
|
|
17
|
+
readonly ko: "뱅드림! 걸즈 밴드 파티!";
|
|
18
|
+
readonly zhs: "BanG Dream! 少女乐团派对!";
|
|
19
|
+
readonly zht: "BanG Dream! 少女樂團派對";
|
|
20
|
+
};
|
|
21
|
+
readonly author: {
|
|
22
|
+
readonly en: "Burrito";
|
|
23
|
+
};
|
|
24
|
+
readonly description: {
|
|
25
|
+
readonly en: string;
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
export declare const engineConfiguration: Resource;
|
|
29
|
+
export declare const engineData: Resource;
|
|
30
|
+
export declare const engineThumbnail: Resource;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sonolus-bandori-engine",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"description": "A recreation of BanG Dream! Girls Band Party engine in Sonolus",
|
|
5
5
|
"author": "NonSpicyBurrito",
|
|
6
6
|
"repository": "github:NonSpicyBurrito/sonolus-bandori-engine",
|
|
@@ -8,30 +8,26 @@
|
|
|
8
8
|
"keywords": [
|
|
9
9
|
"Sonolus"
|
|
10
10
|
],
|
|
11
|
-
"main": "dist",
|
|
11
|
+
"main": "dist/index.cjs",
|
|
12
12
|
"files": [
|
|
13
13
|
"dist"
|
|
14
14
|
],
|
|
15
15
|
"scripts": {
|
|
16
|
-
"
|
|
17
|
-
"
|
|
18
|
-
"build": "
|
|
16
|
+
"dev": "sonolus-cli --dev",
|
|
17
|
+
"prebuild": "tsc -p . --noEmit && eslint --ext .mts ./src && eslint --ext .cts ./lib",
|
|
18
|
+
"build": "tsc -p ./lib/tsconfig.json && sonolus-cli --build && node ./lib/build.mjs"
|
|
19
19
|
},
|
|
20
20
|
"devDependencies": {
|
|
21
|
-
"@
|
|
22
|
-
"@
|
|
23
|
-
"@typescript-eslint/
|
|
24
|
-
"
|
|
25
|
-
"eslint": "^8.
|
|
26
|
-
"eslint-config-prettier": "^8.5.0",
|
|
21
|
+
"@types/node": "^16.18.35",
|
|
22
|
+
"@typescript-eslint/eslint-plugin": "^5.59.9",
|
|
23
|
+
"@typescript-eslint/parser": "^5.59.9",
|
|
24
|
+
"eslint": "^8.42.0",
|
|
25
|
+
"eslint-config-prettier": "^8.8.0",
|
|
27
26
|
"eslint-plugin-prettier": "^4.2.1",
|
|
28
|
-
"
|
|
29
|
-
"prettier": "^2.
|
|
30
|
-
"
|
|
31
|
-
"sonolus
|
|
32
|
-
"
|
|
33
|
-
"ts-node": "^10.9.1",
|
|
34
|
-
"ts-node-dev": "^2.0.0",
|
|
35
|
-
"typescript": "^4.9.3"
|
|
27
|
+
"prettier": "^2.8.8",
|
|
28
|
+
"prettier-plugin-organize-imports": "^3.2.2",
|
|
29
|
+
"sonolus-core": "~7.0.0",
|
|
30
|
+
"sonolus.js": "~9.0.0",
|
|
31
|
+
"typescript": "~5.1.3"
|
|
36
32
|
}
|
|
37
33
|
}
|
package/LICENSE.txt
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2021 NonSpicyBurrito
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
package/README.md
DELETED
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
# Sonolus Bandori Engine
|
|
2
|
-
|
|
3
|
-
A recreation of BanG Dream! Girls Band Party engine in [Sonolus](https://sonolus.com).
|
|
4
|
-
|
|
5
|
-
## Links
|
|
6
|
-
|
|
7
|
-
- [Sonolus Website](https://sonolus.com)
|
|
8
|
-
- [Sonolus Wiki](https://github.com/NonSpicyBurrito/sonolus-wiki)
|
|
9
|
-
|
|
10
|
-
## Installation
|
|
11
|
-
|
|
12
|
-
```
|
|
13
|
-
npm install sonolus-bandori-engine --save
|
|
14
|
-
```
|
|
15
|
-
|
|
16
|
-
## Custom Resources
|
|
17
|
-
|
|
18
|
-
Engine ID: `1`
|
|
19
|
-
|
|
20
|
-
### Skin Sprites
|
|
21
|
-
|
|
22
|
-
| ID | Sprite | Bandori Asset Path |
|
|
23
|
-
| --- | ------------------------------ | ----------------------------------------------------- |
|
|
24
|
-
| 1 | Stage | `/ingameskin/fieldskin/{name}/bg_line_rhythm` |
|
|
25
|
-
| 2 | Judgment Line | `/ingameskin/fieldskin/{name}/game_play_line` |
|
|
26
|
-
| 11 | Left Directional Flick Note | `/ingameskin/noteskin/{name}/DirectionalFlickSprites` |
|
|
27
|
-
| 12 | Right Directional Flick Note | `/ingameskin/noteskin/{name}/DirectionalFlickSprites` |
|
|
28
|
-
| 21 | Left Directional Flick Marker | `/ingameskin/noteskin/{name}/DirectionalFlickSprites` |
|
|
29
|
-
| 22 | Right Directional Flick Marker | `/ingameskin/noteskin/{name}/DirectionalFlickSprites` |
|
|
30
|
-
|
|
31
|
-
### Effect Clips
|
|
32
|
-
|
|
33
|
-
| ID | Clip | Bandori Asset Path |
|
|
34
|
-
| --- | ------------------------ | ------------------------------------------ |
|
|
35
|
-
| 1 | Directional Flick Single | `/sound/tapseskin/{name}/directional_fl` |
|
|
36
|
-
| 2 | Directional Flick Double | `/sound/tapseskin/{name}/directional_fl_2` |
|
|
37
|
-
| 3 | Directional Flick Triple | `/sound/tapseskin/{name}/directional_fl_3` |
|
|
38
|
-
|
|
39
|
-
### Particle Effects
|
|
40
|
-
|
|
41
|
-
| ID | Effect |
|
|
42
|
-
| --- | -------------------------------- |
|
|
43
|
-
| 1 | Circular Left Directional Flick |
|
|
44
|
-
| 2 | Circular Right Directional Flick |
|
|
45
|
-
| 11 | Linear Left Directional Flick |
|
|
46
|
-
| 12 | Linear Right Directional Flick |
|
|
47
|
-
|
|
48
|
-
## Documentation
|
|
49
|
-
|
|
50
|
-
### `version`
|
|
51
|
-
|
|
52
|
-
Package version.
|
|
53
|
-
|
|
54
|
-
### `engineInfo`
|
|
55
|
-
|
|
56
|
-
Partial engine information compatible with [sonolus-express](https://github.com/NonSpicyBurrito/sonolus-express).
|
|
57
|
-
|
|
58
|
-
### `engineConfiguration`
|
|
59
|
-
|
|
60
|
-
Engine Configuration.
|
|
61
|
-
|
|
62
|
-
- `engineConfiguration.path`: path to file.
|
|
63
|
-
- `engineConfiguration.buffer`: buffer of file.
|
|
64
|
-
- `engineConfiguration.hash`: hash of file.
|
|
65
|
-
|
|
66
|
-
### `engineData`
|
|
67
|
-
|
|
68
|
-
Engine Data.
|
|
69
|
-
|
|
70
|
-
- `engineData.path`: path to file.
|
|
71
|
-
- `engineData.buffer`: buffer of file.
|
|
72
|
-
- `engineData.hash`: hash of file.
|
|
73
|
-
|
|
74
|
-
### `engineThumbnail`
|
|
75
|
-
|
|
76
|
-
Engine Thumbnail.
|
|
77
|
-
|
|
78
|
-
- `engineThumbnail.path`: path to file.
|
|
79
|
-
- `engineThumbnail.buffer`: buffer of file.
|
|
80
|
-
- `engineThumbnail.hash`: hash of file.
|
|
81
|
-
|
|
82
|
-
### `fromBestdori(chart)`
|
|
83
|
-
|
|
84
|
-
Converts Bestdori chart to Level Data.
|
|
85
|
-
|
|
86
|
-
- `chart`: Bestdori chart.
|
package/dist/Resource.js
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.Resource = void 0;
|
|
4
|
-
const crypto_1 = require("crypto");
|
|
5
|
-
const fs_1 = require("fs");
|
|
6
|
-
const path_1 = require("path");
|
|
7
|
-
class Resource {
|
|
8
|
-
constructor(path) {
|
|
9
|
-
this.path = (0, path_1.resolve)(__dirname, path);
|
|
10
|
-
}
|
|
11
|
-
get hash() {
|
|
12
|
-
if (!this._hash) {
|
|
13
|
-
this._hash = (0, crypto_1.createHash)('sha1').update(this.buffer).digest('hex');
|
|
14
|
-
}
|
|
15
|
-
return this._hash;
|
|
16
|
-
}
|
|
17
|
-
get buffer() {
|
|
18
|
-
if (!this._buffer) {
|
|
19
|
-
this._buffer = (0, fs_1.readFileSync)(this.path);
|
|
20
|
-
}
|
|
21
|
-
return this._buffer;
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
exports.Resource = Resource;
|
package/dist/archetypes.json
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"initializationIndex":0,"stageIndex":1,"tapNoteIndex":2,"flickNoteIndex":3,"directionalFlickNoteIndex":4,"slideStartNoteIndex":5,"slideTickNoteIndex":6,"slideEndNoteIndex":7,"slideFlickNoteIndex":8,"straightSliderIndex":9,"curvedSliderIndex":10}
|
package/dist/convert.d.ts
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
import { LevelData } from 'sonolus-core';
|
|
2
|
-
export type ChartObject = SingleObject | DirectionalObject | SlideObject | LongObject | BPMObject | SystemObject;
|
|
3
|
-
type ObjectBase = {
|
|
4
|
-
beat: number;
|
|
5
|
-
};
|
|
6
|
-
type NoteBase = ObjectBase & {
|
|
7
|
-
lane: number;
|
|
8
|
-
flick?: true;
|
|
9
|
-
skill?: true;
|
|
10
|
-
charge?: true;
|
|
11
|
-
};
|
|
12
|
-
type SingleObject = NoteBase & {
|
|
13
|
-
type: 'Single';
|
|
14
|
-
};
|
|
15
|
-
type DirectionalObject = NoteBase & {
|
|
16
|
-
type: 'Directional';
|
|
17
|
-
direction: 'Left' | 'Right';
|
|
18
|
-
width: number;
|
|
19
|
-
};
|
|
20
|
-
type SlideObject = {
|
|
21
|
-
type: 'Slide';
|
|
22
|
-
connections: Connection[];
|
|
23
|
-
};
|
|
24
|
-
type LongObject = {
|
|
25
|
-
type: 'Long';
|
|
26
|
-
connections: Connection[];
|
|
27
|
-
};
|
|
28
|
-
type Connection = NoteBase & {
|
|
29
|
-
hidden?: true;
|
|
30
|
-
};
|
|
31
|
-
type BPMObject = ObjectBase & {
|
|
32
|
-
type: 'BPM';
|
|
33
|
-
bpm: number;
|
|
34
|
-
};
|
|
35
|
-
type SystemObject = ObjectBase & {
|
|
36
|
-
type: 'System';
|
|
37
|
-
data: string;
|
|
38
|
-
};
|
|
39
|
-
export declare function fromBestdori(chart: ChartObject[], archetypes: {
|
|
40
|
-
initializationIndex: number;
|
|
41
|
-
stageIndex: number;
|
|
42
|
-
tapNoteIndex: number;
|
|
43
|
-
flickNoteIndex: number;
|
|
44
|
-
directionalFlickNoteIndex: number;
|
|
45
|
-
slideStartNoteIndex: number;
|
|
46
|
-
slideTickNoteIndex: number;
|
|
47
|
-
slideEndNoteIndex: number;
|
|
48
|
-
slideFlickNoteIndex: number;
|
|
49
|
-
straightSliderIndex: number;
|
|
50
|
-
curvedSliderIndex: number;
|
|
51
|
-
}): LevelData;
|
|
52
|
-
export {};
|
package/dist/convert.js
DELETED
|
@@ -1,257 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.fromBestdori = void 0;
|
|
4
|
-
function fromBestdori(chart, archetypes) {
|
|
5
|
-
const chartObjects = repair(chart);
|
|
6
|
-
const timings = [];
|
|
7
|
-
let timePerBeat = 0;
|
|
8
|
-
let beats = 0;
|
|
9
|
-
let time = 0;
|
|
10
|
-
chartObjects
|
|
11
|
-
.filter((chartObject) => chartObject.type === 'BPM')
|
|
12
|
-
.sort((a, b) => a.beat - b.beat)
|
|
13
|
-
.forEach((bpmObject) => {
|
|
14
|
-
time += (bpmObject.beat - beats) * timePerBeat;
|
|
15
|
-
beats = bpmObject.beat;
|
|
16
|
-
timePerBeat = 60 / bpmObject.bpm;
|
|
17
|
-
timings.unshift({
|
|
18
|
-
beat: beats,
|
|
19
|
-
time,
|
|
20
|
-
timePerBeat,
|
|
21
|
-
});
|
|
22
|
-
});
|
|
23
|
-
const wrappedNoteEntities = [
|
|
24
|
-
{
|
|
25
|
-
entity: {
|
|
26
|
-
archetype: archetypes.initializationIndex,
|
|
27
|
-
},
|
|
28
|
-
time: Number.NEGATIVE_INFINITY,
|
|
29
|
-
lane: 0,
|
|
30
|
-
},
|
|
31
|
-
{
|
|
32
|
-
entity: {
|
|
33
|
-
archetype: archetypes.stageIndex,
|
|
34
|
-
},
|
|
35
|
-
time: Number.NEGATIVE_INFINITY,
|
|
36
|
-
lane: 0,
|
|
37
|
-
},
|
|
38
|
-
];
|
|
39
|
-
const wrappedSliderEntities = [];
|
|
40
|
-
chartObjects.forEach((chartObject) => {
|
|
41
|
-
switch (chartObject.type) {
|
|
42
|
-
case 'Single': {
|
|
43
|
-
const time = beatToTime(chartObject.beat);
|
|
44
|
-
const lane = chartObject.lane - 3;
|
|
45
|
-
wrappedNoteEntities.push({
|
|
46
|
-
entity: {
|
|
47
|
-
archetype: chartObject.flick
|
|
48
|
-
? archetypes.flickNoteIndex
|
|
49
|
-
: archetypes.tapNoteIndex,
|
|
50
|
-
data: {
|
|
51
|
-
index: 1,
|
|
52
|
-
values: [time, lane],
|
|
53
|
-
},
|
|
54
|
-
},
|
|
55
|
-
time,
|
|
56
|
-
lane,
|
|
57
|
-
});
|
|
58
|
-
break;
|
|
59
|
-
}
|
|
60
|
-
case 'Directional': {
|
|
61
|
-
const time = beatToTime(chartObject.beat);
|
|
62
|
-
const lane = chartObject.lane - 3;
|
|
63
|
-
wrappedNoteEntities.push({
|
|
64
|
-
entity: {
|
|
65
|
-
archetype: archetypes.directionalFlickNoteIndex,
|
|
66
|
-
data: {
|
|
67
|
-
index: 1,
|
|
68
|
-
values: [
|
|
69
|
-
time,
|
|
70
|
-
lane,
|
|
71
|
-
chartObject.width - 1,
|
|
72
|
-
chartObject.direction === 'Left' ? 1 : 0,
|
|
73
|
-
],
|
|
74
|
-
},
|
|
75
|
-
},
|
|
76
|
-
time,
|
|
77
|
-
lane,
|
|
78
|
-
});
|
|
79
|
-
break;
|
|
80
|
-
}
|
|
81
|
-
case 'Slide':
|
|
82
|
-
case 'Long': {
|
|
83
|
-
let segments = [];
|
|
84
|
-
const hasHidden = chartObject.connections.some((connection) => connection.hidden);
|
|
85
|
-
const isLong = chartObject.connections.length === 2 &&
|
|
86
|
-
chartObject.connections[0].lane === chartObject.connections[1].lane
|
|
87
|
-
? 1
|
|
88
|
-
: 0;
|
|
89
|
-
chartObject.connections.forEach((connection, index) => {
|
|
90
|
-
const time = beatToTime(connection.beat);
|
|
91
|
-
const lane = connection.lane - 3;
|
|
92
|
-
if (connection.hidden) {
|
|
93
|
-
segments.push({
|
|
94
|
-
time,
|
|
95
|
-
lane,
|
|
96
|
-
});
|
|
97
|
-
}
|
|
98
|
-
else {
|
|
99
|
-
if (index === 0) {
|
|
100
|
-
wrappedNoteEntities.push({
|
|
101
|
-
entity: {
|
|
102
|
-
archetype: archetypes.slideStartNoteIndex,
|
|
103
|
-
data: {
|
|
104
|
-
index: 1,
|
|
105
|
-
values: [time, lane],
|
|
106
|
-
},
|
|
107
|
-
},
|
|
108
|
-
time,
|
|
109
|
-
lane,
|
|
110
|
-
});
|
|
111
|
-
}
|
|
112
|
-
else {
|
|
113
|
-
const head = wrappedNoteEntities[wrappedNoteEntities.length - 1];
|
|
114
|
-
if (index === chartObject.connections.length - 1) {
|
|
115
|
-
wrappedNoteEntities.push({
|
|
116
|
-
entity: {
|
|
117
|
-
archetype: connection.flick
|
|
118
|
-
? archetypes.slideFlickNoteIndex
|
|
119
|
-
: archetypes.slideEndNoteIndex,
|
|
120
|
-
data: {
|
|
121
|
-
index: 0,
|
|
122
|
-
values: [0, time, lane, 0, 0, isLong],
|
|
123
|
-
},
|
|
124
|
-
},
|
|
125
|
-
time,
|
|
126
|
-
lane,
|
|
127
|
-
head,
|
|
128
|
-
});
|
|
129
|
-
}
|
|
130
|
-
else {
|
|
131
|
-
wrappedNoteEntities.push({
|
|
132
|
-
entity: {
|
|
133
|
-
archetype: archetypes.slideTickNoteIndex,
|
|
134
|
-
data: {
|
|
135
|
-
index: 0,
|
|
136
|
-
values: [0, time, lane],
|
|
137
|
-
},
|
|
138
|
-
},
|
|
139
|
-
time,
|
|
140
|
-
lane,
|
|
141
|
-
head,
|
|
142
|
-
});
|
|
143
|
-
}
|
|
144
|
-
segments.push({
|
|
145
|
-
time,
|
|
146
|
-
lane,
|
|
147
|
-
});
|
|
148
|
-
const tail = wrappedNoteEntities[wrappedNoteEntities.length - 1];
|
|
149
|
-
let prevSegment = {
|
|
150
|
-
time: head.time,
|
|
151
|
-
lane: head.lane,
|
|
152
|
-
};
|
|
153
|
-
segments.forEach((segment) => {
|
|
154
|
-
wrappedSliderEntities.push({
|
|
155
|
-
entity: {
|
|
156
|
-
archetype: hasHidden
|
|
157
|
-
? archetypes.curvedSliderIndex
|
|
158
|
-
: archetypes.straightSliderIndex,
|
|
159
|
-
data: {
|
|
160
|
-
index: 0,
|
|
161
|
-
values: [
|
|
162
|
-
0,
|
|
163
|
-
0,
|
|
164
|
-
prevSegment.time,
|
|
165
|
-
segment.time,
|
|
166
|
-
prevSegment.lane,
|
|
167
|
-
segment.lane,
|
|
168
|
-
],
|
|
169
|
-
},
|
|
170
|
-
},
|
|
171
|
-
head,
|
|
172
|
-
tail,
|
|
173
|
-
});
|
|
174
|
-
prevSegment = segment;
|
|
175
|
-
});
|
|
176
|
-
segments = [];
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
});
|
|
180
|
-
break;
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
});
|
|
184
|
-
return {
|
|
185
|
-
bgmOffset: 0,
|
|
186
|
-
entities: [
|
|
187
|
-
...wrappedNoteEntities
|
|
188
|
-
.sort((a, b) => a.time - b.time || Math.abs(b.lane) - Math.abs(a.lane))
|
|
189
|
-
.map((wrappedNoteEntity) => {
|
|
190
|
-
if (wrappedNoteEntity.head) {
|
|
191
|
-
if (!wrappedNoteEntity.entity.data)
|
|
192
|
-
throw 'Unexpected missing entity data';
|
|
193
|
-
wrappedNoteEntity.entity.data.values[0] = wrappedNoteEntities.indexOf(wrappedNoteEntity.head);
|
|
194
|
-
}
|
|
195
|
-
return wrappedNoteEntity.entity;
|
|
196
|
-
}),
|
|
197
|
-
...wrappedSliderEntities.map((wrappedSliderEntity) => {
|
|
198
|
-
if (!wrappedSliderEntity.entity.data)
|
|
199
|
-
throw 'Unexpected missing entity data';
|
|
200
|
-
wrappedSliderEntity.entity.data.values[0] = wrappedNoteEntities.indexOf(wrappedSliderEntity.head);
|
|
201
|
-
wrappedSliderEntity.entity.data.values[1] = wrappedNoteEntities.indexOf(wrappedSliderEntity.tail);
|
|
202
|
-
return wrappedSliderEntity.entity;
|
|
203
|
-
}),
|
|
204
|
-
],
|
|
205
|
-
};
|
|
206
|
-
function beatToTime(beat) {
|
|
207
|
-
for (const timing of timings) {
|
|
208
|
-
if (beat >= timing.beat) {
|
|
209
|
-
return timing.time + (beat - timing.beat) * timing.timePerBeat;
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
return 0;
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
exports.fromBestdori = fromBestdori;
|
|
216
|
-
function repair(chartObjects) {
|
|
217
|
-
chartObjects.forEach((chartObject) => {
|
|
218
|
-
switch (chartObject.type) {
|
|
219
|
-
case 'Long':
|
|
220
|
-
case 'Slide': {
|
|
221
|
-
chartObject.connections.sort((a, b) => a.beat - b.beat);
|
|
222
|
-
const visibleConnections = chartObject.connections.filter((connection) => !connection.hidden);
|
|
223
|
-
switch (visibleConnections.length) {
|
|
224
|
-
case 0:
|
|
225
|
-
remove(chartObject);
|
|
226
|
-
break;
|
|
227
|
-
case 1: {
|
|
228
|
-
const connection = visibleConnections[0];
|
|
229
|
-
replace(chartObject, {
|
|
230
|
-
type: 'Single',
|
|
231
|
-
lane: connection.lane,
|
|
232
|
-
beat: connection.beat,
|
|
233
|
-
flick: connection.flick,
|
|
234
|
-
});
|
|
235
|
-
break;
|
|
236
|
-
}
|
|
237
|
-
default:
|
|
238
|
-
while (chartObject.connections[0]?.hidden) {
|
|
239
|
-
chartObject.connections.shift();
|
|
240
|
-
}
|
|
241
|
-
while (chartObject.connections[chartObject.connections.length - 1]?.hidden) {
|
|
242
|
-
chartObject.connections.pop();
|
|
243
|
-
}
|
|
244
|
-
break;
|
|
245
|
-
}
|
|
246
|
-
break;
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
});
|
|
250
|
-
return chartObjects;
|
|
251
|
-
function replace(o, n) {
|
|
252
|
-
chartObjects.splice(chartObjects.indexOf(o), 1, n);
|
|
253
|
-
}
|
|
254
|
-
function remove(o) {
|
|
255
|
-
chartObjects.splice(chartObjects.indexOf(o), 1);
|
|
256
|
-
}
|
|
257
|
-
}
|