2 Commits
Author SHA1 Message Date
vvo 86500443f2 240709 2024-07-11 11:10:06 +08:00
vvo 390ce43878 cleanup 2024-07-05 14:26:10 +08:00
1962 changed files with 63129 additions and 49 deletions
+4 -13
View File
@@ -1,13 +1,4 @@
# Editor configs
.vscode
.idea
# External modules
node_modules
# Project files
asphyxia-core.d.ts
package.json
package-lock.json
typedoc.json
tsconfig.json
handlers/test.json
webui/test_asset
s3p_extract.exe
ffmpeg.exe
-11
View File
@@ -1,11 +0,0 @@
{
"trailingComma": "es5",
"tabWidth": 2,
"useTabs": false,
"endOfLine": "lf",
"semi": true,
"singleQuote": true,
"bracketSpacing": true,
"arrowParens": "avoid",
"quoteProps": "consistent"
}
+70 -25
View File
@@ -1,25 +1,70 @@
## Asphyxia Plugins
### Plugins included
1. [SOUND VOLTEX (KFC)](https://github.com/22vv0/asphyxia_plugins/tree/kfc)
2. [DanceDanceRevolution (MDX)](https://github.com/22vv0/asphyxia_plugins/tree/mdx)
### Usage
1. Download the Asphyxia plugin of your choosing via one of two methods:
- Method 1:
1. Select the branch of the game plugin you want to use. Branch names use the game's codenames:
- kfc for SDVX
- mdx for DDR
2. Click the green "Code" button and then click "Download ZIP" to start downloading.
- Method 2:
1. Go to the [Releases](https://github.com/22vv0/asphyxia_plugins/releases) page.
2. Find the latest version release of the plugin for your game, indicated again by their codenames.
3. Click "Source code (zip)" to start downloading.
2. Once downloaded, open and extract the files inside the zip to your specific game plugin folder, overwriting any files.
- If you're starting fresh, extract the files to a new folder named ddr@asphyxia or sdvx@asphyxia, depending on the plugin you've downloaded.
### Special thanks
1. Team Asphyxia for providing the plugins repo that I used as a starting point for this 'project' I started for fun.
# SOUND VOLTEX
**Plugin Version:** fork-6.0.3.4
**Supported game versions:** EXCEED GEAR (2024070900)
**Unsupported game versions:** Every other game, as they're untested.
**Required Asphyxia Core version** [1.50c](https://github.com/asphyxia-core/asphyxia-core.github.io/releases/tag/v1.50)
**Notes:**
- Please be aware that this plugin and the savefile it produces are incompatible with the official plugin, or any other forks. Please be cautious of using other plugins' savefiles with this fork of the plugin, or using this fork's savefile with other plugins.
- Before using this plugin, run the [WebUI Asset Update](/plugin/sdvx@asphyxia/update%20webui%20assets). Do this every data and plugin update.
- Please back up your save data to prevent unwanted issues (just in case)
Changelog
===========
## fork-6.0.3.4
### New:
1. Main:
- 2024070900 support
- Added ARENA season 14 (rank match: MEGAMIX BATTLE)
- ARENA STATION set 14 added.
- Added TAMANEKO Adventure: new unlock system where you complete map missions and earn food for TAMANEKO. Completing maps unlock new songs and new XCD charts.
- Track Liberation map can be enabled/disabled in the main settings.
- Check 'Unlocking Events -> Stamp Events -> TAMA猫アドベンチャー (TAMANEKO Adventure)' to toggle the event.
2. Misc:
- Updated Achievements list.
## fork-6.0.3.3
### New:
1. Main:
- 2024060401 support
- Added PREMIUM GENERATOR (角巻わため、 / Tsunomaki Watame set)
- Note: subbg files from this pregene set are missing on some leaked update data, you will not be able to use those until those files are in your data.
- Added Watame songs to licensed songs list (exg.ts)
- Watame crew usable (exg.ts)
2. Misc
- Added option to hide/show serverside-removed music (enabled by default)
## fork-6.0.3.2
### New:
1. Main:
- 2024043001 support
- Added ARENA season 13 (rank match: ARENA BATTLE point system)
- ARENA STATION set 13 added.
- VALKYRIE GENERATOR 14 added.
- Added BPL S3 Stamp Event (eXLIPXe)
- Check "Unlocking Events -> Stamp Events -> BEMANI PRO LEAGUE -SEASON 3- Special Stamp" to toggle the event.
2. Misc:
- Updated ARENA STATION pricing to reflect real game server prices (might miss some though)
### Todo:
1. Figure out how to use image (png) files to appear in information/news popup.
2. More work on online matchmaking (idk if this is possible)
3. Implement pro_team_id setting.
4. Reminder to add new achievements (when it is released officially)
+7
View File
@@ -0,0 +1,7 @@
@echo off
for /f %%a in ('dir "webui\asset\audio\" /b /s /a-d ^| findstr ".wma"') do (
echo Converting %%~fa
ffmpeg -loglevel error -y -i "%%~fa" -vn -ar 44100 -ac 2 -b:a 192k "%%~dpa%%~na.mp3"
del %%~fa
)
@echo on
+1
View File
@@ -0,0 +1 @@
find . -type f -name "*.wma" -exec bash -c 'echo "Converting $1" && ffmpeg -loglevel error -y -i $1 -vn -ar 44100 -ac 2 -b:a 192k ${1%.wma}.mp3 && rm $1' bash {} \;
+7605
View File
File diff suppressed because it is too large Load Diff
+4521
View File
File diff suppressed because it is too large Load Diff
+32
View File
@@ -0,0 +1,32 @@
export const COURSE2 = [
{
id: 0,
level: 0,
season_id: 0,
season_name: '',
new_flg: 0,
name: '',
type: 0,
name_id: 0,
matching_assist: 0,
guage_type: 0,
paseli_type: 0,
tracks: [
{
no: 0,
id: 2,
type: 0
},
{
no: 1,
id: 2,
type: 0
},
{
no: 2,
id: 2,
type: 0
},
]
},
];
+3268
View File
File diff suppressed because it is too large Load Diff
+74
View File
@@ -0,0 +1,74 @@
export const textureslist = [
{
'file': '/data/graphics/ver06/arena_rank.ifs',
'asset_folder': 'arena_rank',
'md5': '0311d56e5db4fe276aaab4435cb52354',
'textures': [
['glow.png', 2890640, 16288, [2, 570, 2, 106], [0, 572, 0, 108]],
['mixstar.png', 2712288, 48206, [2, 542, 110, 650], [0, 544, 108, 652]],
['u1.png', 457712, 149908, [574, 1114, 2, 542], [572, 1116, 0, 544]],
['u2.png', 153136, 152586, [1118, 1658, 2, 542], [1116, 1660, 0, 544]],
['u3.png', 0, 153136, [546, 1086, 546, 1086], [544, 1088, 544, 1088]],
['u4.png', 305728, 151974, [1090, 1630, 546, 1086], [1088, 1632, 544, 1088]],
['u.png', 607632, 147016, [2, 542, 654, 1194], [0, 544, 652, 1196]],
['s1.png', 1067584, 102100, [546, 1086, 1090, 1630], [544, 1088, 1088, 1632]],
['s2.png', 860160, 103886, [1090, 1630, 1090, 1630], [1088, 1632, 1088, 1632]],
['s3.png', 754656, 105494, [2, 542, 1198, 1738], [0, 544, 1196, 1740]],
['s4.png', 964048, 103534, [1662, 2202, 2, 542], [1660, 2204, 0, 544]],
['a1.png', 1856768, 93336, [2206, 2746, 2, 542], [2204, 2748, 0, 544]],
['a2.png', 1666144, 96328, [2750, 3290, 2, 542], [2748, 3292, 0, 544]],
['a3.png', 1568784, 97346, [3294, 3834, 2, 542], [3292, 3836, 0, 544]],
['a4.png', 1762480, 94284, [1634, 2174, 546, 1086], [1632, 2176, 544, 1088]],
['b1.png', 2484560, 86781, [2178, 2718, 546, 1086], [2176, 2720, 544, 1088]],
['b2.png', 2220768, 88790, [2722, 3262, 546, 1086], [2720, 3264, 544, 1088]],
['b3.png', 2041344, 90088, [3266, 3806, 546, 1086], [3264, 3808, 544, 1088]],
['b4.png', 2309568, 87663, [1634, 2174, 1090, 1630], [1632, 2176, 1088, 1632]],
['c1.png', 1470944, 97837, [2178, 2718, 1090, 1630], [2176, 2720, 1088, 1632]],
['c2.png', 1271488, 100109, [2722, 3262, 1090, 1630], [2720, 3264, 1088, 1632]],
['c3.png', 1169696, 101777, [3266, 3806, 1090, 1630], [3264, 3808, 1088, 1632]],
['c4.png', 1371600, 99342, [546, 1086, 1634, 2174], [544, 1088, 1632, 2176]],
['d1.png', 2571344, 85426, [1090, 1630, 1634, 2174], [1088, 1632, 1632, 2176]],
['d2.png', 2131440, 89314, [1634, 2174, 1634, 2174], [1632, 2176, 1632, 2176]],
['d3.png', 1950112, 91226, [2178, 2718, 1634, 2174], [2176, 2720, 1632, 2176]],
['d4.png', 2397232, 87321, [2722, 3262, 1634, 2174], [2720, 3264, 1632, 2176]],
['none.png', 2656784, 55490, [3266, 3806, 1634, 2174], [3264, 3808, 1632, 2176]],
['fudawinstat.png', 2922368, 9846, [2, 514, 1742, 1826], [0, 516, 1740, 1828]]
]
},
{
'file': '/data/graphics/ver06/psd_level.ifs',
'asset_folder': 'difficulty',
'md5': '26ef89b4550cac6156fa78ef4e59e8c3',
'textures': [
['level_small_xcd.png', 193824, 2181, [710, 922, 2, 50], [708, 924, 0, 52]]
]
},
{
'file': '/data/graphics/ver06/psd_skill.ifs',
'asset_folder': 'skill_lv',
'md5': '9a5684960c0d86cd18f1c64f6e13c98b',
'textures': [
['skill_frame_normal_sp.png', 549552, 45470, [2, 602, 242, 582], [0, 604, 240, 584]],
['skill_frame_normal_silver.png', 884448, 32373, [2, 602, 586, 926], [0, 604, 584, 928]],
['skill_frame_normal_gold.png', 850288, 34158, [610, 1210, 2, 342], [608, 1212, 0, 344]],
['skill_frame_god_sp_none.png', 595024, 40145, [1214, 1814, 2, 342], [1212, 1816, 0, 344]],
['skill_frame_god_sp.png', 195312, 80745, [606, 1206, 346, 686], [604, 1208, 344, 688]],
['skill_frame_god_silver.png', 346064, 53343, [1210, 1810, 346, 686], [1208, 1812, 344, 688]],
['skill_frame_god_gold.png', 276064, 69987, [606, 1206, 690, 1030], [604, 1208, 688, 1032]],
['skill_none.png', 1227792, 10209, [2, 454, 930, 1058], [0, 456, 928, 1060]],
['skill_12.png', 1012656, 20206, [458, 910, 1034, 1162], [456, 912, 1032, 1164]],
['skill_11.png', 1050144, 14880, [914, 1366, 1034, 1162], [912, 1368, 1032, 1164]],
['skill_10.png', 1156848, 12906, [1370, 1822, 1034, 1162], [1368, 1824, 1032, 1164]],
['skill_09.png', 1169760, 12873, [2, 454, 1062, 1190], [0, 456, 1060, 1192]],
['skill_08.png', 1091424, 13181, [458, 910, 1166, 1294], [456, 912, 1164, 1296]],
['skill_07.png', 1065024, 13193, [914, 1366, 1166, 1294], [912, 1368, 1164, 1296]],
['skill_06.png', 1078224, 13189, [1370, 1822, 1166, 1294], [1368, 1824, 1164, 1296]],
['skill_05.png', 1104608, 13144, [2, 454, 1194, 1322], [0, 456, 1192, 1324]],
['skill_04.png', 1182640, 12353, [458, 910, 1298, 1426], [456, 912, 1296, 1428]],
['skill_03.png', 1117760, 13079, [914, 1366, 1298, 1426], [912, 1368, 1296, 1428]],
['skill_02.png', 1130848, 13045, [1370, 1822, 1298, 1426], [1368, 1824, 1296, 1428]],
['skill_01.png', 1143904, 12943, [2, 454, 1326, 1454], [0, 456, 1324, 1456]],
['skill_00.png', 1217568, 10211, [458, 910, 1430, 1558], [456, 912, 1428, 1560]]
]
}
]
+549
View File
@@ -0,0 +1,549 @@
import { EVENT4, COURSES4, EXTENDS4 } from '../data/hvn';
import { EVENT5, COURSES5, EXTENDS5 } from '../data/vvw';
import { EVENT6, COURSES6, EXTENDS6, APRILFOOLSSONGS, VALKYRIE_SONGS,
LICENSED_SONGS6, ARENA, VALGENE, INFORMATION6, STAMP_EVENTS6,
REMOVED_SONGS6
} from '../data/exg';
import { COURSE2 } from '../data/inf';
import {getVersion, getRandomIntInclusive} from '../utils';
export const common: EPR = async (info, data, send) => {
try {
let music_db = await IO.ReadFile('webui/asset/json/music_db.json')
let events = [];
let courses = [];
let extend = [];
let date = new Date();
let currentYMDDate = parseInt([date.getFullYear(), ((date.getMonth() + 1) > 9 ? '' : '0') + (date.getMonth() + 1), (date.getDate() > 9 ? '' : '0') + date.getDate()].join(''));
let currentDate = date.toLocaleDateString()
console.log('====================================')
console.log("Calling common function");
const version = parseInt(info.model.split(":")[4]);
if (version <= 2013052900) {
console.log('Game: Booth')
return send.pugFile('templates/booth/common.pug');
}
if (version <= 2014112000) {
console.log('Game: Infinite Infection')
courses = COURSE2;
return send.pugFile('templates/infiniteinfection/common.pug',{
courses,
});
}
switch (info.method) {
case 'sv4_common': {
console.log('Game: Heavenly Haven')
events = EVENT4;
courses = COURSES4;
//extend = EXTENDS4;
EXTENDS4.forEach(val => extend.push(Object.assign({}, val)));
break;
}
case 'sv5_common': {
console.log('Game: Vivid Wave')
events = EVENT5;
courses = COURSES5;
//extend = EXTENDS5;
EXTENDS5.forEach(val => extend.push(Object.assign({}, val)));
break;
}
case 'sv6_common': {
console.log('Game: Exceed Gear')
//events = EVENT6;
EVENT6.forEach(val => events.push(val));
if(IO.Exists('webui/asset/config/flags.json')) {
let bufFlagConfig = await IO.ReadFile('webui/asset/config/flags.json')
let flagConfig = JSON.parse(bufFlagConfig.toString())
for(const flagIter in flagConfig) {
if(flagConfig[flagIter]['toggle']) events.push(flagConfig[flagIter]['str'])
}
}
courses = COURSES6;
EXTENDS6.forEach(val => extend.push(Object.assign({}, val)));
break;
}
}
let songs = [];
const gameVersion = getVersion(info);
let songNum = 2200;
if(gameVersion === 2) songNum = 554;
if(gameVersion === 3) songNum = 954;
if(gameVersion === 4) songNum = 1368;
if(U.GetConfig('unlock_all_songs')) {
console.log("Unlocking songs");
for (let i = 1; i < songNum; ++i) {
for (let j = 0; j < 5; ++j) {
songs.push({
music_id: K.ITEM('s32', i),
music_type: K.ITEM('u8', j),
limited: K.ITEM('u8', 3),
});
}
}
} else {
let mdb = JSON.parse(music_db.toString());
let limitedNo = 2;
songNum = parseInt(mdb.mdb.music[mdb.mdb.music.length - 1]['@id'])
console.log("Latest song id in mdb: " + songNum)
for (let i = 0; i <= songNum; i++) {
var foundSongIndex = mdb.mdb.music.map(function(x) {return x['@id']; }).indexOf(i.toString());
if(foundSongIndex != -1) {
var songData = mdb.mdb.music[foundSongIndex];
if(gameVersion === 6 || gameVersion === -6) {
if(parseInt(songData['info']['distribution_date']['#text']) > currentYMDDate) {
console.log("Unreleased song: " + songData.info.title_name)
}
else {
limitedNo = 2;
// if song is released during exceed gear
if(songData.info.version['#text'] === '6') {
// Songs are removed for multiple reasons, this will check whether to show or hide them (for songs released during EG)
if(REMOVED_SONGS6.includes(i.toString()) && !U.GetConfig('enable_removed_songs')) {
limitedNo -= 1;
}
// Licensed songs released in Exceed Gear needs limited=3 to appear
if(LICENSED_SONGS6.includes(i.toString())) {
limitedNo += 1;
}
else if(VALKYRIE_SONGS.includes(i.toString()) && (!U.GetConfig('enable_valk_songs') && info.model.split(":")[2].match(/^(G|H)$/g) == null)){
limitedNo -= 1;
}
for(let j = 0; j < 5; j++) {
songs.push({
music_id: K.ITEM('s32', i),
music_type: K.ITEM('u8', j),
limited: K.ITEM('u8', limitedNo),
});
}
}
// if song has new XCD track
else if (songData.info.inf_ver['#text'] === '6') {
songs.push({
music_id: K.ITEM('s32', i),
music_type: K.ITEM('u8', 3),
limited: K.ITEM('u8', limitedNo),
});
}
// Songs are removed for multiple reasons, this will check whether to show or hide them (for songs released before EG)
else if(REMOVED_SONGS6.includes(i.toString()) && !U.GetConfig('enable_removed_songs')) {
for(let j = 0; j < 5; j++) {
songs.push({
music_id: K.ITEM('s32', i),
music_type: K.ITEM('u8', j),
limited: K.ITEM('u8', 2),
});
}
}
}
}
}
}
}
if(U.GetConfig('use_information')){
console.log("Sending server information");
let time = new Date();
let tempDate = time.getDate();
const currentTime = parseInt((time.getTime()/100000) as unknown as string)*100;
extend.push({
id: 1,
type: 1,
params: [
1,
currentTime,
1,
1,
31,
'[f:0]SERVER INFORMATION',
'[sz:120] [olc:555555][ol:4][c:ff3333,3333ff,77ff77]Asphyxia\n'+
'[sz:75] CORE\n[sz:30]'+
'[sz:30][c:ffffff,888888] \n \n'+
' [c:00d5ff,888888]ASPHYXIA CORE'+CORE_VERSION+'\n'+
' [c:e5f3ff,a3d5ff]SDVX Plugin ver 6.0.0\n \n \n'+
'\n\n [f:0][c:ff3333,ffffff]FREE SOFTWARE. BEWARE OF SCAMMERS.\n'+
'[c:ffffff,888888] If you bought this software, request refund immediately.\n \n \n[/ol]'+
'[br:10][c:00FFFF][sz:50]メリー。。。クリスマス、です。。。'+
'\n \n \n \n[sz:32][c:560000,FC0000]DO NOT STREAM OR DISTRIBUTE THIS GAME IN PUBLIC',
//'[img:test]',
'',
'',
'',
],
});
}
else if(INFORMATION6[version.toString()] != undefined) {
console.log("Sending server information");
let time = new Date();
let tempDate = time.getDate();
const currentTime = parseInt((time.getTime()/100000) as unknown as string)*100;
for(const keyIter in INFORMATION6[version.toString()]) {
extend.push({
id: parseInt(keyIter) + 1,
type: 1,
params: [
1,
currentTime,
0,
0,
31,
'[f:0]SERVER INFORMATION',
INFORMATION6[version.toString()][keyIter],
'',
'',
'',
],
});
}
}
if(IO.Exists('webui/asset/config/events.json')) {
const itemTypeList = {"track": 'e', "appeal": 'a', "crew": 'c', "pcb": 'b', "prereq": "r"}
let bufEventData = await IO.ReadFile('webui/asset/json/events.json')
let bufEventConfig = await IO.ReadFile('webui/asset/config/events.json')
let eventData = JSON.parse(bufEventData.toString())
let eventConfig = JSON.parse(bufEventConfig.toString())
for(const eventIter in eventData['events']) {
let stmpEvntInfo = STAMP_EVENTS6[eventData['events'][eventIter]['id']]
if(eventData['events'][eventIter]['type'] === 'stamp' && eventConfig[eventData['events'][eventIter]['id']] !== undefined && eventConfig[eventData['events'][eventIter]['id']]['toggle']) {
for(const stmpDataIter in stmpEvntInfo['info']['data']) {
extend.push({
'type': 3,
'id': stmpEvntInfo['info']['data'][stmpDataIter]['stmpid'],
'params': [
5,
stmpEvntInfo['info']['data'][stmpDataIter]['stps'],
0,
stmpEvntInfo['info']['data'][stmpDataIter]['stps'],
0,
'',
stmpEvntInfo['info']['stmpHd'],
'',
stmpEvntInfo['info']['stmpFt'],
stmpEvntInfo['info']['data'][stmpDataIter]['stprwrd']
]
})
}
if(stmpEvntInfo['type'] === 'select') {
extend.push({
'type': 3,
'id': stmpEvntInfo['info']['id'],
'params': [
9,
(stmpEvntInfo['info']['textstampval'] !== undefined) ? stmpEvntInfo['info']['textstampval'] : 0,
0,
0,
0,
stmpEvntInfo['info']['sheet'],
'',
stmpEvntInfo['info']['stmpSlHd'],
stmpEvntInfo['info']['stmpSlFt'],
stmpEvntInfo['info']['stmpBg']
]
})
}
}
else if(eventData['events'][eventIter]['type'] === 'completestamp' && eventConfig[eventData['events'][eventIter]['id']] !== undefined && eventConfig[eventData['events'][eventIter]['id']]['toggle']) {
extend.push({
'type': 19,
'id': stmpEvntInfo['info']['id'],
'params': [
0, 0, 0, 0, 0,
JSON.stringify(stmpEvntInfo['info']['data']),
'',
'',
'',
''
]
})
}
else if(eventData['events'][eventIter]['type'] === 'tama' && eventConfig[eventData['events'][eventIter]['id']] !== undefined && eventConfig[eventData['events'][eventIter]['id']]['toggle']) {
events.push('TAMAADV_ENABLE')
extend.push({
'type': 20,
'id': stmpEvntInfo['info']['id'],
'params': [
0, 0, 0, 0, 0,
(U.GetConfig('tama_track_lib') ? '0,' : '') + stmpEvntInfo['info']['list'],
'',
'',
'',
''
]
})
}
}
}
if(IO.Exists('handlers/test.json')) {
let bufTest = await IO.ReadFile('handlers/test.json')
let extendTest = JSON.parse(bufTest.toString())
for(const ex in extendTest) {
extend.push({
'type': extendTest[ex]['type'],
'id': extendTest[ex]['id'],
'params': extendTest[ex]['params']
})
}
}
if(U.GetConfig('use_asphyxia_gameover')){
let time = new Date();
let tempDate = time.getDate();
const currentTime = parseInt((time.getTime()/100000) as unknown as string)*100;
let rightCharater = [
"go_bansui","go_bof","go_cannon","go_chinema","go_chocopla",
"go_dd","go_ekusa","go_esp","go_flowry","go_fukuryu",
"go_gorilla","go_grace","go_grace_rori","go_grace_ver06","go_haelequin",
"go_haruka","go_joyeuse","go_kino","go_kisa","go_mai",
"go_makina","go_makishima","go_left","go_makishima_ver06","go_mitsuru","go_miyako",
"go_nana","go_natsuhi","go_noisia","go_left_ver06","go_ondine","go_pannakotta",
"go_psychoholic","go_rain","go_rain02","go_ribbon","go_right",
"go_riot","go_rishna","go_rouge","go_sakurako","go_satan",
"go_tama","go_torako","go_vela","go_vertex","go_wabutan",
"go_wanlove","go_yusya",
];
let leftCharater = [
"go_akane","go_apex4sis","go_candy","go_capsaicin","go_chikage",
"go_evileye","go_fluorine","go_gangara","go_gin","go_hero",
"go_hiryubiren","go_hiyuki","go_hotaru","go_inoten","go_kamito",
"go_kanade","go_kemuri","go_kokona","go_konoha","go_kouki",
"go_kureha","go_left_bag","go_madholic",
"go_mimiko","go_mion","go_mitsuruco","go_nathanael","go_nishinippori",
"go_ortlinde","go_pico","go_pilica","go_profession","go_rasis",
"go_rasis_ver06","go_right_ver06","go_rimuru","go_rowa","go_saigawara",
"go_setu","go_shelly","go_soul","go_tamaneko","go_toraipuru",
"go_tsubaki","go_tsumabuki","go_tsumabuki_ver06","go_yuki","go_yukito",
];
let middleCharater = ["go_cat","go_cawoashi","go_iruyoru","go_neno",];
// Pattern 1 Left Right Left
// Pattern 2 Right Left Right
// Pattern 3 Right Middle Left
// Pattern 4 Left Middle Right
// switch(getVersion(info)){
// case 5:{
// break;
// }
// case 6:{
// rightCharater.push();
// leftCharater.push();
// break;
// }
// }
var charaString = "characters: ";
let pattern = getRandomIntInclusive(1,4);
switch(pattern){
case 1:{
var chara1 = leftCharater[getRandomIntInclusive(0,leftCharater.length-1)];
var chara2 = rightCharater[getRandomIntInclusive(0,rightCharater.length-1)];
var chara3 = leftCharater[getRandomIntInclusive(0,leftCharater.length-1)];
charaString += "chara01/"+chara1+" chara02/"+chara2+" chara01/"+chara3;
break;
}
case 2:{
var chara1 = rightCharater[getRandomIntInclusive(0,rightCharater.length-1)];
var chara2 = leftCharater[getRandomIntInclusive(0,leftCharater.length-1)];
var chara3 = rightCharater[getRandomIntInclusive(0,rightCharater.length-1)];
charaString += "chara02/"+chara1+" chara01/"+chara2+" chara02/"+chara3;
break;
}
case 3:{
var chara1 = rightCharater[getRandomIntInclusive(0,rightCharater.length-1)];
var chara2 = middleCharater[getRandomIntInclusive(0,middleCharater.length-1)]
var chara3 = leftCharater[getRandomIntInclusive(0,leftCharater.length-1)];
charaString += "chara02/"+chara1+" chara03/"+chara2+" chara01/"+chara3;
break;
}
case 4:{
var chara1 = leftCharater[getRandomIntInclusive(0,leftCharater.length-1)];
var chara2 = middleCharater[getRandomIntInclusive(0,middleCharater.length-1)];
var chara3 = rightCharater[getRandomIntInclusive(0,rightCharater.length-1)];
charaString += "chara01/"+chara1+" chara03/"+chara2+" chara02/"+chara3;
break;
}
}
if(Math.abs(getVersion(info)) == 6){//Due to older version misses newer characters, not supported on older versions
extend.push({
id: 3,
type: 1,
params: [
3,
currentTime,
0,
60,
0,
'[GAMEOVER]',
'[ol:6][olc:FFFFFF][ds:4][dsc:000000][sz:32][c:99FF00A8]Thank You For Using Asphyxia CORE!!!',
'[ol:6][olc:FFFFFF][ds:4][dsc:000000][sz:32][c:990D46F2]For more information please visit our Discord!',
'[ol:6][olc:FFFFFF][ds:4][dsc:000000][sz:32][c:99ED4F39]Nice Play!!!',
//'characters: chara01/go_rasis_ver06 chara02/go_left_ver06 chara01/go_right_ver06',
charaString,
],
});
}
}
console.log("Sending common objects");
let arena_szn = U.GetConfig('arena_szn')
let arena_catalog_items = []
if(arena_szn !== 'None') {
arena_catalog_items = ARENA[arena_szn].arena_items.map(item => ({
catalog_id: K.ITEM('s32', item.catalog_id),
catalog_type: K.ITEM('s32', item.catalog_type),
price: K.ITEM('s32', item.price),
item_type: K.ITEM('s32', item.item_type),
item_id: K.ITEM('s32', item.item_id),
param: K.ITEM('s32', item.param),
}))
}
let valgene_info = []
let valgene_items = []
valgene_info = VALGENE.info.map(val => ({
valgene_name: K.ITEM('str', val.valgene_name),
valgene_name_english: K.ITEM('str', val.valgene_name_english),
valgene_id: K.ITEM('s32', val.valgene_id)
}))
VALGENE.catalog.forEach((val) => {
val.items.forEach((itemVal) => {
itemVal.item_ids.forEach((item_id) => {
valgene_items.push({
valgene_id: K.ITEM('s32', val.volume),
rarity: K.ITEM('s32', VALGENE.rarity[itemVal.type.toString()]),
item_type: K.ITEM('s32', itemVal.type),
item_id: K.ITEM('s32', item_id)
})
})
})
})
if(currentDate.substring(0,4) === '4/1/' || U.GetConfig('april_fools')) {
console.log('Using April Fools Event')
events.push('APRIL_GRACE');
events.push('EVENTDATE_APRILFOOL');
for (const afsong in APRILFOOLSSONGS) {
for (let j = 0; j < 5; ++j) {
songs.push({
music_id: K.ITEM('s32', parseInt(APRILFOOLSSONGS[afsong])),
music_type: K.ITEM('u8', j),
limited: K.ITEM('u8', 3),
});
}
}
}
send.object(
{
valgene: {
info: valgene_info,
catalog: valgene_items
},
arena: (arena_szn !== 'None') ? {
season: K.ITEM('s32', ARENA[arena_szn].details.season),
rule: K.ITEM('s32', ARENA[arena_szn].details.rule),
rank_match_target: K.ITEM('s32', ARENA[arena_szn].details.rank_match_target),
time_start: K.ITEM('u64', ARENA[arena_szn].details.time_start),
time_end: K.ITEM('u64', ARENA[arena_szn].details.time_end),
shop_start: K.ITEM('u64', ARENA[arena_szn].details.shop_start),
shop_end: K.ITEM('u64', ARENA[arena_szn].details.shop_end),
is_open: K.ITEM('bool', ARENA[arena_szn].details.is_open),
is_shop: K.ITEM('bool', ARENA[arena_szn].details.is_shop),
catalog: arena_catalog_items
} : {},
event: {
info: events.map(e => ({
event_id: K.ITEM('str', e),
})),
},
extend: {
info: extend.map(e => ({
extend_id: K.ITEM('u32', e.id),
extend_type: K.ITEM('u32', e.type),
param_num_1: K.ITEM('s32', e.params[0]),
param_num_2: K.ITEM('s32', e.params[1]),
param_num_3: K.ITEM('s32', e.params[2]),
param_num_4: K.ITEM('s32', e.params[3]),
param_num_5: K.ITEM('s32', e.params[4]),
param_str_1: K.ITEM('str', e.params[5]),
param_str_2: K.ITEM('str', e.params[6]),
param_str_3: K.ITEM('str', e.params[7]),
param_str_4: K.ITEM('str', e.params[8]),
param_str_5: K.ITEM('str', e.params[9]),
})),
},
music_limited: { info: songs },
skill_course: {
info: courses.reduce(
(acc, s) => {
let courseData = s.courses.map(c => ({
season_id: K.ITEM('s32', s.id),
season_name: K.ITEM('str', s.name),
season_new_flg: K.ITEM('bool', s.isNew),
course_type: K.ITEM('s16', c.type),
course_id: K.ITEM('s16', c.id),
course_name: K.ITEM('str', c.name),
skill_level: K.ITEM('s16', c.level),
skill_type: K.ITEM('s16', 0),
skill_name_id: K.ITEM('s16', c.nameID),
matching_assist: K.ITEM('bool', c.assist),
clear_rate: K.ITEM('s32', 5000),
avg_score: K.ITEM('u32', 15000000),
track: c.tracks.map(t => ({
track_no: K.ITEM('s16', t.no),
music_id: K.ITEM('s32', t.mid),
music_type: K.ITEM('s8', t.mty),
})),
}))
acc = acc.concat(courseData)
if((info.model.split(":")[2] === 'G' || info.model.split(":")[2] === 'H') && s.hasGod !== undefined && s.hasGod === 1) {
courseData = courseData.concat(
s.courses.map(c => ({
season_id: K.ITEM('s32', s.id),
season_name: K.ITEM('str', s.name),
season_new_flg: K.ITEM('bool', s.isNew),
course_type: K.ITEM('s16', c.type),
course_id: K.ITEM('s16', c.id),
course_name: K.ITEM('str', c.name),
skill_level: K.ITEM('s16', c.level),
skill_type: K.ITEM('s16', s.hasGod),
skill_name_id: K.ITEM('s16', c.nameID),
matching_assist: K.ITEM('bool', c.assist),
clear_rate: K.ITEM('s32', 5000),
avg_score: K.ITEM('u32', 15000000),
track: c.tracks.map(t => ({
track_no: K.ITEM('s16', t.no),
music_id: K.ITEM('s32', t.mid),
music_type: K.ITEM('s8', t.mty),
})),
}))
)
acc = acc.concat(courseData)
}
return acc
},
[]
),
},
},
{ encoding: 'utf8' }
);
} catch (error) {
console.log(error)
}
};
export const log: EPR = async (info, data, send) => {
send.success();
}
+260
View File
@@ -0,0 +1,260 @@
import { Profile } from '../models/profile';
import { MusicRecord } from '../models/music_record';
import { Matchmaker } from '../models/matchmaker';
import { getVersion, IDToCode, GetCounter } from '../utils';
import { Mix } from '../models/mix';
import { Rival } from '../models/rival';
export const hiscore: EPR = async (info, data, send) => {
const records = await DB.Find<MusicRecord>(null, { collection: 'music' });
const version = getVersion(info);
const profiles = _.groupBy(
await DB.Find<Profile>(null, { collection: 'profile' }),
'__refid'
);
if (version === 1) {
return send.object({
hiscore: K.ATTR({ type: "1" }, {
music: _.map(
_.groupBy(records, r => {
return `${r.mid}:${r.type}`;
}),
r => _.maxBy(r, 'score')
).map(r => (K.ATTR({ id: String(r.mid) }, {
note: (() => {
const notes = [];
for (let i = 1; i <= 3; i++) {
if (r.type !== i) continue;
notes.push(K.ATTR({ type: String(r.type) }, {
name: K.ITEM('str', profiles[r.__refid][0].name),
score: K.ITEM('u32', r.score)
}))
}
return notes;
})()
}))),
})
})
}
return send.object({
sc: {
d: _.map(
_.groupBy(records, r => {
return `${r.mid}:${r.type}`;
}),
r => _.maxBy(r, 'score')
).map(r => ({
id: K.ITEM('u32', r.mid),
ty: K.ITEM('u32', r.type),
a_sq: K.ITEM('str', IDToCode(profiles[r.__refid][0].id)),
a_nm: K.ITEM('str', profiles[r.__refid][0].name),
a_sc: K.ITEM('u32', r.score),
l_sq: K.ITEM('str', IDToCode(profiles[r.__refid][0].id)),
l_nm: K.ITEM('str', profiles[r.__refid][0].name),
l_sc: K.ITEM('u32', r.score),
})),
},
});
};
export const rival: EPR = async (info, data, send) => {
const refid = $(data).str('refid');
const version = parseInt(info.model.split(":")[4]);
if (!refid) return send.deny();
const rivals = (
await DB.Find<Rival>(refid, { collection: 'rival', mutual: true })
).filter(p => p.refid != refid);
return send.object({
rival: await Promise.all(
rivals.map(async (p, index) => {
return {
no: K.ITEM('s16', index),
seq: K.ITEM('str', IDToCode(p.sdvxID)),
name: K.ITEM('str', p.name),
music: (
await DB.Find<MusicRecord>(p.refid, { collection: 'music' })
).map(r => ({
// Changes were somehow made in the order of the field for the version 2023042500
param: K.ARRAY('u32', version < 2023042500 ? [r.mid, r.type, r.score, r.clear, r.grade] : [r.mid, r.type, r.score, r.exscore, r.clear, r.grade]),
})),
};
})
),
});
};
export const saveMix: EPR = async (info, data, send) => {
const refid = $(data).str('ref_id');
if (!refid) return send.deny();
const profile = await DB.FindOne<Profile>(refid, { collection: 'profile' });
if (!profile) return send.deny();
const mix = $(data).element('automation');
const id = await GetCounter('mix');
let code = _.padStart(_.random(0, 999999999999).toString(), 12, '0');
while (await DB.FindOne<Mix>({ collection: 'mix', code })) {
code = _.padStart(_.random(0, 999999999999).toString(), 12, '0');
}
const doc = await DB.Insert<Mix>({
collection: 'mix',
id,
code,
name: mix.str('mix_name'),
creator: profile.name,
param: mix.str('generate_param'),
tag: mix.number('tag_bit'),
jacket: mix.number('jacket_id'),
});
return send.object({
automation: {
mix_id: K.ITEM('s32', id),
mix_code: K.ITEM('str', doc.code),
seq: K.ITEM('str', doc.code),
mix_name: K.ITEM('str', doc.name),
player_name: K.ITEM('str', doc.creator),
generate_param: K.ITEM('str', doc.param),
distribution_date: K.ITEM('u32', 19990101),
jacket_id: K.ITEM('s32', doc.jacket),
tag_bit: K.ITEM('s32', doc.tag),
like_flg: K.ITEM('bool', 0),
},
});
};
export const loadMix: EPR = async (info, data, send) => {
const code = $(data).str('mix_code');
const mix = await DB.FindOne<Mix>({ collection: 'mix', code });
if (!mix) {
return send.object({ result: K.ITEM('s32', 1) });
}
return send.object({
automation: {
mix_id: K.ITEM('s32', mix.id),
mix_code: K.ITEM('str', mix.code),
seq: K.ITEM('str', mix.code),
mix_name: K.ITEM('str', mix.name),
player_name: K.ITEM('str', mix.creator),
generate_param: K.ITEM('str', mix.param),
distribution_date: K.ITEM('u32', 19990101),
jacket_id: K.ITEM('s32', mix.jacket),
tag_bit: K.ITEM('s32', mix.tag),
like_flg: K.ITEM('bool', 0),
},
});
};
export const entryE: EPR = async (info, data, send) => {
console.log("entry_e id: " + $(data).number('eid'))
send.success()
}
export const globalMatch: EPR = async (info, data, send) => {
let entryData: Matchmaker = {
collection: 'matchmaker',
timestamp: Date.now(),
c_ver: $(data).number('c_ver'),
p_num: $(data).number('p_num'),
p_rest: $(data).number('p_rest'),
filter: $(data).number('filter'),
mid: $(data).number('mid'),
sec: $(data).number('sec'),
port: $(data).number('port'),
gip: $(data).numbers('gip'),
lip: $(data).numbers('lip'),
claim: $(data).number('claim'),
entry_id: $(data).number('entry_id')
}
let loggip = entryData.gip.join(".")
let loglip = entryData.lip.join(".")
console.log("====================================")
// console.log(" c_ver: " + entryData.c_ver)
// console.log(" p_num: " + entryData.p_num) // current match player count
// console.log(" p_rest: " + entryData.p_rest) // remaining player spaces
// console.log(" filter: " + entryData.filter) // game mode matchmaking filter
// console.log(" mid: " + entryData.mid)
// console.log(" sec: " + entryData.sec) // remaining seconds
// console.log(" port: " + entryData.port)
// console.log(" gip: " + entryData.gip)
// console.log(" lip: " + entryData.lip)
// console.log(" claim: " + entryData.claim)
// console.log("entry_id: " + entryData.entry_id)
console.log("[" + loglip + " | " + loggip + "] Searching for online match opponents")
let expCnt = await DB.Remove({collection: 'matchmaker', timestamp: {$lt: Date.now() - 100000}})
console.log("[" + loglip + " | " + loggip + "] Removed " + expCnt + " expired match data.")
if(await DB.Count({collection: 'matchmaker', lip: entryData.lip}) === 0) {
console.log("[" + loglip + " | " + loggip + "] Adding your info.")
await DB.Upsert<Matchmaker>(
{ collection: 'matchmaker', gip: entryData.gip, lip: entryData.lip},
entryData
)
} else {
console.log("[" + loglip + " | " + loggip + "] Updating info.")
await DB.Upsert<Matchmaker>(
{ collection: 'matchmaker', gip: entryData.gip, lip: entryData.lip},
{ $set: {
c_ver: entryData.c_ver,
p_num: entryData.p_num,
p_rest: entryData.p_rest,
filter: entryData.filter,
mid: entryData.mid,
sec: entryData.sec,
claim: entryData.claim
}
}
)
}
if(entryData.p_rest < 1) {
console.log("[" + loglip + " | " + loggip + "] Room is full. Halting.")
return send.deny();
}
console.log("[" + loglip + " | " + loggip + "] Searching...")
let opData = await DB.Find<Matchmaker>({collection: 'matchmaker', filter: entryData.filter, mid: entryData.mid, claim: entryData.claim, entry_id: entryData.entry_id})
let opponents = {
entry_id: K.ITEM('u32', entryData.entry_id),
entry: opData.map(e => ({
port: K.ITEM('u16', e.port),
gip: K.ITEM('4u8', e.gip),
lip: K.ITEM('4u8', e.lip)
}))
}
console.log("[" + loglip + " | " + loggip + "] Players found: " + (opponents.entry.length - 1) + "")
if(opponents.entry.length === 1) send.deny()
else send.object(opponents)
}
export const lounge: EPR = async (info, data, send) => {
let filter = $(data).number('filter')
await DB.Remove({collection: 'matchmaker', timestamp: {$lt: Date.now() - 100000}})
let matches = await DB.Find<Matchmaker>({collection: 'matchmaker', filter: filter})
if(matches.length < 1) {
send.object({
interval: K.ITEM('u32', 5)
})
} else {
let longestWait = Math.max(...matches.map(m => m.sec))
send.object({
interval: K.ITEM('u32', 10),
wait: K.ITEM('u32', longestWait)
})
}
}
+1003
View File
File diff suppressed because it is too large Load Diff
+821
View File
@@ -0,0 +1,821 @@
import { Profile } from '../models/profile';
import { MusicRecord } from '../models/music_record';
import { ValgeneTicket } from '../models/valgene_ticket';
import { Skill } from '../models/skill';
import { getVersion, IDToCode, GetCounter } from '../utils';
import { Mix } from '../models/mix';
import { Rival } from '../models/rival';
import { PREGENE, COURSES6} from '../data/exg';
import { textureslist } from '../data/webui'
import * as fs from 'fs';
import { PNG } from '../webui/asset/js/pngjs/png.js';
export const updateProfile = async (data: {
refid: string;
name?: string;
appeal?: string;
akaname?: string;
bplSupport?: string;
nemsys?: string;
bgm?: string;
subbg?: string;
stampA?: string;
stampB?: string;
stampC?: string;
stampD?: string;
stampRA?: string;
stampRB?: string;
stampRC?: string;
stampRD?: string;
sysBG?: string;
valgeneTicket?: string;
skilltitle?: string;
creatorItem?: string;
}) => {
if (data.refid == null) return;
const update: Update<Profile>['$set'] = {};
if (data.name && data.name.length > 0) {
const validName = data.name
.toUpperCase()
.replace(/[^ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!?#$&*\-\.\ ]/g, '')
.slice(0, 8);
if (validName.length > 0) update.name = validName;
}
if (data.appeal && data.appeal.length > 0) {
const validAppeal = parseInt(data.appeal);
if (!_.isNaN(validAppeal)) update.appeal = validAppeal;
}
if (data.akaname && data.akaname.length > 0) {
const validAka = parseInt(data.akaname);
if (!_.isNaN(validAka)) update.akaname = validAka;
}
if (data.nemsys && data.nemsys.length > 0) {
const validNemsys = parseInt(data.nemsys);
if (!_.isNaN(validNemsys)) update.nemsys = validNemsys;
}
if (data.bplSupport && data.bplSupport.length > 0) {
const validBplSupport = parseInt(data.bplSupport);
if (!_.isNaN(validBplSupport)) update.bplSupport = validBplSupport;
}
if (data.subbg && data.subbg.length > 0) {
const validSubbg = parseInt(data.subbg);
if (!_.isNaN(validSubbg)) update.subbg = validSubbg;
}
if (data.bgm && data.bgm.length > 0) {
const validBGM = parseInt(data.bgm);
if (!_.isNaN(validBGM)) update.bgm = validBGM;
}
if (data.stampA && data.stampA.length > 0) {
const validStampA = parseInt(data.stampA);
if (!_.isNaN(validStampA)) update.stampA = validStampA;
}
if (data.stampB && data.stampB.length > 0) {
const validStampB = parseInt(data.stampB);
if (!_.isNaN(validStampB)) update.stampB = validStampB;
}
if (data.stampC && data.stampC.length > 0) {
const validStampC = parseInt(data.stampC);
if (!_.isNaN(validStampC)) update.stampC = validStampC;
}
if (data.stampD && data.stampD.length > 0) {
const validStampD = parseInt(data.stampD);
if (!_.isNaN(validStampD)) update.stampD = validStampD;
}
if (data.stampRA && data.stampRA.length > 0) {
const validStampRA = parseInt(data.stampRA);
if (!_.isNaN(validStampRA)) update.stampRA = validStampRA;
}
if (data.stampRB && data.stampRB.length > 0) {
const validStampRB = parseInt(data.stampRB);
if (!_.isNaN(validStampRB)) update.stampRB = validStampRB;
}
if (data.stampRC && data.stampRC.length > 0) {
const validStampRC = parseInt(data.stampRC);
if (!_.isNaN(validStampRC)) update.stampRC = validStampRC;
}
if (data.stampRD && data.stampRD.length > 0) {
const validStampRD = parseInt(data.stampRD);
if (!_.isNaN(validStampRD)) update.stampRD = validStampRD;
}
if (data.sysBG && data.sysBG.length > 0) {
const validSysBG = parseInt(data.sysBG);
if (!_.isNaN(validSysBG)) update.sysBG = validSysBG;
}
if (data.creatorItem && data.creatorItem.length > 0) {
const validCreatorItem = parseInt(data.creatorItem);
if (!_.isNaN(validCreatorItem)) update.creatorItem = validCreatorItem;
}
await DB.Update<Profile>(
data.refid,
{ collection: 'profile' },
{ $set: update }
);
if (parseInt(data.skilltitle) >= 0) {
await DB.Update<Skill>(
data.refid,
{ collection: 'skill' },
{ $set: {
name: parseInt(data.skilltitle)
}
}
);
}
if (parseInt(data.valgeneTicket) >= 0) {
await DB.Upsert<ValgeneTicket>(
data.refid,
{ collection: 'valgene_ticket' },
{ $set: {
ticketNum: parseInt(data.valgeneTicket),
limitDate: Date.parse('31 Dec 2099 23:59:59 GMT')
}
}
);
}
};
export const updateMix = async (data: {
code: string;
name?: string;
creator?: string;
}) => {
const update: Update<Mix>['$set'] = {};
if (data.name && data.name.length > 0) {
if (data.name.length > 0) update.name = data.name;
}
if (data.creator && data.creator.length > 0) {
// const validCreator = data.creator
// .toUpperCase()
// .replace(/[^ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!?#$&*\-\.\ ]/g, '')
// .slice(0, 8);
if (data.creator.length > 0) update.creator = data.creator;
}
await DB.Update<Mix>(
{ collection: 'mix', code: data.code },
{ $set: update }
);
};
export const importMix = async (data: { json: string }) => {
if (data.json.startsWith('`')) {
data.json = data.json.slice(1);
}
if (data.json.endsWith('`')) {
data.json = data.json.slice(0, data.json.length - 1);
}
const mix: any[] = JSON.parse(data.json);
let code = mix[0];
while (await DB.FindOne<Mix>({ collection: 'mix', code })) {
code = _.padStart(_.random(0, 999999999999).toString(), 12, '0');
}
const id = await GetCounter('mix');
const musics = mix.slice(9);
if (musics.length % 2 !== 0) return;
const mdata = [];
for (let i = 0; i < musics.length; i += 2) {
mdata.push({
grade: musics[i + 1],
id: musics[i],
});
}
await DB.Insert<Mix>({
collection: 'mix',
code,
id,
name: mix[1],
creator: mix[2],
param: `{ "dbVer" : "${mix[3]
}", "gene" : { "params" : "{ \\"minorVer\\" : \\"${mix[4]
}\\", \\"seed\\" : ${mix[5]} }", "ver" : "${mix[6]
}" }, "musics" : ${JSON.stringify(mdata)}, "voxdj" : { "params" : "${mix[7]
}", "ver" : "${mix[8]}" } }`,
jacket: 0,
tag: 1,
});
};
export const deleteMix = async (data: { code: string }) => {
await DB.Remove<Mix>({ collection: 'mix', code: data.code });
};
export const copyResourcesFromGame = async (data: {}, send: WebUISend) => {
let mdbJsonFix = [];
let mdbJsonFixFinal;
let newJsonSongs = [];
let newVersionSongs = [];
let newXCDSongs = [];
let newNemsysData = []
let newAPCardData = []
let newSubBGData = []
let newBGMData = []
let newChatStampData = []
let newValgeneItemFiles = []
let newAkanames = []
let runErrors = []
let resourceJsonData = JSON.parse(U.DecodeString(await IO.ReadFile('webui/asset/json/data.json'), 'utf8'))
let apCardJsonData = JSON.parse(U.DecodeString(await IO.ReadFile('webui/asset/json/appeal.json'), 'utf8'))
// Get new music data from music_db.xml
console.log('Getting new music_db info')
if(IO.Exists(U.GetConfig('sdvx_eg_root_dir') + "/data/others/music_db.xml")) {
let ea3Config = []
let version = ''
let mdb = U.parseXML(U.DecodeString(await IO.ReadFile(U.GetConfig('sdvx_eg_root_dir') + "/data/others/music_db.xml"), "shift_jis"), false)
if(IO.Exists(U.GetConfig('sdvx_eg_root_dir') + "/prop/ea3-config.xml")) {
console.log("Reading ea3-config.xml")
ea3Config = U.parseXML(U.DecodeString(await IO.ReadFile(U.GetConfig('sdvx_eg_root_dir') + "/prop/ea3-config.xml"), "shift_jis"), false)
version = ea3Config['ea3']['soft']['ext']['@content'];
} else if(IO.Exists(U.GetConfig('sdvx_eg_root_dir') + "/prop/ea3-ident.xml")) {
console.log("Reading ea3-ident.xml")
ea3Config = U.parseXML(U.DecodeString(await IO.ReadFile(U.GetConfig('sdvx_eg_root_dir') + "/prop/ea3-ident.xml"), "shift_jis"), false)
version = ea3Config['ea3_conf']['soft']['ext']['@content'];
}
let prevAssetMdb = []
if(IO.Exists('webui/asset/json/music_db.json')) {
prevAssetMdb = JSON.parse(U.DecodeString(await IO.ReadFile('webui/asset/json/music_db.json'), 'utf8'))
}
mdb.mdb.music.forEach(musicValue => {
if(Object.keys(prevAssetMdb).length > 0) {
if(prevAssetMdb['mdb']['music'].find(item => parseInt(item['@id']) == parseInt(musicValue['@attr'].id)) == undefined) {
console.log("New song added to json: " + musicValue.info.title_name['@content'] + " (" + musicValue.info.distribution_date['@content'] + ")")
newJsonSongs.push([ musicValue['@attr'].id, '[' + musicValue.info.distribution_date['@content'] + ' | ' + musicValue['@attr'].id + '] ' + musicValue.info.title_name['@content']])
}
if(prevAssetMdb['mdb']['music'].find(item => (parseInt(item['@id']) == parseInt(musicValue['@attr'].id) && parseInt(item['info']['inf_ver']['#text']) === 0)) != undefined) {
if(musicValue.info.inf_ver['@content'] == '6') {
console.log("New XCD difficulty song: " + musicValue.info.title_name['@content'] + " (" + musicValue.info.distribution_date['@content'] + ")")
newXCDSongs.push([ musicValue['@attr'].id, '[' + musicValue.info.distribution_date['@content'] + ' | ' + musicValue['@attr'].id + '] ' + musicValue.info.title_name['@content']])
}
}
} else {
console.log("New song added to json: " + musicValue.info.title_name['@content'] + " (" + musicValue.info.distribution_date['@content'] + ")")
newJsonSongs.push([ musicValue['@attr'].id, '[' + musicValue.info.distribution_date['@content'] + ' | ' + musicValue['@attr'].id + '] ' + musicValue.info.title_name['@content']])
if(musicValue.info.inf_ver['@content'] == '6') {
console.log("New XCD difficulty song: " + musicValue.info.title_name['@content'] + " (" + musicValue.info.distribution_date['@content'] + ")")
newXCDSongs.push([ musicValue['@attr'].id, '[' + musicValue.info.distribution_date['@content'] + ' | ' + musicValue['@attr'].id + '] ' + musicValue.info.title_name['@content']])
}
}
if(parseInt(musicValue.info.distribution_date['@content'][0]) >= parseInt(version.substring(0,8))) {
console.log("Found new song for version " + version + ": " + musicValue.info.title_name['@content'] + " (" + musicValue.info.distribution_date['@content'] + ")");
newVersionSongs.push([ musicValue['@attr'].id, '[' + musicValue.info.distribution_date['@content'] + ' | ' + musicValue['@attr'].id + '] ' + musicValue.info.title_name['@content']])
}
mdbJsonFix.push({
'@id': musicValue['@attr'].id,
'info': {
'title_name': musicValue.info.title_name['@content'],
'version': {
'@__type': 'u8',
'#text': musicValue.info.version['@content'][0].toString()
},
'inf_ver': {
'@__type': 'u8',
'#text': musicValue.info.inf_ver['@content'][0].toString()
},
'distribution_date' : {
'#text': musicValue.info.distribution_date['@content'][0]
}
},
'difficulty': {
'novice': {
'difnum': {
'@__type': 'u8',
'#text': musicValue.difficulty.novice.difnum['@content'][0].toString()
}
},
'advanced': {
'difnum': {
'@__type': 'u8',
'#text': musicValue.difficulty.advanced.difnum['@content'][0].toString()
}
},
'exhaust': {
'difnum': {
'@__type': 'u8',
'#text': musicValue.difficulty.exhaust.difnum['@content'][0].toString()
}
},
'maximum': {
'difnum': {
'@__type': 'u8',
'#text': musicValue.difficulty.maximum != undefined ? musicValue.difficulty.maximum.difnum['@content'][0].toString() : '0'
}
},
'infinite': {
'difnum': {
'@__type': 'u8',
'#text': musicValue.difficulty.infinite != undefined ? musicValue.difficulty.infinite.difnum['@content'][0].toString() : '0'
}
}
}
});
})
mdbJsonFixFinal = {
'mdb': {
'version': version,
'music': mdbJsonFix
}
};
IO.WriteFile('webui/asset/json/music_db.json', JSON.stringify(mdbJsonFixFinal, null, 4));
} else {
console.log('Error reading music_db.xml. Check your "Exceed Gear Data Directory" config.')
runErrors.push('[music_db] Error reading music_db.xml. Check your "Exceed Gear Data Directory" config.')
}
// Copying new nemsys files from gamedata
console.log("Copying new nemsys files from gamedata")
if(IO.Exists(U.GetConfig('sdvx_eg_root_dir') + "/data/graphics/game_nemsys")) {
let nemsysFiles = await IO.ReadDir(U.GetConfig('sdvx_eg_root_dir') + "/data/graphics/game_nemsys")
for await (const nemsys of nemsysFiles) {
let fileToWrite = await IO.ReadFile(U.GetConfig('sdvx_eg_root_dir') + "/data/graphics/game_nemsys/" + nemsys.name)
if(!IO.Exists('webui/asset/nemsys/' + nemsys.name.substring(0, (nemsys.name.length - 4)) + ".png") && !IO.Exists('webui/asset/nemsys/' + nemsys.name.substring(0, (nemsys.name.length - 4)) + ".jpg")) {
console.log("[nemsys] copying " + nemsys.name)
IO.WriteFile('webui/asset/nemsys/' + nemsys.name, fileToWrite)
newNemsysData.push(nemsys.name)
}
if(nemsys.name.match(/([0-9]+)/g) != undefined) {
let nemsysId = parseInt(nemsys.name.match(/([0-9]+)/g)[0])
if(nemsysId && ![8, 9, 10, 11].includes(nemsysId) && resourceJsonData.nemsys.find(nem => nem.value == nemsysId) == undefined) {
console.log("[nemsys] adding to json: " + nemsys.name)
resourceJsonData.nemsys.push({"value": nemsysId, "name": nemsys.name})
}
}
}
} else {
console.log('Error reading nemsys directory. Check your "Exceed Gear Data Directory" config.')
runErrors.push('[nemsys] Error reading nemsys directory. Check your "Exceed Gear Data Directory" config.')
}
// Copying new subbg files from gamedata
console.log("Copying new subbg files from gamedata")
if(IO.Exists(U.GetConfig('sdvx_eg_root_dir') + "/data/graphics/submonitor_bg")) {
let subBGFiles = await IO.ReadDir(U.GetConfig('sdvx_eg_root_dir') + "/data/graphics/submonitor_bg")
for await (const subbg of subBGFiles) {
if (subbg.name.match(/^(subbg[_0-9]*)(\.png|\.jpg|\.mp4)/g)) {
let fileToWrite = await IO.ReadFile(U.GetConfig('sdvx_eg_root_dir') + "/data/graphics/submonitor_bg/" + subbg.name)
if(!IO.Exists('webui/asset/submonitor_bg/' + subbg.name.substring(0, (subbg.name.length - 4)) + ".png") && !IO.Exists('webui/asset/submonitor_bg/' + subbg.name.substring(0, (subbg.name.length - 4)) + ".jpg") && !IO.Exists('webui/asset/submonitor_bg/' + subbg.name.substring(0, (subbg.name.length - 4)) + ".mp4")) {
console.log("[subbg] copying " + subbg.name)
IO.WriteFile('webui/asset/submonitor_bg/' + subbg.name, fileToWrite)
newSubBGData.push(subbg.name)
}
let subbgId = parseInt(subbg.name.match(/([0-9]+)/g)[0])
if(subbgId) {
let subbgName = subbg.name
let subbgType = 'normal'
let foundSubbg = resourceJsonData.subbg.findIndex(subbg => subbg.value === subbgId)
if(subbg.name.match(/(subbg_[0-9]+_[0-9]+)/g)) {
subbgName = subbg.name.match(/(subbg_[0-9]+)/g)[0]
subbgType = 'slideshow'
} else if(subbg.name.includes('.mp4')) subbgType = 'video'
if(foundSubbg == -1) {
console.log("[subbg] adding " + subbgId + " - " + subbgName + " (" + subbgType + ")")
resourceJsonData.subbg.push({"value": subbgId, "type": subbgType, "name": subbgName})
} else {
resourceJsonData.subbg[foundSubbg] = {"value": subbgId, "type": subbgType, "name": subbgName}
}
}
}
}
} else {
console.log('Error reading submonitor_bg directory. Check your "Exceed Gear Data Directory" config.')
runErrors.push('[submonitor_bg] Error reading submonitor_bg directory. Check your "Exceed Gear Data Directory" config.')
}
// Copying new bgm files from gamedata
console.log("Copying new bgm files from gamedata")
if(IO.Exists(U.GetConfig('sdvx_eg_root_dir') + "/data/sound/custom")) {
let bgmFiles = await IO.ReadDir(U.GetConfig('sdvx_eg_root_dir') + "/data/sound/custom")
for await (const bgm of bgmFiles) {
if (bgm.name.match(/(\.s3p)/g)) {
let folderName = bgm.name.match(/(custom|special)_([0-9]*)/g)[0]
if(folderName != '') {
if(!IO.Exists('webui/asset/audio/' + folderName)) {
console.log("[bgm] extracting audio files from " + bgm.name + ".")
// Thanks to mon/s3p_extract on GitHub.
let bufOffset = 4
let s3pBuffer = await IO.ReadFile(U.GetConfig('sdvx_eg_root_dir') + "/data/sound/custom/" + bgm.name, {flag: 'r'})
let fileMagic = s3pBuffer.toString('utf8', 0, 4)
let fileEntries = s3pBuffer.readInt32LE(bufOffset)
let entries = []
bufOffset += 4
for(let entryCtr = 0; entryCtr < fileEntries; entryCtr++) {
entries.push(
{
offset: s3pBuffer.readInt32LE(bufOffset),
length: s3pBuffer.readInt32LE(bufOffset + 4)
}
)
bufOffset += 8
}
let filename = 0
entries.forEach(entry => {
let magic = s3pBuffer.toString('utf8', entry.offset, entry.offset + 4)
let fileStart = s3pBuffer.readInt32LE(entry.offset + 4)
let arrayBuffer = s3pBuffer.buffer.slice(entry.offset, entry.offset + entry.length)
IO.WriteFile('webui/asset/audio/' + folderName + '/' + filename + '.wma', s3pBuffer.toString('binary', entry.offset + fileStart, entry.offset + entry.length), {encoding: 'binary'})
filename++
})
}
let bgmId = parseInt(bgm.name.match(/(?<=(custom|special)_)([0-9]*)/g)[0])
if(bgmId && resourceJsonData.bgm.find(bgm => bgm.value == bgmId) == undefined) {
console.log("[bgm] adding to json: " + bgmId + " - " + bgm.name)
newBGMData.push(bgm.name)
resourceJsonData.bgm.push({"value": bgmId, "name": bgm.name})
}
}
}
}
} else {
console.log('Error reading BGM directory. Check your "Exceed Gear Data Directory" config.')
runErrors.push('[BGM] Error reading BGM directory. Check your "Exceed Gear Data Directory" config.')
}
// Copying new chat stamps from gamedata
console.log("Copying new chat stamps from gamedata")
if(IO.Exists(U.GetConfig('sdvx_eg_root_dir') + "/data/others/chat_stamp.xml")) {
let chatStampData = U.parseXML(U.DecodeString(await IO.ReadFile(U.GetConfig('sdvx_eg_root_dir') + "/data/others/chat_stamp.xml"), "shift_jis"), false)
// console.log(JSON.stringify(chatStampData.chat_stamp_data))
for(const chatStamp of chatStampData.chat_stamp_data.info) {
if(resourceJsonData.stamp.find(stamp => stamp['value'] === chatStamp.id['@content'][0]) == undefined) {
let stampTitle = chatStamp.title['@content'] + " " + (parseInt(chatStamp.id['@content'][0]) % 4 !== 0 ? parseInt(chatStamp.id['@content'][0]) % 4 : 4)
console.log("[chat_stamp] " + chatStamp.id['@content'][0] + " - " + stampTitle)
resourceJsonData.stamp.push({"value": chatStamp.id['@content'][0], "name": stampTitle})
newChatStampData.push(chatStamp.id['@content'][0] + ": " + chatStamp.filename['@content'])
}
if(!IO.Exists('webui/asset/chat_stamp/' + chatStamp.filename['@content'] + '.png') && !IO.Exists('webui/asset/chat_stamp/' + chatStamp.filename['@content'] + '.png')) {
console.log("[chat_stamp] copying " + chatStamp.filename['@content'] + '.png')
let fileToWrite = await IO.ReadFile(U.GetConfig('sdvx_eg_root_dir') + "/data/graphics/chat_stamp/" + chatStamp.filename['@content'] + ".png")
IO.WriteFile('webui/asset/chat_stamp/' + chatStamp.filename['@content'] + '.png', fileToWrite)
}
}
resourceJsonData.stamp.sort(function(a, b){return a.value - b.value})
} else {
console.log('Error reading chat stamp xml file. Check your "Exceed Gear Data Directory" config.')
runErrors.push('[chat stamp] Error reading chat stamp xml file. Check your "Exceed Gear Data Directory" config.')
}
// Copying new valgene_item files from gamedata
console.log("Copying new valgene_item files from gamedata")
if(IO.Exists(U.GetConfig('sdvx_eg_root_dir') + "/data/graphics/valgene_item")) {
let valgeneItemFiles = await IO.ReadDir(U.GetConfig('sdvx_eg_root_dir') + "/data/graphics/valgene_item")
for await (const valgeneItem of valgeneItemFiles) {
if (valgeneItem.name.substring(valgeneItem.name.length-4, valgeneItem.name.length).match(/(\.png|\.jpg)/g)) {
let fileToWrite = await IO.ReadFile(U.GetConfig('sdvx_eg_root_dir') + "/data/graphics/valgene_item/" + valgeneItem.name)
if(!IO.Exists('webui/asset/valgene_item/' + valgeneItem.name.substring(0, (valgeneItem.name.length - 4)) + ".png") && !IO.Exists('webui/asset/valgene_item/' + valgeneItem.name.substring(0, (valgeneItem.name.length - 4)) + ".jpg")) {
console.log("[valgene_item] copying " + valgeneItem.name)
IO.WriteFile('webui/asset/valgene_item/' + valgeneItem.name, fileToWrite)
newValgeneItemFiles.push(valgeneItem.name)
}
}
}
} else {
console.log('Error reading valgene_item directory. Check your "Exceed Gear Data Directory" config.')
runErrors.push('[valgene_item] Error reading valgene_item directory. Check your "Exceed Gear Data Directory" config.')
}
// Copying new akanames from gamedata
console.log("Copying new appeal titles from gamedata")
// resourceJsonData.akaname = []
if(IO.Exists(U.GetConfig('sdvx_eg_root_dir') + "/data/others/akaname_parts.xml")) {
let akanameData = U.parseXML(U.DecodeString(await IO.ReadFile(U.GetConfig('sdvx_eg_root_dir') + "/data/others/akaname_parts.xml"), "shift_jis"), false)
for(const akaname of akanameData.akaname_parts.part) {
if(resourceJsonData.akaname.find(aka => aka.value === akaname['@attr'].id) === undefined) {
let akanameFmtd = ('@content' in akaname.word) ? akaname.word['@content'].replace(/(\[[A-z0-9:,\/\]]*)/g,'') : ''
console.log("[appeal title] adding " + akaname['@attr'].id + " - " + akanameFmtd)
resourceJsonData.akaname.push({"value": akaname['@attr'].id, "name": akanameFmtd})
newAkanames.push(akaname['@attr'].id + ": " + akanameFmtd )
}
}
resourceJsonData.akaname.sort(function(a, b){return parseInt(a.value) - parseInt(b.value)})
} else {
console.log('Error reading akaname xml file. Check your "Exceed Gear Data Directory" config.')
runErrors.push('[akaname] Error reading akaname xml file. Check your "Exceed Gear Data Directory" config.')
}
// Copying new appeal card data from gamedata
console.log("Copying new appeal card data from gamedata")
if(IO.Exists(U.GetConfig('sdvx_eg_root_dir') + "/data/others/appeal_card.xml")) {
let apCardData = U.parseXML(U.DecodeString(await IO.ReadFile(U.GetConfig('sdvx_eg_root_dir') + "/data/others/appeal_card.xml"), "shift_jis"), false)
for(const apCard of apCardData.appeal_card_data.card) {
if(apCardJsonData.appeal_card_data.card.find(ap => ap['@id'] === apCard['@attr'].id) == undefined) {
console.log("[ap_card] adding to json: " + apCard['@attr'].id + " - " + apCard.info['title']['@content'])
apCardJsonData.appeal_card_data.card.push({"@id": apCard['@attr'].id, "info": {"texture": apCard.info['texture']['@content'], "title": apCard.info['title']['@content']}})
newAPCardData.push(apCard['@attr'].id + ": " + apCard.info['texture']['@content'] + "(" + apCard.info['title']['@content'] + ")")
}
if(!IO.Exists('webui/asset/ap_card/' + apCard.info['texture']['@content'] + '.png') && !IO.Exists('webui/asset/ap_card/' + apCard.info['texture']['@content'] + '.jpg')) {
console.log("[ap_card] copying " + apCard.info['texture']['@content'] + '.png')
let fileToWrite = await IO.ReadFile(U.GetConfig('sdvx_eg_root_dir') + "/data/graphics/ap_card/" + apCard.info['texture']['@content'] + ".png")
IO.WriteFile('webui/asset/ap_card/' + apCard.info['texture']['@content'] + '.png', fileToWrite)
}
}
apCardJsonData.appeal_card_data.card.sort(function(a, b){return parseInt(a['@id']) - parseInt(b['@id'])})
} else {
console.log('Error reading appeal card xml file. Check your "Exceed Gear Data Directory" config.')
runErrors.push('[appeal card] Error reading appeal card xml file. Check your "Exceed Gear Data Directory" config.')
}
await IO.WriteFile('webui/asset/json/data.json', JSON.stringify(resourceJsonData, null, 4))
await IO.WriteFile('webui/asset/json/appeal.json', JSON.stringify(apCardJsonData, null, 4))
// Extract textures from ifs files using pngjs. Massive thanks to https://github.com/mon/ifstools
console.log("Extracting textures from IFS files")
let ifsSuccess = []
for(let listIter = 0; listIter < textureslist.length; listIter++) {
let manifestJson = {}
let bufOffset = 0
let magic = '6CAD8F89'
console.log(textureslist[listIter]['file'] + ":")
let ifsBuffer = await IO.ReadFile(U.GetConfig('sdvx_eg_root_dir') + textureslist[listIter].file, {flag: 'r'})
if(!fs.existsSync('plugins/sdvx@asphyxia/webui/asset/' + textureslist[listIter].asset_folder)) {
fs.mkdirSync('plugins/sdvx@asphyxia/webui/asset/' + textureslist[listIter].asset_folder)
}
let header = Buffer.from(ifsBuffer.buffer.slice(0, 36))
let sig = header.readUInt32BE().toString(16).toUpperCase()
bufOffset += 4
if(sig === magic) {
bufOffset += 12
let manifest_end = ifsBuffer.readUInt32BE(bufOffset)
bufOffset += 4
let md5_hash = ifsBuffer.toString('hex', bufOffset, bufOffset + 16)
bufOffset += 16
if(md5_hash === textureslist[listIter].md5) {
for(let texIter = 0; texIter < textureslist[listIter]['textures'].length; texIter++) {
let tdFileName = textureslist[listIter]['textures'][texIter][0]
let tdOffset = parseInt(textureslist[listIter]['textures'][texIter][1].toString())
let tdSize = parseInt(textureslist[listIter]['textures'][texIter][2].toString())
let tdUvrect = textureslist[listIter]['textures'][texIter][3]
let tdImgRect = textureslist[listIter]['textures'][texIter][4]
let imgBufferHead = Buffer.from(ifsBuffer.buffer.slice(manifest_end + tdOffset, manifest_end + tdOffset + 8))
let imgBufferHeadOff = 0
let imgBuffer = Buffer.from(ifsBuffer.buffer.slice(manifest_end + tdOffset + 8, manifest_end + tdOffset + tdSize))
let imgBufferOff = 0
let imgUncompressedSize = imgBufferHead.readUInt32BE(imgBufferHeadOff)
imgBufferHeadOff += 4
let imgCompressedSize = imgBufferHead.readUInt32BE(imgBufferHeadOff)
imgBufferHeadOff += 4
// Decompression algorithm & code from ifstools/handlers/lz77.py
let decompressed = []
let contLoop = true
let diff, flag, w, position, length
while(contLoop) {
flag = imgBuffer.readUInt8(imgBufferOff)
imgBufferOff++
for(let i = 0; i < 8; i++){
if (((flag >> i) & 1) === 1) {
decompressed.push(imgBuffer.readUInt8(imgBufferOff))
imgBufferOff++
}
else {
w = imgBuffer.readUInt16BE(imgBufferOff)
imgBufferOff+=2
position = (w >> 4)
length = (w & 0x0F) + 3
if(position === 0) {
contLoop = false
break;
}
if(position > decompressed.length) {
diff = 0
diff = position - decompressed.length
diff = Math.min(diff, length)
for(let e2p = 0; e2p < diff; e2p++) {
decompressed.push(0)
}
length -= diff
}
if (-position+length < 0) {
decompressed.push(...decompressed.slice(decompressed.length + (-position), decompressed.length + (-position+length)))
}
else {
for(let loop = 0; loop < length; loop++) {
decompressed.push(decompressed[decompressed.length + (-position)])
}
}
}
}
}
// Swap red and blue data (RGBA -> BGRA)
if(decompressed.length === imgUncompressedSize) {
for(let decCtr = 0; decCtr < decompressed.length; decCtr += 4) {
decompressed[decCtr + 2] = [decompressed[decCtr], decompressed[decCtr] = decompressed[decCtr + 2]][0];
}
let pngf = new PNG({
width: Math.floor(tdImgRect[1]/2) - Math.floor(tdImgRect[0]/2),
height: Math.floor(tdImgRect[3]/2) - Math.floor(tdImgRect[2]/2),
bitDepth: 8,
colorType: 6,
inputHasAlpha: true
})
pngf.data = Buffer.from(decompressed)
const outputStream = await fs.createWriteStream('plugins/sdvx@asphyxia/webui/asset/' + textureslist[listIter].asset_folder + '/' + tdFileName);
await pngf.pack().pipe(outputStream);
console.log(' - ' + tdFileName + ' created successfully.');
ifsSuccess.push(textureslist[listIter].file + ' - ' + tdFileName)
} else {
console.log("Decompression mismatch.")
runErrors.push('[ifs] decompression mismatch for ' + textureslist[listIter]['file'] + '/' + tdFileName)
}
}
} else {
console.log('MD5 mismatch.')
runErrors.push('[ifs] MD5 mismatch - ' + textureslist[listIter].file)
}
} else {
console.log('IFS file unsupported/invalid.')
runErrors.push('[ifs] IFS file "' + textureslist[listIter].file + '" unsupported/invalid.')
}
}
console.log("Updating course_data.json")
let courseDataUpdateSuccess = false
let courseData = JSON.parse(U.DecodeString(await IO.ReadFile('webui/asset/json/course_data.json'), 'utf8'))
for(let cIter = 0; cIter < courseData.courseData.length; cIter++) {
if(courseData.courseData[cIter].version === 6) {
courseData.courseData[cIter].info = COURSES6
courseDataUpdateSuccess = true
}
}
if(courseDataUpdateSuccess === false) runErrors.push('[course_data] Update unsuccessful.')
await IO.WriteFile('webui/asset/json/course_data.json', JSON.stringify(courseData, null, 4))
send.json(
{
status: 'ok',
course: courseDataUpdateSuccess,
ifs: ifsSuccess,
akaname: newAkanames,
nemsys: newNemsysData,
apCard: newAPCardData,
subbg: newSubBGData,
bgm: newBGMData,
chatStamp: newChatStampData,
valgeneItemFiles: newValgeneItemFiles,
versionSongs: newVersionSongs.sort((a, b) => a[0] - b[0]),
jsonSongs: newJsonSongs.sort((a, b) => a[0] - b[0]),
xcdSongs: newXCDSongs.sort((a, b) => a[0] - b[0]),
errors: runErrors
}
)
}
export const getRivalScores = async (data: { rivalId: string; refid: string; }, send: WebUISend) => {
let rival = await DB.FindOne<Rival>(data.refid, {collection: 'rival', refid: data.rivalId})
send.json({
rival: await DB.FindOne<Profile>(data.rivalId, {collection: 'profile'}),
yourScores: await DB.Find<MusicRecord>(data.refid, { collection: 'music' }),
rivalScores: await DB.Find<MusicRecord>(rival.refid, { collection: 'music' })
})
}
export const addRival = async (data: { rivalId: string; refid: string; }, send: WebUISend) => {
let you = await DB.FindOne<Profile>(data.refid, {collection: 'profile'})
let rival = await DB.FindOne<Profile>(data.rivalId, {collection: 'profile'})
let checkMutual = (await DB.Count<Rival>(data.rivalId, {collection: 'rival', refid: data.refid}) > 0)
if(await DB.Count<Rival>(data.refid, {collection: 'rival', refid: data.rivalId}) === 0) {
if(checkMutual) {
DB.Upsert(data.rivalId, {"collection": "rival", "sdvxID": you.id, "refid": data.refid, "name": you.name}, {$set: {"mutual": checkMutual}})
}
DB.Insert(data.refid, {"collection": "rival", "sdvxID": rival.id, "refid": data.rivalId, "name": rival.name, "mutual": checkMutual})
send.json({
"msg": "Successfully added profile to rival. In order for your rivals to appear in-game, they need to add you as their rival as well."
})
} else {
if(checkMutual) {
DB.Upsert(data.rivalId, {"collection": "rival", "sdvxID": you.id, "refid": data.refid, "name": you.name}, {$set: {"mutual": false}})
}
DB.Remove(data.refid, {"collection": "rival", "sdvxID": rival.id, "refid": data.rivalId, "name": rival.name})
send.json({
"msg": "Successfully removed profile from rival."
})
}
}
export const preGeneRoll = async (data: { set: number, refid: string, items: [] }, send: WebUISend) => {
let itemId = {
'crew': 11,
'stamp': 17,
'subbg': 18,
'bgm': 19,
'nemsys': 20,
'sysbg': 21
}
let preGeneSet = PREGENE.find(itemSet => itemSet.id === data.set)
let finishedRolling = false
if(preGeneSet != undefined) {
while(!finishedRolling) {
let rollWhat = 0
let probability = Math.random();
console.log("Rolling Premium Generator")
for(const probIndex in preGeneSet.probability) {
if(probability <= preGeneSet.probability[probIndex]) {
rollWhat = parseInt(probIndex);
break;
}
if(parseInt(probIndex) === preGeneSet.probability.length - 1) rollWhat = parseInt(probIndex);
}
let unobtainedItems = preGeneSet.items[Object.keys(preGeneSet.items)[rollWhat]].map((x) => x)
data.items.forEach(item => {
let checkId = 0;
checkId = item['id']
if(item['type'] == 17) checkId = (item['id'] / 4)
if(item['type'] == itemId[Object.keys(preGeneSet.items)[rollWhat]] && preGeneSet.items[Object.keys(preGeneSet.items)[rollWhat]].includes(checkId)) {
unobtainedItems.splice(unobtainedItems.indexOf(checkId), 1)
}
})
if(unobtainedItems.length > 0) {
let randomItemIndex = Math.floor(Math.random() * unobtainedItems.length);
console.log("Rolled item id: " + unobtainedItems[randomItemIndex] + " | item type: " + itemId[Object.keys(preGeneSet.items)[rollWhat]])
if(itemId[Object.keys(preGeneSet.items)[rollWhat]] == 17) {
for(let stampID = (unobtainedItems[randomItemIndex] * 4) - 3; stampID <= (unobtainedItems[randomItemIndex] * 4); stampID++) {
DB.Upsert(data.refid, {
"collection": "item",
"type": itemId[Object.keys(preGeneSet.items)[rollWhat]],
"id": stampID },
{$set: {"param": 1}}
)
}
} else {
DB.Upsert(data.refid, {
"collection": "item",
"type": itemId[Object.keys(preGeneSet.items)[rollWhat]],
"id": unobtainedItems[randomItemIndex] },
{$set: {"param": 1}}
)
}
let finalItemType = (Object.keys(preGeneSet.items)[rollWhat] === 'subbg') ? 'bg' : Object.keys(preGeneSet.items)[rollWhat]
finishedRolling = true
send.json(
{
status: 'ok',
id: unobtainedItems[randomItemIndex],
type: finalItemType
}
)
} else {
console.log("No more " + Object.keys(preGeneSet.items)[rollWhat] + " items to get, will re-roll.")
}
}
} else console.log('pregeneset none')
}
export const manageEvents = async (data: { eventConfig: {} }) => {
IO.WriteFile('webui/asset/config/events.json', JSON.stringify(data.eventConfig, null, 4));
}
export const manageStartupFlags = async (data: { flagConfig: {} }) => {
IO.WriteFile('webui/asset/config/flags.json', JSON.stringify(data.flagConfig, null, 4));
}
+127
View File
@@ -0,0 +1,127 @@
import {common, log} from './handlers/common';
import {hiscore, rival, saveMix, loadMix, globalMatch, lounge, entryE} from './handlers/features';
import {
updateProfile,
updateMix,
importMix,
deleteMix,
copyResourcesFromGame,
getRivalScores,
addRival,
preGeneRoll,
manageEvents,
manageStartupFlags
} from './handlers/webui';
import {
load,
create,
loadScore,
save,
saveScore,
saveCourse,
buy,
print,
saveValgene,
saveE
} from './handlers/profiles';
import {
ARENA
} from './data/exg';
export function register() {
R.Contributor("LatoWolf#1170");
R.Contributor("ovv (this fork)");
R.GameCode('KFC');
R.Config('arena_szn',{ type: 'string', options: Object.keys(ARENA), default: 'None', name: 'Ranked Match Season', desc: 'Current ARENA/SINGLE BATTLE ranked season. Also sets ARENA STATION catalog corresponding to that season.'});
R.Config('enable_valk_songs' ,{ type: 'boolean', default: false, name:'Enable Valkyrie Model Songs', desc:'Enable the valkyrie model songs on non-valkyrie mode.'});
R.Config('use_blasterpass',{ type: 'boolean', default: true, name:'Use Blaster Pass', desc:'Enable Blaster Pass for VW and EG'});
R.Config('tama_track_lib',{ type: 'boolean', default: true, name:'Enable Track Liberation', desc:'(Requires TAMANEKO adventure event to be enabled) A TAMANEKO adventure map that will unlock a random song that has no unlock condition. OVER ADVENTURE will be displayed if this is disabled and if you have completed all other adventures.'});
R.Config('unlock_all_valk_items', { type: 'boolean', default: false, name:'Unlock All Valkyrie and Premium Items', desc: 'Unlock Nemsys, BGM, Submonitor BG, System BG and Stamp Items (Valk crews not included; check \'unlock all navigators\' option)'});
R.Config('unlock_all_songs', { type: 'boolean', default: false, name:'Unlock All Songs'});
R.Config('unlock_all_navigators', { type: 'boolean', default: false, name:'Unlock All Navigators'} );
R.Config('unlock_all_appeal_cards', { type: 'boolean', default: false, name:'Unlock All Appeal Cards'});
R.Config('enable_removed_songs', {type: 'boolean', default: true, name:'Enable removed songs', desc: 'Songs hidden or removed server-side will appear.'})
R.Config('sdvx_eg_root_dir', { type: 'string', needRestart: true, default: '', name: 'Exceed Gear Data Directory', desc: 'The root directory of your SDVX Exceed Gear game files (for asset copying)'});
R.Config('use_information' ,{ type: 'boolean', default: true, name:'Use Asphyxia Information', desc:'Enable the Asphyxia information section after entry. Otherwise, it will try to look for official information data and display them.'});
R.Config('use_asphyxia_gameover',{ type: 'boolean', default: true, name:'Use Asphyxia Gameover', desc:'Enable the Asphyxia gameover message after ending the game.'})
R.Config('april_fools',{ type: 'boolean', default: false, name:'April Fools', desc:'Enable April Fools Event (toggles Grace crew + April Fools songs)'});
// R.Config('new_year_special',{ type: 'boolean', default: false, name:'Use New Year Special', desc:'Enable New Year Special BGM for login.'});
R.WebUIEvent('copyResourcesFromGame', copyResourcesFromGame);
R.WebUIEvent('getRivalScores', getRivalScores);
R.WebUIEvent('addRival', addRival);
R.WebUIEvent('preGeneRoll', preGeneRoll);
R.WebUIEvent('manageEvents', manageEvents);
R.WebUIEvent('manageStartupFlags', manageStartupFlags);
R.WebUIEvent('updateProfile', updateProfile);
R.WebUIEvent('updateMix', updateMix);
R.WebUIEvent('importMix', importMix);
R.WebUIEvent('deleteMix', deleteMix);
const MultiRoute = (method: string, handler: EPR | boolean) => {
// Helper for register multiple versions.
R.Route(`game.${method}`, handler);
R.Route(`game_2.${method}`, handler);
//R.Route(`game_3.${method}`, handler);
R.Route(`game.sv4_${method}`, handler);
R.Route(`game.sv5_${method}`, handler);
R.Route(`game.sv6_${method}`, handler);
};
// Common
MultiRoute('common', common);
// Profile
MultiRoute('new', create);
MultiRoute('load', load);
MultiRoute('load_m', loadScore);
MultiRoute('save', save);
MultiRoute('save_m', saveScore);
MultiRoute('save_c', saveCourse);
MultiRoute('save_valgene', saveValgene);
MultiRoute('frozen', true);
MultiRoute('buy', buy);
MultiRoute('print',print);
// Features
MultiRoute('hiscore', hiscore);
MultiRoute('load_r', rival);
MultiRoute('save_ap', saveMix);
MultiRoute('load_ap', loadMix);
// Lazy
MultiRoute('lounge', lounge);
MultiRoute('shop', (_, __, send) => send.object({
nxt_time: K.ITEM('u32', 1000 * 5 * 60)
}));
MultiRoute('save_e', saveE);
MultiRoute('save_mega', true);
MultiRoute('play_e', true);
MultiRoute('play_s', true);
MultiRoute('entry_s', globalMatch);
MultiRoute('entry_e', entryE);
MultiRoute('exception', true);
MultiRoute('log',log);
R.Route('eventlog.write', (_, __, send) => send.object({
gamesession: K.ITEM('s64', BigInt(1)),
logsendflg: K.ITEM('s32', 0),
logerrlevel: K.ITEM('s32', 0),
evtidnosendflg: K.ITEM('s32', 0)
}));
R.Route('package.list',(_,__,send)=>send.object({
package:K.ATTR({expire:"1200"},{status:"1"})
}));
R.Route('ins.netlog', (_, __, send) => send.object({
//gamesession: K.ITEM('s64', BigInt(1)),
//logsendflg: K.ITEM('s32', 0),
//logerrlevel: K.ITEM('s32', 0),
//evtidnosendflg: K.ITEM('s32', 0)
}));
R.Unhandled(undefined)
}
+11
View File
@@ -0,0 +1,11 @@
export interface Arena {
collection: 'arena';
last_play_season: number;
rank_point: number;
shop_point: number;
ultimate_rate: number;
megamix_rate: number;
rank_play_cnt: number;
ultimate_play_cnt: number;
}
+6
View File
@@ -0,0 +1,6 @@
export interface Counter {
collection: 'counter';
key: string;
value: number;
}
+15
View File
@@ -0,0 +1,15 @@
export interface CourseRecord {
collection: 'course';
version: number;
sid: number;
cid: number;
stype: number;
score: number;
exscore: number;
clear: number;
grade: number;
rate: number;
count: number;
}
+7
View File
@@ -0,0 +1,7 @@
export interface Item {
collection: 'item';
type: number;
id: number;
param: number;
}
+16
View File
@@ -0,0 +1,16 @@
export interface Matchmaker {
collection: 'matchmaker';
timestamp: number,
c_ver: number,
p_num: number,
p_rest: number,
filter: number,
mid: number,
sec: number,
port: number,
gip: number[],
lip: number[],
claim: number,
entry_id: number
}
+11
View File
@@ -0,0 +1,11 @@
export interface Mix {
collection: 'mix';
id: number;
code: string;
name: string;
creator: string;
param: string;
jacket: number;
tag: number;
}
+13
View File
@@ -0,0 +1,13 @@
export interface MusicRecord {
collection: 'music';
mid: number;
type: number;
score: number;
exscore: number;
clear: number;
grade: number;
buttonRate: number;
longRate: number;
volRate: number;
}
+6
View File
@@ -0,0 +1,6 @@
export interface Param {
collection: 'param';
type: number;
id: number;
param: number[];
}
+64
View File
@@ -0,0 +1,64 @@
export interface Profile {
collection: 'profile';
pluginVer: number;
id: number;
name: string;
appeal: number;
akaname: number;
packets: number;
blocks: number;
expPoint: number;
mUserCnt: number;
musicID: number;
musicType: number;
sortType: number;
headphone: number;
blasterEnergy: number;
blasterCount: number;
extrackEnergy: number;
hiSpeed: number;
laneSpeed: number;
gaugeOption: number;
arsOption: number;
notesOption: number;
earlyLateDisp: number;
drawAdjust: number;
effCLeft: number;
effCRight: number;
narrowDown: number;
bgm: number;
subbg: number;
nemsys: number;
stampA: number;
stampB: number;
stampC: number;
stampD: number;
stampRA: number;
stampRB: number;
stampRC: number;
stampRD: number;
sysBG: number;
boothFrame: number[];
playCount: number;
dayCount: number;
todayCount: number;
playchain: number;
maxPlayChain: number;
weekCount: number;
weekPlayCount: number;
weekChain: number;
maxWeekChain: number;
bplSupport: number;
creatorItem: number;
}
+8
View File
@@ -0,0 +1,8 @@
export interface Rival {
collection: 'rival';
sdvxID: number;
refid: string;
name: string;
mutual: boolean;
}
+10
View File
@@ -0,0 +1,10 @@
export interface Skill {
collection: 'skill';
version: number;
level: number;
base: number;
name: number;
type: number;
}
+6
View File
@@ -0,0 +1,6 @@
export interface ValgeneTicket {
collection: 'valgene_ticket';
ticketNum: number;
limitDate: number;
}
+16
View File
@@ -0,0 +1,16 @@
- let music = 0;
- let event = 0;
- let catalog = 0;
game
limited
while music < 200
music(id=music++, flag=2)
event
while event < 16
info(id=event++)
catalog
while catalog < 256
info(id=catalog++, currency=1, price=1)
+23
View File
@@ -0,0 +1,23 @@
game
name(__type="str") #{name}
code(__type="str") #{code}
gamecoin_packet(__type="u32") #{packets}
gamecoin_block(__type="u32") #{blocks}
exp_point(__type="u32") #{expPoint ? expPoint : 0}
m_user_cnt(__type="u32") #{mUserCnt ? mUserCnt : 0}
have_item(__type="bool" __count=512) #{Array(512).fill(1).join(" ")}
have_note(__type="bool" __count=512) #{Array(512).fill(1).join(" ")}
last(
music_id=musicID,
music_type=musicType,
sort_type=sortType,
headphone=headphone,
hispeed=hiSpeed,
appeal_id=appeal,
frame0=boothFrame ? boothFrame[0] : 0,
frame1=boothFrame ? boothFrame[1] : 0,
frame2=boothFrame ? boothFrame[2] : 0,
frame3=boothFrame ? boothFrame[3] : 0,
frame4=boothFrame ? boothFrame[4] : 0,
)
+38
View File
@@ -0,0 +1,38 @@
- let music = 0;
- let event = 0;
- let catalog = 0;
game
music_limited
while music < 23
each type in [0,1,2,3]
info
music_id(__type="s32") #{music++}
music_type(__type="u8") #{type}
limited(__type="u8") 3
event
while event < 41
info
event_id(__type="u32") #{event++}
skill_course
each course in courses
info
course_id(__type="s16") #{course.id}
level(__type="s16") #{course.level}
season_id(__type="s16") #{course.season_id}
season_name(__type="str") #{course.season_name}
season_new_flg(__type="bool") #{course.new_flg}
course_name(_type="str") #{course.name}
course_type(__type="s16") #{course.type}
skill_name_id(__type="s16") #{course.name_id}
matching_assist(__type="bool") #{course.matching_assist}
guage_type(__type="s16") #{course.guage_type}
paseli_type(type="s16") #{course.paseli_type}
each trackinfo in course.tracks
track
track_no(__type="s16") #{trackinfo.no}
music_id(__type="s32") #{trackinfo.id}
music_type(__type="s8") #{trackinfo.type}
+105
View File
@@ -0,0 +1,105 @@
game
result(__type="u8") 0
name(__type="str") #{name}
code(__type="str") #{code}
sdvx_id(__type="str") #{code}
gamecoin_packet(__type="u32") #{packets}
gamecoin_block(__type="u32") #{blocks}
last
music_id(__type="s32") #{musicID}
music_type(__type="u8") #{musicType}
sort_type(__type="u8") #{sortType}
comment_id(__type="u16") 0
appeal_id(__type="u16") #{appeal}
headphone(__type="u8") #{headphone}
narrow_down(__type="u8") #{narrowDown}
gauge_option(__type="u8") #{gaugeOption}
blaster_energy(__type="u32") #{blasterEnergy}
blaster_count(__type="u32") #{blasterCount}
extrack_energy(__type="u16") #{extrackEnergy}
hispeed(__type="s32") #{hiSpeed}
lanespeed(__type="u32") #{laneSpeed}
ars_option(__type="u8") #{arsOption}
notes_option(__type="u8") #{notesOption}
early_late_disp(__type="u8") #{earlyLateDisp}
draw_adjust(__type="s32") #{drawAdjust}
eff_c_left(__type="u8") #{effCLeft}
eff_c_right(__type="u8") #{effCRight}
kac_id(__type="str") #{name}
skill_level(__type="s16") #{skill.level}
skill_base_id(__type="s16") #{skill.base}
skill_name_id(__type="s16") #{skill.name}
ea_shop
packet_booster(__type="s32") 1
if version < 5
block_booster(__type="s32") 1
if version >= 5
blaster_pass_enable(__type="bool") 1
blaster_pass_limit_date(__type="u64") #{currentTime}
eaappli
relation(__type="s8") 1
cloud
relation(__type="s8") 1
block_no(__type="s32") 0
skill
course
each course in courses
d
ssnid(__type="s16") #{course.sid}
crsid(__type="s16") #{course.cid}
sc(__type="s32") #{course.score}
ex(__type="s32") 0
ct(__type="s16") #{course.clear}
gr(__type="s16") #{course.grade}
ar(__type="s16") #{course.rate}
cnt(__type="s16") #{course.count}
course_total
each course in courses
d
ssnid(__type="s16") #{course.sid}
crsid(__type="s16") #{course.cid}
sc(__type="s32") #{course.score}
ex(__type="s32") 0
ct(__type="s16") #{course.clear}
gr(__type="s16") #{course.grade}
ar(__type="s16") #{course.rate}
cnt(__type="s16") #{course.count}
course_all
each course in courses
d
ssnid(__type="s16") #{course.sid}
crsid(__type="s16") #{course.cid}
sc(__type="s32") #{course.score}
ex(__type="s32") 0
ct(__type="s16") #{course.clear}
gr(__type="s16") #{course.grade}
ar(__type="s16") #{course.rate}
cnt(__type="s16") #{course.count}
item
each item in tempItem
info
type(__type="u8") #{item.type}
id(__type="u32") #{item.id}
param(__type="u32") #{item.param}
play_count(__type="u32") 1001
day_count(__type="u32") 301
today_count(__type="u32") 21
play_chain(__type="u32") 31
max_play_chain(__type="u32") 31
week_count(__type="u32") 9
week_play_count(__type="u32") 101
week_chain(__type="u32") 31
max_week_chain(__type="u32") 31
+14
View File
@@ -0,0 +1,14 @@
game
new
each music in temp
music
music_id (__type="u32")#{music.mid}
music_type (__type="u32")#{music.type}
score (__type="u32")#{music.score}
cnt (__type="u32")1
clear_type (__type="u32")#{music.clear}
score_grade (__type="u32")#{music.grade}
btn_rate (__type="u32")#{music.buttonRate}
long_rate (__type="u32")#{music.longRate}
vol_rate (__type="u32")#{music.volRate}
old
+155
View File
@@ -0,0 +1,155 @@
game
result(__type="u8") 0
name(__type="str") #{name}
code(__type="str") #{code}
sdvx_id(__type="str") #{code}
gamecoin_packet(__type="u32") #{packets}
gamecoin_block(__type="u32") #{blocks}
appeal_id(__type="u16") #{appeal}
last_music_id(__type="s32") #{musicID}
last_music_type(__type="u8") #{musicType}
sort_type(__type="u8") #{sortType}
headphone(__type="u8") #{headphone}
blaster_energy(__type="u32") #{blasterEnergy}
blaster_count(__type="u32") 0
extrack_energy(__type="u16") #{extrackEnergy}
hispeed(__type="s32") #{hiSpeed}
lanespeed(__type="u32") #{laneSpeed}
gauge_option(__type="u8") #{gaugeOption}
ars_option(__type="u8") #{arsOption}
notes_option(__type="u8") #{notesOption}
early_late_disp(__type="u8") #{earlyLateDisp}
draw_adjust(__type="s32") #{drawAdjust}
eff_c_left(__type="u8") #{effCLeft}
eff_c_right(__type="u8") #{effCRight}
narrow_down(__type="u8") #{narrowDown}
kac_id(__type="str") #{name}
skill_level(__type="s16") #{skill.level}
skill_base_id(__type="s16") #{skill.base}
skill_name_id(__type="s16") #{skill.name}
skill_type(__type="s16") #{skill.type !== undefined ? skill.type : 0}
if bplSupport
support_team_id(__type="s32") #{bplSupport}
ea_shop
packet_booster(__type="s32") 1
if version < 5
block_booster(__type="s32") 1
if version >= 5
blaster_pass_enable(__type="bool") #{blasterpass}
blaster_pass_limit_date(__type="u64") #{currentTime}
eaappli
relation(__type="s8") 1
cloud
relation(__type="s8") 1
block_no(__type="s32") 0
skill
each course in courses
course
ssnid(__type="s16") #{course.sid}
crsid(__type="s16") #{course.cid}
st(__type="s16") #{course.stype !== undefined ? course.stype : 0}
sc(__type="s32") #{course.score}
ex(__type="s32") #{course.exscore !== undefined ? course.exscore : 0}
ct(__type="s16") #{course.clear}
gr(__type="s16") #{course.grade}
ar(__type="s16") #{course.rate}
cnt(__type="s16") #{course.count}
item
each item in items
info
type(__type="u8") #{item.type}
id(__type="u32") #{item.id}
param(__type="u32") #{item.param}
//- Unlock automation songs
each song in automation
info
type(__type="u8") 15
id(__type="u32") #{song}
param(__type="u32") 1
present
each item in present
info
type(__type="u8") #{item.type}
id(__type="u32") #{item.id}
param(__type="u32") #{item.param}
param
each param in params
info
type(__type="s32") #{param.type}
id(__type="s32") #{param.id}
param(__type="s32" __count=param.param.length) #{param.param.join(" ")}
//- Akaname
each id in [0, 1, 2]
info
type(__type="s32") 6
id(__type="s32") #{id}
param(__type="s32" __count="1") #{akaname}
if playCount
play_count(__type="u32") #{playCount}
if dayCount
day_count(__type="u32") #{dayCount}
if todayCount
today_count(__type="u32") #{todayCount}
if playChain
play_chain(__type="u32") #{playChain}
if maxPlayChain
max_play_chain(__type="u32") #{maxPlayChain}
if weekCount
week_count(__type="u32") #{weekCount}
if weekPlayCount
week_play_count(__type="u32") #{weekPlayCount}
if weekChain
week_chain(__type="u32") #{weekChain}
if maxWeekChain
max_week_chain(__type="u32") #{maxWeekChain}
if mixes
each mix in mixes
automation
mix_id(__type="s32") #{mix.id}
mix_code(__type="str") #{mix.code}
seq(__type="str")
mix_name(__type="str") #{mix.name}
player_name(__type="str") #{mix.creator}
generate_param(__type="str") #{mix.param}
distribution_date(__type="u32") 20200101
jacket_id(__type="s32") #{mix.jacket}
tag_bit(__type="s32") #{mix.tag}
like_flg(__type="u8") 0
if arena
arena
last_play_season(__type="s32") #{arena.season !== undefined ? arena.season : 0}
rank_point(__type="s32") #{arena.rankPoint}
shop_point(__type="s32") #{arena.shopPoint}
ultimate_rate(__type="s32") #{arena.ultimateRate}
ultimate_rank_num(__type="s32") #{arena.ultimateRankNum !== undefined ? arena.ultimateRankNum : 0}
megamix_rate(__type="s32") #{arena.megamixRate !== undefined ? arena.megamixRate : 0}
rank_play_cnt(__type="s32") #{arena.rankCount}
ultimate_play_cnt(__type="s32") #{arena.ultimateCount}
if valgeneTicket
valgene_ticket
ticket_num(__type="s32") #{valgeneTicket.ticketNum}
limit_date(__type="u64") #{valgeneTicket.limitDate}
if creatorItem > 1
creator_item
info
creator_type(__type="u32") #{creatorItem}
item_id(__type="u32") 0
param(__type="u32") 0
+33
View File
@@ -0,0 +1,33 @@
import {Counter} from './models/counter';
export function IDToCode(id: number) {
const padded = _.padStart(id.toString(), 8);
return `${padded.slice(0, 4)}-${padded.slice(4)}`;
}
export async function GetCounter(key: string) {
return (
await DB.Upsert<Counter>(
{ collection: 'counter', key: 'mix' },
{ $inc: { value: 1 } }
)
).docs[0].value;
}
export function getVersion(info: EamuseInfo) {
const dateCode = parseInt(info.model.split(":")[4]);
if (dateCode <= 2013052900) return 1;
if (dateCode <= 2014112000) return 2;
if (dateCode <= 2016121200) return 3;
if (info.method.startsWith('sv4')) return 4;
if (info.method.startsWith('sv5')) return 5;
if (dateCode >= 2021083100) return -6;
if (info.method.startsWith('sv6')) return 6;
return 0;
}
export function getRandomIntInclusive(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min + 1) + min); //The maximum is inclusive and the minimum is inclusive
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Some files were not shown because too many files have changed in this diff Show More