From 206212be2f40bff95cb183aeed09575206de6aaa Mon Sep 17 00:00:00 2001 From: vvo <> Date: Mon, 6 Nov 2023 03:00:57 +0800 Subject: [PATCH] 231024 + webui stuff --- sdvx@asphyxia/README.md | 48 +- sdvx@asphyxia/bgm_convert.bat | 8 +- sdvx@asphyxia/data/exg.ts | 144 +- sdvx@asphyxia/handlers/common.ts | 2 +- sdvx@asphyxia/handlers/features.ts | 23 +- sdvx@asphyxia/handlers/profiles.ts | 31 +- sdvx@asphyxia/handlers/webui.ts | 128 +- sdvx@asphyxia/models/arena.ts | 1 + sdvx@asphyxia/models/matchmaker.ts | 16 + sdvx@asphyxia/models/valgene_ticket.ts | 6 + sdvx@asphyxia/templates/load.pug | 8 +- sdvx@asphyxia/webui/asset/js/achievements.js | 106 + sdvx@asphyxia/webui/asset/js/detail.js | 232 +- sdvx@asphyxia/webui/asset/js/generator.js | 36 +- sdvx@asphyxia/webui/asset/js/preview.js | 20 +- sdvx@asphyxia/webui/asset/js/songslist.js | 61 +- .../webui/asset/json/achievements.json | 5297 +++++++++++++++++ .../webui/asset/json/customize_data_ext.json | 78 + sdvx@asphyxia/webui/asset/json/events.json | 2 +- .../webui/asset/json/valgene_data.json | 11 +- sdvx@asphyxia/webui/profile_--detail.pug | 9 +- sdvx@asphyxia/webui/profile_--setting.pug | 34 +- sdvx@asphyxia/webui/profile_achievements.pug | 39 + sdvx@asphyxia/webui/update webui assets.pug | 5 +- 24 files changed, 6116 insertions(+), 229 deletions(-) create mode 100644 sdvx@asphyxia/models/matchmaker.ts create mode 100644 sdvx@asphyxia/models/valgene_ticket.ts create mode 100644 sdvx@asphyxia/webui/asset/js/achievements.js create mode 100644 sdvx@asphyxia/webui/asset/json/achievements.json create mode 100644 sdvx@asphyxia/webui/profile_achievements.pug diff --git a/sdvx@asphyxia/README.md b/sdvx@asphyxia/README.md index 457a370..418d66a 100644 --- a/sdvx@asphyxia/README.md +++ b/sdvx@asphyxia/README.md @@ -1,10 +1,10 @@ # SOUND VOLTEX -**Plugin Version:** fork-6.0.2.1 +**Plugin Version:** fork-6.0.2.3 **Supported game versions:** EXCEED GEAR -**Latest supported game datacode:** 2023091200 +**Latest supported game datacode:** 2023102400 **Unsupported game versions:** Every other game, as they're untested. @@ -12,14 +12,51 @@ **Notes:** - This fork enables a few of the features that are added in the later updates of Exceed Gear. However, I still highly recommend using the official stable version of the plugin. -- Most importantly, for everything to properly work: +- Before using this plugin: - run the [WebUI Asset Update](/plugin/sdvx@asphyxia/update%20webui%20assets). Do this every data update. - go to [Unlocking Events](/plugin/sdvx@asphyxia/unlocking%20events) and click "Apply" at least once. Check out the many options available while you're there. + - also adjust the plugin settings at the WebUI dashboard to your liking. - Don't expect stability, there might be some bugs. Please back up your save data to prevent unwanted issues (just in case) Changelog =========== +## fork-6.0.2.3 + +### New: + +1. Main: + - Added ~~ARENA~~ MEGAMIX BATTLE ranked match season & ARENA STATION set 11. + - Added PREMIUM GENERATOR Fubuki set. + - Updated licensed songs list (Fubuki songs) +2. WebUI + - Updated ARENA Season statistics display in detail page. Displays rank, rank point meter, megamix rate (for ranked megamix,) ultimate rate (for ultimate players,) and arena power. + - Added achievements list page (work in progress) + - Added ability to set how many Valkyrie Generator tickets you have. These tickets are used to purchase valkyrie generator items. + - Added ability to change Skill Titles. Players can only switch to titles they own. + - (Update webui resources) Added code to extract wma audio from .s3p files. Largely based on [mon's s3p_extract](https://github.com/mon/s3p_extract) code. +3. Others: + - DEMOLOOP_INFORMATION implementation (attract mode announcements images) + - Updated bgm_convert batch script to remove the need for s3p_extract. + +### Fixes: + +1. Game + - Fixed gibberish on Asphyxia card entry information data. +2. WebUI + - Fixed details page error for players with no skill course data. + - Fixed sorting of Valgene/Pregene item images. +3. Misc: + - Updated BPL Triple Tribe event category from 'gift' to 'event_online.' + - Added missing matchmaker model file. + +### Todo: +1. Figure out how to extract textures from .ifs files in TS/JS. +2. ~~Figure out how to extract audio files from .s3p files in TS/JS~~ Figure out how to convert wma audio to mp3 in JS/TS. +3. Figure out how to use image (png) files to appear in information/news popup. +4. More work/research on online matchmaking (globalMatch.) I can't seem to make clients establish a connection. + + ## fork-6.0.2.2 ### New: @@ -47,11 +84,6 @@ Changelog 1. Fixes WebUI resource update not adding video submonitor backgrounds. I 100% recommend updating your WebUI assets. -### Todo: -1. Figure out how to use image (png) files to appear in information/news popup. -2. Figure out how demoloop works. -3. More work/research on online matchmaking (globalMatch.) I can't seem to make clients establish a connection. - ## fork-6.0.2.1 diff --git a/sdvx@asphyxia/bgm_convert.bat b/sdvx@asphyxia/bgm_convert.bat index c729ba3..b70e3ac 100644 --- a/sdvx@asphyxia/bgm_convert.bat +++ b/sdvx@asphyxia/bgm_convert.bat @@ -1,10 +1,6 @@ @echo off -for /f %%a in ('dir "webui\asset\audio\*.s3p" /s /b') do ( - echo "%%~fa" - s3p_extract %%~fa - ffmpeg -i "%%~fa.out\0.wma" -vn -ar 44100 -ac 2 -b:a 192k "%%~fa.out\..\0.mp3" - ffmpeg -i "%%~fa.out\1.wma" -vn -ar 44100 -ac 2 -b:a 192k "%%~fa.out\..\1.mp3" - rmdir /s /q "%%~fa.out" +for /f %%a in ('dir "webui\asset\audio\" /b /s /a-d ^| findstr ".wma"') do ( + ffmpeg -i "%%~fa" -vn -ar 44100 -ac 2 -b:a 192k "%%~dpa%%~na.mp3" del %%~fa ) @echo on \ No newline at end of file diff --git a/sdvx@asphyxia/data/exg.ts b/sdvx@asphyxia/data/exg.ts index 7d1c1a5..6d8cbbc 100644 --- a/sdvx@asphyxia/data/exg.ts +++ b/sdvx@asphyxia/data/exg.ts @@ -40,7 +40,8 @@ export const EVENT6 = [ 'S_PUC_EFFECT_ENABLE', 'PLAYER_RADAR_ENABLE', 'SINGLE_BATTLE_ENABLE', - // 'DEMOLOOP_INFORMATION', + 'DEMOLOOP_INFORMATION\tdemo_info/230710_bpls3_streaming.png', + 'CHARACTER_IGNORE_DISABLE\t122,123,131,139,140,143' ]; export const INFORMATION6 = { @@ -69,7 +70,10 @@ export const LICENSED_SONGS6 = [ '1960', '1961', '1962', '2028', '2029', '1912', '1913', '2030', // 230518 - 230912 - '2031', '2032', '2033', '2034', '2035', '2036', '1905', '1882', '2058' + '2031', '2032', '2033', '2034', '2035', '2036', '1905', '1882', '2058', + + // 231005 + '2069', '2070', '2071', '2072', '2073' ] export const STAMP_EVENTS6 = { @@ -1516,6 +1520,133 @@ export const ARENA = { param: 8, } ] + }, + 'Season 11 (MEGAMIX BATTLE 2023/10/26~2023/11/13)': { + details: { + season: 11, + rule: 0, + rank_match_target: 2, + time_start: BigInt(Date.parse('26 Oct 2023 00:00:00 GMT')), + time_end: BigInt(Date.parse('31 Dec 2099 23:59:59 GMT')), + shop_start: BigInt(Date.parse('26 Oct 2023 00:00:00 GMT')), + shop_end: BigInt(Date.parse('31 Dec 2099 23:59:59 GMT')), + is_open: 1, + is_shop: 1 + }, + arena_items: [ + { + catalog_id: 1, + catalog_type: 1, + price: 15000, + item_type: 11, + item_id: 104, + param: 1, + }, + { + catalog_id: 1, + catalog_type: 1, + price: 8000, + item_type: 0, + item_id: 1742, + param: 23, + }, + { + catalog_id: 1, + catalog_type: 1, + price: 8000, + item_type: 0, + item_id: 1745, + param: 23, + }, + { + catalog_id: 1, + catalog_type: 1, + price: 8000, + item_type: 0, + item_id: 289, + param: 8, + }, + { + catalog_id: 1, + catalog_type: 1, + price: 4000, + item_type: 0, + item_id: 241, + param: 8, + }, + { + catalog_id: 1, + catalog_type: 1, + price: 4000, + item_type: 0, + item_id: 390, + param: 8, + }, + { + catalog_id: 1, + catalog_type: 1, + price: 8000, + item_type: 0, + item_id: 510, + param: 8, + }, + { + catalog_id: 1, + catalog_type: 1, + price: 8000, + item_type: 0, + item_id: 842, + param: 8, + }, + { + catalog_id: 1, + catalog_type: 1, + price: 8000, + item_type: 0, + item_id: 281, + param: 8, + }, + { + catalog_id: 1, + catalog_type: 1, + price: 8000, + item_type: 0, + item_id: 632, + param: 8, + }, + { + catalog_id: 1, + catalog_type: 1, + price: 4000, + item_type: 0, + item_id: 37, + param: 8, + }, + { + catalog_id: 1, + catalog_type: 1, + price: 4000, + item_type: 0, + item_id: 239, + param: 8, + }, + { + catalog_id: 1, + catalog_type: 1, + price: 2000, + item_type: 0, + item_id: 111, + param: 8, + }, + { + catalog_id: 1, + catalog_type: 1, + price: 2000, + item_type: 0, + item_id: 132, + param: 8, + } + ] } } @@ -1936,6 +2067,15 @@ export const PREGENE = [ 'sysbg': [1, 2, 3] }, probability: [0.01, 0.42, 0.84, 0.9] + }, + { + id: 7, + items: { + 'crew': [143], + 'stamp': [249, 250, 251, 252, 253, 254, 255, 256, 257, 258], + 'subbg': [369, 370, 371, 372, 373, 374, 375, 376, 377, 378, 379, 380, 381] + }, + probability: [0.01, 0.39, 0.6] } ] diff --git a/sdvx@asphyxia/handlers/common.ts b/sdvx@asphyxia/handlers/common.ts index fce753a..3a1235a 100644 --- a/sdvx@asphyxia/handlers/common.ts +++ b/sdvx@asphyxia/handlers/common.ts @@ -146,7 +146,7 @@ export const common: EPR = async (info, data, send) => { ' [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]¥á¥ê©`¡£¡£¡£¥¯¥ꥹ¥ޥ¹¡¢¤Ǥ¹¡£¡£¡£'+ + '[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]', '', diff --git a/sdvx@asphyxia/handlers/features.ts b/sdvx@asphyxia/handlers/features.ts index 6eeab8d..3ad1637 100644 --- a/sdvx@asphyxia/handlers/features.ts +++ b/sdvx@asphyxia/handlers/features.ts @@ -174,13 +174,14 @@ export const globalMatch: EPR = async (info, data, send) => { } let loggip = entryData.gip.join(".") + let loglip = entryData.lip.join(".") console.log("====================================") - console.log("[" + loggip + "] Searching for online match opponents") - console.log("[" + loggip + "] Removed " + await DB.Remove({collection:'matchmaker', timestamp: {$lt: Date.now() - 100000}}) + " expired match data.") + console.log("[" + loglip + " | " + loggip + "] Searching for online match opponents") + console.log("[" + loglip + " | " + loggip + "] Removed " + await DB.Remove({collection:'matchmaker', timestamp: {$lt: Date.now() - 100000}}) + " expired match data.") if(entryData.p_rest < 1) { - console.log("[" + loggip + "] Room is full. Halting.") + console.log("[" + loglip + " | " + loggip + "] Room is full. Halting.") return send.deny(); } @@ -196,15 +197,15 @@ export const globalMatch: EPR = async (info, data, send) => { // console.log(" claim: " + entryData.claim) // console.log("entry_id: " + entryData.entry_id) - console.log("[" + loggip + "] Adding/updating your match data") - if(await DB.Count({collection: 'matchmaker', gip: entryData.gip}) === 0) { + console.log("[" + loglip + " | " + loggip + "] Adding/updating your match data") + if(await DB.Count({collection: 'matchmaker', lip: entryData.lip}) === 0) { await DB.Upsert( - { collection: 'matchmaker', gip: entryData.gip }, + { collection: 'matchmaker', gip: entryData.gip, lip: entryData.lip}, entryData ) } else { await DB.Upsert( - { collection: 'matchmaker', gip: entryData.gip}, + { collection: 'matchmaker', gip: entryData.gip, lip: entryData.lip}, { $set: { c_ver: entryData.c_ver, p_num: entryData.p_num, @@ -218,8 +219,8 @@ export const globalMatch: EPR = async (info, data, send) => { ) } - console.log("[" + loggip + "] Searching...") - let filteredDB = await DB.Find({collection: "matchmaker", entry_id: entryData.entry_id, filter: entryData.filter, $not: {gip: entryData.gip}}) + console.log("[" + loglip + " | " + loggip + "] Searching...") + let filteredDB = await DB.Find({collection: "matchmaker", entry_id: entryData.entry_id, filter: entryData.filter, $not: {lip: entryData.lip}}) let opponents = filteredDB.length === 0 ? null : { entry_id: K.ITEM('u32', entryData.entry_id), @@ -230,11 +231,11 @@ export const globalMatch: EPR = async (info, data, send) => { })) } if(opponents !== null) { - console.log("[" + loggip + "] Opponent/s found.") + console.log("[" + loglip + " | " + loggip + "] Opponent/s found.") send.object(opponents) } else { - console.log("[" + loggip + "] No found opponents.") + console.log("[" + loglip + " | " + loggip + "] No found opponents.") send.deny() } } diff --git a/sdvx@asphyxia/handlers/profiles.ts b/sdvx@asphyxia/handlers/profiles.ts index ed3705b..6a7071f 100644 --- a/sdvx@asphyxia/handlers/profiles.ts +++ b/sdvx@asphyxia/handlers/profiles.ts @@ -6,6 +6,7 @@ import { Arena } from '../models/arena'; import { MusicRecord } from '../models/music_record'; import { CourseRecord } from '../models/course_record'; import { Profile } from '../models/profile'; +import { ValgeneTicket } from '../models/valgene_ticket'; import { getVersion, IDToCode } from '../utils'; import { Mix } from '../models/mix'; import { ARENA, EVENT_SONGS6 } from '../data/exg'; @@ -597,6 +598,7 @@ export const save: EPR = async (info, data, send) => { const earnedRP = are.number('earned_rank_point'); const earnedSP = are.number('earned_shop_point'); const earnedUR = are.number('earned_ultimate_rate'); + const earnedMR = are.number('earned_megamix_rate'); const earnedLE = are.number('earned_live_energy'); const rankPlay = are.str('rank_play') == 'true' ? 1 : 0; const ultimatePlay = are.str('ultimate_play') == 'true' ? 1 : 0; @@ -609,6 +611,7 @@ export const save: EPR = async (info, data, send) => { { $inc: { ultimateRate: _.isNil(earnedUR) ? 0 : earnedUR, + megamixRate: _.isNil(earnedMR) ? 0 : earnedMR, shopPoint: _.isNil(earnedSP) ? 0 : earnedSP, rankPoint: _.isNil(earnedRP) ? 0 : earnedRP, liveEnergy: _.isNil(earnedLE) ? 0 : earnedLE, @@ -704,7 +707,9 @@ export const load: EPR = async (info, data, send) => { const items = await DB.Find(refid, { collection: 'item' }); const courses = await DB.Find(refid, { collection: 'course', version }); const params = await DB.Find(refid, { collection: 'param' }); - const arena = await DB.FindOne(refid, { collection: 'arena', season: Object.keys(ARENA).findIndex(data => data == U.GetConfig('arena_szn')) + 1 }); + const arena = await DB.FindOne(refid, { collection: 'arena', season: (U.GetConfig('arena_szn') !== "None") ? ARENA[U.GetConfig('arena_szn')]['details']['season'] : 0 }); + const valgeneTicket = await DB.FindOne(refid, { collection: 'valgene_ticket' }) + let time = new Date(); let tempHour = time.getHours(); let tempDate = time.getDate(); @@ -788,6 +793,7 @@ export const load: EPR = async (info, data, send) => { automation: version == 5 ? SDVX_AUTOMATION_SONGS : [], code: IDToCode(profile.id), arena, + valgeneTicket, ...profile, }); }; @@ -939,6 +945,7 @@ export const saveValgene: EPR = async (info, data, send) => { console.log("Saving Valkyrie Generator Item") const refid = $(data).str('refid'); const items = $(data).elements('item.info'); + const useTicket = $(data).bool('use_ticket'); let itemsToAdd = [] for (const i of items) { const type = i.number('type'); @@ -967,11 +974,27 @@ export const saveValgene: EPR = async (info, data, send) => { ); } - return send.object({ result: K.ITEM('u8', 0) }); + if(useTicket) { + await DB.Upsert( + refid, + { collection: 'valgene_ticket' }, + { $inc: {ticketNum: -1} } + ) + } + let valgeneTicket = await DB.FindOne(refid, { collection: 'valgene_ticket' }) + let result = { + result: K.ITEM('s32', 1) + } + if(valgeneTicket !== null) { + result['ticket_num'] = K.ITEM('s32', valgeneTicket.ticketNum) + result['limit_date'] = K.ITEM('u64', BigInt(valgeneTicket.limitDate)) + } + + return send.object(result); } export const saveE: EPR = async (info, data, send) => { - console.log("save_e") + console.log("save_e - WIP") - return send.object({ result: K.ITEM('u8', 0) }); + send.success(); } diff --git a/sdvx@asphyxia/handlers/webui.ts b/sdvx@asphyxia/handlers/webui.ts index 160e4f9..5e96c7c 100644 --- a/sdvx@asphyxia/handlers/webui.ts +++ b/sdvx@asphyxia/handlers/webui.ts @@ -1,5 +1,7 @@ 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 { PREGENE } from '../data/exg'; @@ -22,6 +24,8 @@ export const updateProfile = async (data: { stampRC?: string; stampRD?: string; sysBG?: string; + valgeneTicket?: string; + skilltitle?: string; }) => { if (data.refid == null) return; @@ -106,7 +110,6 @@ export const updateProfile = async (data: { } if (data.sysBG && data.sysBG.length > 0) { - console.log(data.sysBG) const validSysBG = parseInt(data.sysBG); if (!_.isNaN(validSysBG)) update.sysBG = validSysBG; } @@ -116,6 +119,29 @@ export const updateProfile = async (data: { { collection: 'profile' }, { $set: update } ); + + if (parseInt(data.skilltitle) >= 0) { + await DB.Update( + data.refid, + { collection: 'skill' }, + { $set: { + name: parseInt(data.skilltitle) + } + } + ); + } + + if (parseInt(data.valgeneTicket) >= 0) { + await DB.Upsert( + 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: { @@ -353,7 +379,7 @@ export const copyResourcesFromGame = async (data: {}, send: WebUISend) => { 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(/(\.png|\.jpg|\.mp4)/g)) { + 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) @@ -367,13 +393,13 @@ export const copyResourcesFromGame = async (data: {}, send: WebUISend) => { 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' - console.log("[subbg] adding to json: " + subbgId + " - " + subbgName) + 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} @@ -394,16 +420,40 @@ export const copyResourcesFromGame = async (data: {}, send: WebUISend) => { if (bgm.name.match(/(\.s3p)/g)) { let folderName = bgm.name.match(/(custom|special)_([0-9]*)/g)[0] if(folderName != '') { - let fileToWrite = await IO.ReadFile(U.GetConfig('sdvx_eg_root_dir') + "/data/sound/custom/" + bgm.name) if(!IO.Exists('webui/asset/audio/' + folderName)) { - console.log("[bgm] copying " + bgm.name) - IO.WriteFile('webui/asset/audio/' + folderName + '/' + bgm.name, fileToWrite) - newBGMData.push(bgm.name) + 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}) } } @@ -414,6 +464,30 @@ export const copyResourcesFromGame = async (data: {}, send: WebUISend) => { 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")) { @@ -425,7 +499,8 @@ export const copyResourcesFromGame = async (data: {}, send: WebUISend) => { console.log("[valgene_item] copying " + valgeneItem.name) IO.WriteFile('webui/asset/valgene_item/' + valgeneItem.name, fileToWrite) newValgeneItemFiles.push(valgeneItem.name) - } + } + } } } else { @@ -434,14 +509,16 @@ export const copyResourcesFromGame = async (data: {}, send: WebUISend) => { } // Copying new akanames from gamedata - console.log("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) { - console.log("[akaname] adding " + akaname['@attr'].id + " - " + akaname.word['@content'] != undefined ? akaname.word['@content'] : '') - resourceJsonData.akaname.push({"value": akaname['@attr'].id, "name": akaname.word['@content'] != undefined ? akaname.word['@content'] : '' }) - newAkanames.push(akaname['@attr'].id + ": " + akaname.word['@content']) + 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)}) @@ -472,29 +549,6 @@ export const copyResourcesFromGame = async (data: {}, send: WebUISend) => { runErrors.push('[appeal card] Error reading appeal card xml file. 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) { - console.log("[chat_stamp] adding to json: " + chatStamp.id['@content'][0] + " - " + chatStamp.filename['@content']) - resourceJsonData.stamp.push({"value": chatStamp.id['@content'][0], "name": chatStamp.filename['@content']}) - 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.') - } - 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)) send.json( diff --git a/sdvx@asphyxia/models/arena.ts b/sdvx@asphyxia/models/arena.ts index 234f736..c0f9d29 100644 --- a/sdvx@asphyxia/models/arena.ts +++ b/sdvx@asphyxia/models/arena.ts @@ -5,6 +5,7 @@ export interface Arena { rank_point: number; shop_point: number; ultimate_rate: number; + megamix_rate: number; rank_play_cnt: number; ultimate_play_cnt: number; } diff --git a/sdvx@asphyxia/models/matchmaker.ts b/sdvx@asphyxia/models/matchmaker.ts new file mode 100644 index 0000000..107b7be --- /dev/null +++ b/sdvx@asphyxia/models/matchmaker.ts @@ -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 +} diff --git a/sdvx@asphyxia/models/valgene_ticket.ts b/sdvx@asphyxia/models/valgene_ticket.ts new file mode 100644 index 0000000..8c05481 --- /dev/null +++ b/sdvx@asphyxia/models/valgene_ticket.ts @@ -0,0 +1,6 @@ +export interface ValgeneTicket { + collection: 'valgene_ticket'; + + ticketNum: number; + limitDate: number; +} diff --git a/sdvx@asphyxia/templates/load.pug b/sdvx@asphyxia/templates/load.pug index 8c575d5..e33dbfa 100644 --- a/sdvx@asphyxia/templates/load.pug +++ b/sdvx@asphyxia/templates/load.pug @@ -35,7 +35,7 @@ game if bplSupport support_team_id(__type="s32") #{bplSupport} - + ea_shop packet_booster(__type="s32") 1 if version < 5 @@ -138,5 +138,11 @@ game 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} diff --git a/sdvx@asphyxia/webui/asset/js/achievements.js b/sdvx@asphyxia/webui/asset/js/achievements.js new file mode 100644 index 0000000..63ccc44 --- /dev/null +++ b/sdvx@asphyxia/webui/asset/js/achievements.js @@ -0,0 +1,106 @@ +var achobt = [] +var achdata = [] +var aptitlelist = [] +$(document).ready(async function() { + achobt = JSON.parse(document.getElementById("data-pass").innerText); + achobt.sort(function(a, b){return a['id'] - b['id']}); + achdata = await $.getJSON( "static/asset/json/achievements.json", function(data) { + return data + }) + aptitlelist = await $.getJSON( "static/asset/json/data.json", function(data) { + return data + }) + aptitlelist = aptitlelist['akaname'] + + await populateAch(1); + + $('#ach-filter').change(async function() { + // $('.ach-list').empty() + await populateAch(parseInt($('#ach-filter').val())); + }) + + +}) + +async function populateAch(listType) { + let achListFinal = [] + achdata['achievements'].forEach(ach => { + let achFound = achobt.find(obt => ach['id'] === obt['id']) + let reward = '' + if(ach['rid'] !== -1) { + if(ach['rtype'] === 'pcb') { + reward = ach['rid'] + " PCB" + } else if(ach['rtype'] === 'aptitle') { + reward = "Appeal Title \"" + aptitlelist.find(e => parseInt(e['value']) === ach['rid'])['name'] + "\"" + } + } else { + reward = '-----' + } + + if(listType === 1) { + if(achFound !== undefined) { + achListFinal.push( + { + 'id': ach['id'], + 'title': ach['title'], + 'reward': reward + } + ) + } + } else if(listType === 2) { + if(achFound === undefined) { + achListFinal.push( + { + 'id': ach['id'], + 'title': ach['title'], + 'reward': reward + } + ) + } + } else if(listType === 3) { + achListFinal.push( + { + 'id': ach['id'], + 'title': ach['title'], + 'reward': reward, + 'comp': (achFound === undefined) ? 'Incomplete' : 'Complete' + } + ) + } + }) + + $('#achlist').DataTable().clear().destroy() + $('#achlist').DataTable({ + data: achListFinal, + columns: (listType === 3) ? [ + { data: 'id' }, + { data: 'title' }, + { data: 'comp' }, + { data: 'reward' } + ] : [ + { data: 'id' }, + { data: 'title' }, + { data: 'reward' } + ], + pageLength: 100, + columnDefs: [ + { + targets: 0, + width: "10px" + } + ], + responsive: { + details: { + display: $.fn.dataTable.Responsive.display.modal({ + header: function(row) { + var data = row.data(); + return 'Details for achievement #' + data.id; + } + }) + } + } + }); + + if(listType === 3) $($('thead tr').children()[2]).show() + else $($('thead tr').children()[2]).hide() +} diff --git a/sdvx@asphyxia/webui/asset/js/detail.js b/sdvx@asphyxia/webui/asset/js/detail.js index 0f311a0..dc9a467 100644 --- a/sdvx@asphyxia/webui/asset/js/detail.js +++ b/sdvx@asphyxia/webui/asset/js/detail.js @@ -74,7 +74,7 @@ function getMedal(clear) { function getAppealCard(appeal) { var result = appeal_db["appeal_card_data"]["card"].filter(object => object["@id"] == appeal); - return "static/asset/ap_card/" + result[0]["info"]["texture"] + ".jpg" + return "static/asset/ap_card/" + ((result.length > 0) ? result[0]["info"]["texture"] : 'ap_06_0001') + ".jpg" } function getSongLevel(musicid, type) { @@ -639,7 +639,6 @@ $('#version_select').change(function() { $('#skillLV').fadeIn(200); }); - function getPlayerSkill(version) { // console.log(getPlayerMaxVersion()) if (skill_data.length == 0) return 0; @@ -656,17 +655,111 @@ function getVersionSelect() { return versionDATA; } +function displayArenaSeasonData(season) { + let sznData = arena_data.find(e => e.season === parseInt(season)) + if(sznData !== undefined) { + let rankInfo = getArenaRank(sznData.rankPoint) + $('.arena-details').append( + $('
').append( + $('
').append( + // $('', { + // src: 'static/asset/arena_icon/' + rankInfo[0] + ".png" + // }) + $('

' + ((rankInfo[0] === 'none') ? 'n/a' : rankInfo[0].toUpperCase()) + "

") + ) + ) + ).append( + $('
').append( + $('
').append( + $('

Arena Power

').append( + $('
' + sznData.shopPoint + ' AP
') + ) + ).append( + (sznData.megamixRate !== (0 || undefined)) ? $('

Megamix Rate

').append( + $('
' + sznData.megamixRate + '
') + ) : $("

") + ) + ) + ) + + if(sznData.rankPoint >= 23600) { + $('.arena-details-child-right').append( + $('

Rank Point

').append( + $('
' + sznData.rankPoint + ' points
') + ) + ) + } + + if(sznData.rankPoint !== 0 && sznData.rankPoint < 27800) { + $('.arena-details-child-left').append( + $('') + ).append( + $('
' + sznData.rankPoint + ' pts (' + (rankInfo[2].point - sznData.rankPoint) + ' pts to ' + rankInfo[2].rank.toUpperCase() + ')
') + ) + } else if(rankInfo[0] !== 'none'){ + $('.arena-details-child-left').append( + $('
Ultimate rate: ' + sznData.ultimateRate + '
') + ).append( + + ) + } + } +} + +function getArenaRank(rp) { + let arenaRanksList = [ + { rank: 'none', point: 0 }, + { rank: 'd4', point: 1 }, + { rank: 'd3', point: 600 }, + { rank: 'd2', point: 1600 }, + { rank: 'd1', point: 2600 }, + { rank: 'c4', point: 3600 }, + { rank: 'c3', point: 4700 }, + { rank: 'c2', point: 5800 }, + { rank: 'c1', point: 6900 }, + { rank: 'b4', point: 8000 }, + { rank: 'b3', point: 9200 }, + { rank: 'b2', point: 10400 }, + { rank: 'b1', point: 11600 }, + { rank: 'a4', point: 12800 }, + { rank: 'a3', point: 14100 }, + { rank: 'a2', point: 15400 }, + { rank: 'a1', point: 16700 }, + { rank: 's4', point: 18000 }, + { rank: 's3', point: 19400 }, + { rank: 's2', point: 20800 }, + { rank: 's1', point: 22200 }, + { rank: 'u4', point: 23600 }, + { rank: 'u3', point: 25000 }, + { rank: 'u2', point: 26400 }, + { rank: 'u1', point: 27800 } + ] + + let prevRank = '' + let rankIndex = 0 + let rankPointMin = 0 + let rankPointNext = 0 + arenaRanksList.forEach(rank => { + if(rp >= rank.point) { + prevRank = rank.rank + rankPointMin = rank.point + rankNext = arenaRanksList[rankIndex + 1] + } + rankIndex++; + }) + return [prevRank, rankPointMin, rankNext] +} + $(document).ready(function() { profile_data = JSON.parse(document.getElementById("data-pass").innerText); score_db = JSON.parse(document.getElementById("score-pass").innerText); skill_data = JSON.parse(document.getElementById("skill-pass").innerText); - xrecord_data = JSON.parse(document.getElementById("xrecord-pass").innerText); arena_data = JSON.parse(document.getElementById("arena-pass").innerText); skill_data.sort(function(a, b) { - return b.version - a.version; - }) - // console.log(score_db); + return b.version - a.version; + }) + // console.log(score_db); // $('#test').append( // $('
').append( @@ -692,31 +785,29 @@ $(document).ready(function() { }) ).then(function() { var currentVF = calculateVolforce(); - var maxVer = parseInt(skill_data[0]["version"]) + var maxVer = skill_data.length > 0 ? parseInt(skill_data[0]["version"]) : 0 var versionInfo = getVersionSelect(); - console.log(versionInfo); - for (var i = 0; i < versionInfo.length; i++) { - console.log(versionInfo[i]) + if(versionInfo.length <= 0) { $('#version_select').append( $('