mirror of
https://github.com/asphyxia-core/plugins.git
synced 2026-04-26 02:02:29 -05:00
Merge pull request #42 from thomeval/feature/00_betterMDB
Feature/00 better mdb
This commit is contained in:
commit
1a2e955dd4
|
|
@ -1,6 +1,6 @@
|
||||||
GITADORA Plugin for Asphyxia-Core
|
GITADORA Plugin for Asphyxia-Core
|
||||||
=================================
|
=================================
|
||||||

|

|
||||||
|
|
||||||
This plugin is based on converted from public-exported Asphyxia's Routes.
|
This plugin is based on converted from public-exported Asphyxia's Routes.
|
||||||
|
|
||||||
|
|
@ -26,10 +26,18 @@ Known Issues
|
||||||
* ~Information dialog keep showing as plugin doesn't store item data currently.~ (Fixed as of version 1.2.1)
|
* ~Information dialog keep showing as plugin doesn't store item data currently.~ (Fixed as of version 1.2.1)
|
||||||
* Special Premium Encore on Nextage
|
* Special Premium Encore on Nextage
|
||||||
- Bandage solution is implemented. Try it.
|
- Bandage solution is implemented. Try it.
|
||||||
|
* Friends and Rivals are unimplemented.
|
||||||
|
|
||||||
Release Notes
|
Release Notes
|
||||||
=============
|
=============
|
||||||
|
|
||||||
|
v1.2.2
|
||||||
|
----------------
|
||||||
|
* Major improvements to the MDB (song data) loader. MDB files can now be in .json, .xml or .b64 format. This applies to both the per-version defaults and custom MDBs. To use a custom MDB, enable it in the web UI, and place a 'custom.xml', 'custom.json' or 'custom.b64' file in the data/mdb subfolder.
|
||||||
|
* Added several player profile stats to the web UI.
|
||||||
|
* MDB loader now logs the number of loaded songs available to GF and DM when in dev mode.
|
||||||
|
* MDB: Fixed "is_secret" field being ignored (always set to false)
|
||||||
|
|
||||||
v1.2.1
|
v1.2.1
|
||||||
----------------
|
----------------
|
||||||
* Secret Music (unlocked songs) are now saved and loaded correctly. Partially fixes Github issue #34. Note that all songs are already marked as unlocked by the server - there is no need to unlock them manually. If you would like to lock them, consider using a custom MDB.
|
* Secret Music (unlocked songs) are now saved and loaded correctly. Partially fixes Github issue #34. Note that all songs are already marked as unlocked by the server - there is no need to unlock them manually. If you would like to lock them, consider using a custom MDB.
|
||||||
|
|
|
||||||
3
gitadora@asphyxia/data/mdb/.gitignore
vendored
3
gitadora@asphyxia/data/mdb/.gitignore
vendored
|
|
@ -6,4 +6,5 @@ ex.json
|
||||||
mt.json
|
mt.json
|
||||||
nt.json
|
nt.json
|
||||||
hv.json
|
hv.json
|
||||||
custom.xml
|
custom.xml
|
||||||
|
custom.json
|
||||||
|
|
@ -1,18 +1,6 @@
|
||||||
import Logger from "../../utils/logger";
|
import Logger from "../../utils/logger";
|
||||||
|
import { CommonMusicData } from "../../models/commonmusicdata";
|
||||||
|
|
||||||
export interface CommonMusicDataField {
|
|
||||||
id: KITEM<"s32">;
|
|
||||||
cont_gf: KITEM<"bool">;
|
|
||||||
cont_dm: KITEM<"bool">;
|
|
||||||
is_secret: KITEM<"bool">;
|
|
||||||
is_hot: KITEM<"bool">;
|
|
||||||
data_ver: KITEM<"s32">;
|
|
||||||
diff: KARRAY<"u16">;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface CommonMusicData {
|
|
||||||
music: CommonMusicDataField[]
|
|
||||||
}
|
|
||||||
|
|
||||||
export enum DATAVersion {
|
export enum DATAVersion {
|
||||||
HIGHVOLTAGE = "hv",
|
HIGHVOLTAGE = "hv",
|
||||||
|
|
@ -21,6 +9,9 @@ export enum DATAVersion {
|
||||||
MATTIX = "mt"
|
MATTIX = "mt"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const allowedFormats = ['.json', '.xml', '.b64']
|
||||||
|
const mdbFolder = "data/mdb/"
|
||||||
|
|
||||||
type processRawDataHandler = (path: string) => Promise<CommonMusicData>
|
type processRawDataHandler = (path: string) => Promise<CommonMusicData>
|
||||||
|
|
||||||
const logger = new Logger("mdb")
|
const logger = new Logger("mdb")
|
||||||
|
|
@ -32,30 +23,43 @@ export async function readXML(path: string) {
|
||||||
return json
|
return json
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function readJSON(path: string) {
|
export async function readMDBFile(path: string, processHandler?: processRawDataHandler): Promise<CommonMusicData> {
|
||||||
logger.debugInfo(`Loading MDB data from ${path}.`)
|
|
||||||
const str = await IO.ReadFile(path, 'utf-8');
|
|
||||||
const json = JSON.parse(str)
|
|
||||||
return json
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function readJSONOrXML(jsonPath: string, xmlPath: string, processHandler: processRawDataHandler): Promise<CommonMusicData> {
|
if (!IO.Exists(path)) {
|
||||||
if (!IO.Exists(jsonPath)) {
|
throw "Unable to find MDB file at " + path
|
||||||
logger.debugInfo(`Loading MDB data from ${xmlPath}.`)
|
|
||||||
const data = await processHandler(xmlPath)
|
|
||||||
await IO.WriteFile(jsonPath, JSON.stringify(data))
|
|
||||||
return data
|
|
||||||
} else {
|
|
||||||
logger.debugInfo(`Loading MDB data from ${jsonPath}.`)
|
|
||||||
const json = JSON.parse(await IO.ReadFile(jsonPath, 'utf-8'))
|
|
||||||
return json
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
export async function readB64JSON(b64path: string) {
|
logger.debugInfo(`Loading MDB data from ${path}.`)
|
||||||
logger.debugInfo(`Loading MDB data from ${b64path}.`)
|
|
||||||
const buff = await IO.ReadFile(b64path, 'utf-8');
|
let result : CommonMusicData;
|
||||||
return JSON.parse(Buffer.from(buff, 'base64').toString('utf-8'));
|
const fileType = path.substring(path.lastIndexOf('.')).toLowerCase()
|
||||||
|
|
||||||
|
switch (fileType) {
|
||||||
|
case '.json':
|
||||||
|
const str = await IO.ReadFile(path, 'utf-8');
|
||||||
|
result = JSON.parse(str)
|
||||||
|
break;
|
||||||
|
case '.xml':
|
||||||
|
processHandler ?? defaultProcessRawXmlData
|
||||||
|
result = await processHandler(path)
|
||||||
|
// Uncomment to save the loaded XML file as JSON.
|
||||||
|
// await IO.WriteFile(path.replace(".xml", ".json"), JSON.stringify(data))
|
||||||
|
break;
|
||||||
|
case '.b64':
|
||||||
|
const buff = await IO.ReadFile(path, 'utf-8');
|
||||||
|
const json = Buffer.from(buff, 'base64').toString('utf-8')
|
||||||
|
// Uncomment to save the decoded base64 file as JSON.
|
||||||
|
// await IO.WriteFile(path.replace(".b64",".json"), json)
|
||||||
|
result = JSON.parse(json)
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw `Invalid MDB file type: ${fileType}. Only .json, .xml, .b64 are supported.`
|
||||||
|
}
|
||||||
|
|
||||||
|
let gfCount = result.music.filter((e) => e.cont_gf["@content"][0]).length
|
||||||
|
let dmCount = result.music.filter((e) => e.cont_dm["@content"][0]).length
|
||||||
|
logger.debugInfo(`Loaded ${result.music.length} songs from MDB file. ${gfCount} songs for GF, ${dmCount} songs for DM.`)
|
||||||
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
export function gameVerToDataVer(ver: string): DATAVersion {
|
export function gameVerToDataVer(ver: string): DATAVersion {
|
||||||
|
|
@ -72,18 +76,47 @@ export function gameVerToDataVer(ver: string): DATAVersion {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function processDataBuilder(gameVer: string, processHandler?: processRawDataHandler) {
|
/**
|
||||||
const ver = gameVerToDataVer(gameVer)
|
* Attempts to find a .json, .xml, or .b64 file (in that order) matching the given name in the specified folder.
|
||||||
const base = `data/mdb/${ver}`
|
* @param fileNameWithoutExtension - The name of the file to find (without the extension).
|
||||||
if (IO.Exists(`${base}.b64`)) {
|
* @param path - The path to the folder to search. If left null, the default MDB folder ('data/mdb' in the plugin folder) will be used.
|
||||||
return await readB64JSON(`${base}.b64`);
|
* @returns - The path of the first matching file found, or null if no file was found.
|
||||||
|
*/
|
||||||
|
export function findMDBFile(fileNameWithoutExtension: string, path: string = null): string {
|
||||||
|
|
||||||
|
path = path ?? mdbFolder
|
||||||
|
if (!IO.Exists(path)) {
|
||||||
|
throw `Path does not exist: ${path}`
|
||||||
}
|
}
|
||||||
const { music } = await readJSONOrXML(`${base}.json`, `${base}.xml`, processHandler ?? defaultProcessRawData)
|
|
||||||
// await IO.WriteFile(`${base}.b64`, Buffer.from(JSON.stringify({music})).toString("base64"))
|
if (!path.endsWith("/")) {
|
||||||
return { music };
|
path += "/"
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const ext of allowedFormats) {
|
||||||
|
const filePath = path + fileNameWithoutExtension + ext
|
||||||
|
if (IO.Exists(filePath)) {
|
||||||
|
return filePath
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function defaultProcessRawData(path: string): Promise<CommonMusicData> {
|
export async function loadSongsForGameVersion(gameVer: string, processHandler?: processRawDataHandler) {
|
||||||
|
const ver = gameVerToDataVer(gameVer)
|
||||||
|
|
||||||
|
let mdbFile = findMDBFile(ver, mdbFolder)
|
||||||
|
|
||||||
|
if (mdbFile == null) {
|
||||||
|
throw `No valid MDB files were found in the data/mdb subfolder. Ensure that this folder contains at least one of the following: ${ver}.json, ${ver}.xml or ${ver}.b64`
|
||||||
|
}
|
||||||
|
|
||||||
|
const music = await readMDBFile(mdbFile, processHandler ?? defaultProcessRawXmlData)
|
||||||
|
return music
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function defaultProcessRawXmlData(path: string): Promise<CommonMusicData> {
|
||||||
const data = await readXML(path)
|
const data = await readXML(path)
|
||||||
const mdb = $(data).elements("mdb.mdb_data");
|
const mdb = $(data).elements("mdb.mdb_data");
|
||||||
const music: any[] = [];
|
const music: any[] = [];
|
||||||
|
|
@ -106,7 +139,7 @@ export async function defaultProcessRawData(path: string): Promise<CommonMusicDa
|
||||||
id: K.ITEM('s32', m.number("music_id")),
|
id: K.ITEM('s32', m.number("music_id")),
|
||||||
cont_gf: K.ITEM('bool', gf == 0 ? 0 : 1),
|
cont_gf: K.ITEM('bool', gf == 0 ? 0 : 1),
|
||||||
cont_dm: K.ITEM('bool', dm == 0 ? 0 : 1),
|
cont_dm: K.ITEM('bool', dm == 0 ? 0 : 1),
|
||||||
is_secret: K.ITEM('bool', 0),
|
is_secret: K.ITEM('bool', m.number("is_secret", 0)),
|
||||||
is_hot: K.ITEM('bool', type == 2 ? 0 : 1),
|
is_hot: K.ITEM('bool', type == 2 ? 0 : 1),
|
||||||
data_ver: K.ITEM('s32', m.number("data_ver", 115)),
|
data_ver: K.ITEM('s32', m.number("data_ver", 115)),
|
||||||
diff: K.ARRAY('u16', [
|
diff: K.ARRAY('u16', [
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,17 @@
|
||||||
import { getVersion } from "../utils";
|
import { getVersion } from "../utils";
|
||||||
import { defaultProcessRawData, processDataBuilder } from "../data/mdb"
|
import { CommonMusicDataField, findMDBFile, readMDBFile, loadSongsForGameVersion } from "../data/mdb";
|
||||||
import { CommonMusicDataField, readJSONOrXML, readXML } from "../data/mdb";
|
|
||||||
import Logger from "../utils/logger"
|
import Logger from "../utils/logger"
|
||||||
|
|
||||||
const logger = new Logger("MusicList")
|
const logger = new Logger("MusicList")
|
||||||
|
|
||||||
export const playableMusic: EPR = async (info, data, send) => {
|
export const playableMusic: EPR = async (info, data, send) => {
|
||||||
const version = getVersion(info);
|
const version = getVersion(info);
|
||||||
|
|
||||||
let music: CommonMusicDataField[] = [];
|
let music: CommonMusicDataField[] = [];
|
||||||
try {
|
try {
|
||||||
if (U.GetConfig("enable_custom_mdb")) {
|
if (U.GetConfig("enable_custom_mdb")) {
|
||||||
music = (await defaultProcessRawData('data/mdb/custom.xml')).music
|
let customMdb = findMDBFile("custom")
|
||||||
|
music = (await readMDBFile(customMdb)).music
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.warn("Read Custom MDB failed. Using default MDB as a fallback.")
|
logger.warn("Read Custom MDB failed. Using default MDB as a fallback.")
|
||||||
|
|
@ -19,10 +20,15 @@ export const playableMusic: EPR = async (info, data, send) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (music.length == 0) {
|
if (music.length == 0) {
|
||||||
music = _.get(await processDataBuilder(version), 'music', []);
|
music = (await loadSongsForGameVersion(version)).music
|
||||||
}
|
}
|
||||||
|
|
||||||
await send.object({
|
let response = getPlayableMusicResponse(music)
|
||||||
|
await send.object(response)
|
||||||
|
};
|
||||||
|
|
||||||
|
function getPlayableMusicResponse(music) {
|
||||||
|
return {
|
||||||
hot: {
|
hot: {
|
||||||
major: K.ITEM('s32', 1),
|
major: K.ITEM('s32', 1),
|
||||||
minor: K.ITEM('s32', 1),
|
minor: K.ITEM('s32', 1),
|
||||||
|
|
@ -30,5 +36,5 @@ export const playableMusic: EPR = async (info, data, send) => {
|
||||||
musicinfo: K.ATTR({ nr: `${music.length}` }, {
|
musicinfo: K.ATTR({ nr: `${music.length}` }, {
|
||||||
music,
|
music,
|
||||||
}),
|
}),
|
||||||
});
|
}
|
||||||
};
|
}
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
import { getEncoreStageData } from "../data/extrastage";
|
import { getEncoreStageData } from "../data/extrastage";
|
||||||
|
import Logger from "../utils/logger";
|
||||||
|
|
||||||
|
const logger = new Logger('info');
|
||||||
export const shopInfoRegist: EPR = async (info, data, send) => {
|
export const shopInfoRegist: EPR = async (info, data, send) => {
|
||||||
send.object({
|
send.object({
|
||||||
data: {
|
data: {
|
||||||
|
|
@ -16,64 +18,8 @@ export const shopInfoRegist: EPR = async (info, data, send) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const gameInfoGet: EPR = async (info, data, send) => {
|
export const gameInfoGet: EPR = async (info, data, send) => {
|
||||||
const addition: any = {
|
|
||||||
monstar_subjugation: {
|
const eventData = getEventDataResponse()
|
||||||
bonus_musicid: K.ITEM('s32', 0),
|
|
||||||
},
|
|
||||||
bear_fes: {},
|
|
||||||
nextadium: {},
|
|
||||||
};
|
|
||||||
const time = BigInt(31536000);
|
|
||||||
for (let i = 1; i <= 20; ++i) {
|
|
||||||
const obj = {
|
|
||||||
term: K.ITEM('u8', 0),
|
|
||||||
start_date_ms: K.ITEM('u64', time),
|
|
||||||
end_date_ms: K.ITEM('u64', time),
|
|
||||||
};
|
|
||||||
if (i == 1) {
|
|
||||||
addition[`phrase_combo_challenge`] = obj;
|
|
||||||
addition[`long_otobear_fes_1`] = {
|
|
||||||
term: K.ITEM('u8', 0),
|
|
||||||
start_date_ms: K.ITEM('u64', time),
|
|
||||||
end_date_ms: K.ITEM('u64', time),
|
|
||||||
bonus_musicid: {},
|
|
||||||
};
|
|
||||||
addition[`sdvx_stamprally3`] = obj;
|
|
||||||
addition[`chronicle_1`] = obj;
|
|
||||||
addition[`paseli_point_lottery`] = obj;
|
|
||||||
addition['sticker_campaign'] = {
|
|
||||||
term: K.ITEM('u8', 0),
|
|
||||||
sticker_list: {},
|
|
||||||
};
|
|
||||||
addition['thanksgiving'] = {
|
|
||||||
...obj,
|
|
||||||
box_term: {
|
|
||||||
state: K.ITEM('u8', 0)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
addition['lotterybox'] = {
|
|
||||||
...obj,
|
|
||||||
box_term: {
|
|
||||||
state: K.ITEM('u8', 0)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
addition[`phrase_combo_challenge_${i}`] = obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i <= 4) {
|
|
||||||
addition['monstar_subjugation'][`monstar_subjugation_${i}`] = obj;
|
|
||||||
addition['bear_fes'][`bear_fes_${i}`] = obj;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (i <= 3) {
|
|
||||||
addition[`kouyou_challenge_${i}`] = {
|
|
||||||
term: K.ITEM('u8', 0),
|
|
||||||
bonus_musicid: K.ITEM('s32', 0),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const extraData = getEncoreStageData(info)
|
const extraData = getEncoreStageData(info)
|
||||||
|
|
||||||
await send.object({
|
await send.object({
|
||||||
|
|
@ -157,6 +103,70 @@ export const gameInfoGet: EPR = async (info, data, send) => {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
...addition,
|
...eventData,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
function getEventDataResponse() {
|
||||||
|
const addition: any = {
|
||||||
|
monstar_subjugation: {
|
||||||
|
bonus_musicid: K.ITEM('s32', 0),
|
||||||
|
},
|
||||||
|
bear_fes: {},
|
||||||
|
nextadium: {},
|
||||||
|
};
|
||||||
|
const time = BigInt(31536000);
|
||||||
|
|
||||||
|
for (let i = 1; i <= 20; ++i) {
|
||||||
|
const obj = {
|
||||||
|
term: K.ITEM('u8', 0),
|
||||||
|
start_date_ms: K.ITEM('u64', time),
|
||||||
|
end_date_ms: K.ITEM('u64', time),
|
||||||
|
};
|
||||||
|
if (i == 1) {
|
||||||
|
addition[`phrase_combo_challenge`] = obj;
|
||||||
|
addition[`long_otobear_fes_1`] = {
|
||||||
|
term: K.ITEM('u8', 0),
|
||||||
|
start_date_ms: K.ITEM('u64', time),
|
||||||
|
end_date_ms: K.ITEM('u64', time),
|
||||||
|
bonus_musicid: {},
|
||||||
|
};
|
||||||
|
addition[`sdvx_stamprally3`] = obj;
|
||||||
|
addition[`chronicle_1`] = obj;
|
||||||
|
addition[`paseli_point_lottery`] = obj;
|
||||||
|
addition['sticker_campaign'] = {
|
||||||
|
term: K.ITEM('u8', 0),
|
||||||
|
sticker_list: {},
|
||||||
|
};
|
||||||
|
addition['thanksgiving'] = {
|
||||||
|
...obj,
|
||||||
|
box_term: {
|
||||||
|
state: K.ITEM('u8', 0)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
addition['lotterybox'] = {
|
||||||
|
...obj,
|
||||||
|
box_term: {
|
||||||
|
state: K.ITEM('u8', 0)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
|
||||||
|
addition[`phrase_combo_challenge_${i}`] = obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i <= 4) {
|
||||||
|
addition['monstar_subjugation'][`monstar_subjugation_${i}`] = obj;
|
||||||
|
addition['bear_fes'][`bear_fes_${i}`] = obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i <= 3) {
|
||||||
|
addition[`kouyou_challenge_${i}`] = {
|
||||||
|
term: K.ITEM('u8', 0),
|
||||||
|
bonus_musicid: K.ITEM('s32', 0),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return addition
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,8 @@ import { Record } from "../models/record";
|
||||||
import { Extra } from "../models/extra";
|
import { Extra } from "../models/extra";
|
||||||
import { getVersion, isDM } from "../utils";
|
import { getVersion, isDM } from "../utils";
|
||||||
import { Scores } from "../models/scores";
|
import { Scores } from "../models/scores";
|
||||||
|
import { PlayerStickerResponse } from "../models/playerstickerresponse";
|
||||||
|
import { SecretMusicResponse } from "../models/secretmusicresponse";
|
||||||
import { PLUGIN_VER } from "../const";
|
import { PLUGIN_VER } from "../const";
|
||||||
import Logger from "../utils/logger"
|
import Logger from "../utils/logger"
|
||||||
import { isAsphyxiaDebugMode } from "../Utils/index";
|
import { isAsphyxiaDebugMode } from "../Utils/index";
|
||||||
|
|
@ -230,38 +232,7 @@ export const getPlayer: EPR = async (info, data, send) => {
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
const sticker: any[] = [];
|
const sticker: PlayerStickerResponse[] = getPlayerStickers(name.card);
|
||||||
|
|
||||||
if (_.isArray(name.card)) {
|
|
||||||
for (const item of name.card) {
|
|
||||||
const id = _.get(item, 'id');
|
|
||||||
const posX = _.get(item, 'position.0');
|
|
||||||
const posY = _.get(item, 'position.1');
|
|
||||||
const scaleX = _.get(item, 'scale.0');
|
|
||||||
const scaleY = _.get(item, 'scale.1');
|
|
||||||
const rotation = _.get(item, 'rotation');
|
|
||||||
|
|
||||||
if (
|
|
||||||
!isFinite(id) ||
|
|
||||||
!isFinite(posX) ||
|
|
||||||
!isFinite(posY) ||
|
|
||||||
!isFinite(scaleX) ||
|
|
||||||
!isFinite(scaleY) ||
|
|
||||||
!isFinite(rotation)
|
|
||||||
) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
sticker.push({
|
|
||||||
id: K.ITEM('s32', id),
|
|
||||||
pos_x: K.ITEM('float', posX),
|
|
||||||
pos_y: K.ITEM('float', posY),
|
|
||||||
scale_x: K.ITEM('float', scaleX),
|
|
||||||
scale_y: K.ITEM('float', scaleY),
|
|
||||||
rotate: K.ITEM('float', rotation),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const playerData: any = {
|
const playerData: any = {
|
||||||
playerboard: {
|
playerboard: {
|
||||||
|
|
@ -376,6 +347,7 @@ export const getPlayer: EPR = async (info, data, send) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const innerSecretMusic = getSecretMusicResponse(profile)
|
const innerSecretMusic = getSecretMusicResponse(profile)
|
||||||
|
const innerFriendData = getFriendDataResponse(profile)
|
||||||
|
|
||||||
const response = {
|
const response = {
|
||||||
player: K.ATTR({ 'no': `${no}` }, {
|
player: K.ATTR({ 'no': `${no}` }, {
|
||||||
|
|
@ -392,7 +364,10 @@ export const getPlayer: EPR = async (info, data, send) => {
|
||||||
status: K.ARRAY('u32', extra.reward_status ?? Array(50).fill(0)),
|
status: K.ARRAY('u32', extra.reward_status ?? Array(50).fill(0)),
|
||||||
},
|
},
|
||||||
rivaldata: {},
|
rivaldata: {},
|
||||||
frienddata: {},
|
frienddata: {
|
||||||
|
friend: innerFriendData
|
||||||
|
},
|
||||||
|
|
||||||
thanks_medal: {
|
thanks_medal: {
|
||||||
medal: K.ITEM('s32', 0),
|
medal: K.ITEM('s32', 0),
|
||||||
grant_medal: K.ITEM('s32', 0),
|
grant_medal: K.ITEM('s32', 0),
|
||||||
|
|
@ -527,6 +502,42 @@ export const getPlayer: EPR = async (info, data, send) => {
|
||||||
send.object(response);
|
send.object(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getPlayerStickers(playerCard) : PlayerStickerResponse[] {
|
||||||
|
let stickers : PlayerStickerResponse[] = []
|
||||||
|
if (_.isArray(playerCard)) {
|
||||||
|
for (const item of playerCard) {
|
||||||
|
const id = _.get(item, 'id');
|
||||||
|
const posX = _.get(item, 'position.0');
|
||||||
|
const posY = _.get(item, 'position.1');
|
||||||
|
const scaleX = _.get(item, 'scale.0');
|
||||||
|
const scaleY = _.get(item, 'scale.1');
|
||||||
|
const rotation = _.get(item, 'rotation');
|
||||||
|
|
||||||
|
if (
|
||||||
|
!isFinite(id) ||
|
||||||
|
!isFinite(posX) ||
|
||||||
|
!isFinite(posY) ||
|
||||||
|
!isFinite(scaleX) ||
|
||||||
|
!isFinite(scaleY) ||
|
||||||
|
!isFinite(rotation)
|
||||||
|
) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
stickers.push({
|
||||||
|
id: K.ITEM('s32', id),
|
||||||
|
pos_x: K.ITEM('float', posX),
|
||||||
|
pos_y: K.ITEM('float', posY),
|
||||||
|
scale_x: K.ITEM('float', scaleX),
|
||||||
|
scale_y: K.ITEM('float', scaleY),
|
||||||
|
rotate: K.ITEM('float', rotation),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return stickers
|
||||||
|
}
|
||||||
|
|
||||||
async function getOrRegisterPlayerInfo(refid: string, version: string, no: number) {
|
async function getOrRegisterPlayerInfo(refid: string, version: string, no: number) {
|
||||||
let playerInfo = await DB.FindOne<PlayerInfo>(refid, {
|
let playerInfo = await DB.FindOne<PlayerInfo>(refid, {
|
||||||
collection: 'playerinfo',
|
collection: 'playerinfo',
|
||||||
|
|
@ -953,6 +964,8 @@ async function saveSinglePlayer(dataplayer: KDataReader, refid: string, no: numb
|
||||||
await DB.Upsert(refid, { collection: 'extra', game, version }, extra)
|
await DB.Upsert(refid, { collection: 'extra', game, version }, extra)
|
||||||
|
|
||||||
const playedStages = dataplayer.elements('stage');
|
const playedStages = dataplayer.elements('stage');
|
||||||
|
// logStagesPlayed(playedStages)
|
||||||
|
|
||||||
const scores = await updatePlayerScoreCollection(refid, playedStages, version, game)
|
const scores = await updatePlayerScoreCollection(refid, playedStages, version, game)
|
||||||
await saveScore(refid, version, game, scores);
|
await saveScore(refid, version, game, scores);
|
||||||
}
|
}
|
||||||
|
|
@ -1122,8 +1135,8 @@ function parseSecretMusic(playerData: KDataReader) : SecretMusicEntry[]
|
||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
|
|
||||||
function getSecretMusicResponse(profile: Profile) {
|
function getSecretMusicResponse(profile: Profile) : SecretMusicResponse[] {
|
||||||
let response = []
|
let response : SecretMusicResponse[] = []
|
||||||
|
|
||||||
if (!profile.secretmusic?.music ) {
|
if (!profile.secretmusic?.music ) {
|
||||||
return response
|
return response
|
||||||
|
|
@ -1140,3 +1153,19 @@ function getSecretMusicResponse(profile: Profile) {
|
||||||
return response
|
return response
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getFriendDataResponse(profile: Profile) {
|
||||||
|
let response = []
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
|
function logStagesPlayed(playedStages: KDataReader[]) {
|
||||||
|
|
||||||
|
let result = "Stages played: "
|
||||||
|
for (let stage of playedStages) {
|
||||||
|
let id = stage.number('musicid')
|
||||||
|
result += `${id}, `
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.debugLog(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,14 +25,15 @@ export function register() {
|
||||||
name: "Dummy Encore for SPE (Nextage Only)",
|
name: "Dummy Encore for SPE (Nextage Only)",
|
||||||
desc: "Since Nextage's Special Premium Encore system is bit complicated, \n"
|
desc: "Since Nextage's Special Premium Encore system is bit complicated, \n"
|
||||||
+ "SPE System isn't fully implemented. \n"
|
+ "SPE System isn't fully implemented. \n"
|
||||||
+ "This thing is bandage of these problem as limiting some Encores for SPE.",
|
+ "This option is a workaround for this issue as limiting some Encores for SPE.",
|
||||||
type: "boolean",
|
type: "boolean",
|
||||||
default: false
|
default: false
|
||||||
})
|
})
|
||||||
|
|
||||||
R.Config("enable_custom_mdb", {
|
R.Config("enable_custom_mdb", {
|
||||||
name: "Enable Custom MDB",
|
name: "Enable Custom MDB",
|
||||||
desc: "For who uses own MDB. eg) Omnimix.",
|
desc: "If disabled, the server will provide the default MDB (song list) to Gitadora clients, depending on which version of the game they are running." +
|
||||||
|
"Enable this option to provide your own custom MDB instead. MDB files are stored in the 'gitadora@asphyxia/data/mdb' folder, and can be in .xml, .json or .b64 format.",
|
||||||
type: "boolean",
|
type: "boolean",
|
||||||
default: false,
|
default: false,
|
||||||
})
|
})
|
||||||
|
|
@ -40,7 +41,7 @@ export function register() {
|
||||||
R.DataFile("data/mdb/custom.xml", {
|
R.DataFile("data/mdb/custom.xml", {
|
||||||
accept: ".xml",
|
accept: ".xml",
|
||||||
name: "Custom MDB",
|
name: "Custom MDB",
|
||||||
desc: "You need to enable Custom MDB option first."
|
desc: "You need to enable the 'Enable Custom MDB' option for the uploaded file to have any effect."
|
||||||
})
|
})
|
||||||
|
|
||||||
R.WebUIEvent('updatePlayerInfo', updatePlayerInfo);
|
R.WebUIEvent('updatePlayerInfo', updatePlayerInfo);
|
||||||
|
|
|
||||||
13
gitadora@asphyxia/models/commonmusicdata.ts
Normal file
13
gitadora@asphyxia/models/commonmusicdata.ts
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
export interface CommonMusicDataField {
|
||||||
|
id: KITEM<"s32">;
|
||||||
|
cont_gf: KITEM<"bool">;
|
||||||
|
cont_dm: KITEM<"bool">;
|
||||||
|
is_secret: KITEM<"bool">;
|
||||||
|
is_hot: KITEM<"bool">;
|
||||||
|
data_ver: KITEM<"s32">;
|
||||||
|
diff: KARRAY<"u16">;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CommonMusicData {
|
||||||
|
music: CommonMusicDataField[]
|
||||||
|
}
|
||||||
8
gitadora@asphyxia/models/playerstickerresponse.ts
Normal file
8
gitadora@asphyxia/models/playerstickerresponse.ts
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
export interface PlayerStickerResponse {
|
||||||
|
id: KITEM<'s32'>,
|
||||||
|
pos_x: KITEM<'float'> ,
|
||||||
|
pos_y: KITEM<'float'>,
|
||||||
|
scale_x: KITEM<'float'> ,
|
||||||
|
scale_y: KITEM<'float'>,
|
||||||
|
rotate: KITEM<'float'>
|
||||||
|
}
|
||||||
|
|
@ -2,4 +2,4 @@ export interface SecretMusicEntry {
|
||||||
musicid: number;
|
musicid: number;
|
||||||
seq: number;
|
seq: number;
|
||||||
kind: number;
|
kind: number;
|
||||||
}
|
}
|
||||||
5
gitadora@asphyxia/models/secretmusicresponse.ts
Normal file
5
gitadora@asphyxia/models/secretmusicresponse.ts
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
export interface SecretMusicResponse {
|
||||||
|
musicid: KITEM<'s32'>;
|
||||||
|
seq: KITEM<'u16'>;
|
||||||
|
kind: KITEM<'s32'>;
|
||||||
|
}
|
||||||
|
|
@ -7,7 +7,6 @@ export default class Logger {
|
||||||
this.category = (category == null) ? null : `[${category}]`
|
this.category = (category == null) ? null : `[${category}]`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public error(...args: any[]) {
|
public error(...args: any[]) {
|
||||||
this.argsHandler(console.error, ...args)
|
this.argsHandler(console.error, ...args)
|
||||||
}
|
}
|
||||||
|
|
@ -18,7 +17,6 @@ export default class Logger {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public warn(...args: any[]) {
|
public warn(...args: any[]) {
|
||||||
this.argsHandler(console.warn, ...args)
|
this.argsHandler(console.warn, ...args)
|
||||||
}
|
}
|
||||||
|
|
@ -29,7 +27,6 @@ export default class Logger {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public info(...args: any[]) {
|
public info(...args: any[]) {
|
||||||
this.argsHandler(console.info, ...args)
|
this.argsHandler(console.info, ...args)
|
||||||
}
|
}
|
||||||
|
|
@ -40,7 +37,6 @@ export default class Logger {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public log(...args: any[]) {
|
public log(...args: any[]) {
|
||||||
this.argsHandler(console.log, ...args)
|
this.argsHandler(console.log, ...args)
|
||||||
}
|
}
|
||||||
|
|
@ -51,7 +47,6 @@ export default class Logger {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private argsHandler(target: Function, ...args: any[]) {
|
private argsHandler(target: Function, ...args: any[]) {
|
||||||
if (this.category == null) {
|
if (this.category == null) {
|
||||||
target(...args)
|
target(...args)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,19 @@
|
||||||
//DATA//
|
//DATA//
|
||||||
info: DB.Find(refid, { collection: 'playerinfo' })
|
info: DB.Find(refid, { collection: 'playerinfo' })
|
||||||
|
profile: DB.Find(refid, { collection: 'profile' })
|
||||||
|
-
|
||||||
|
|
||||||
|
-
|
||||||
|
function getFullGameName(shortName) {
|
||||||
|
switch (shortName) {
|
||||||
|
case "dm" :
|
||||||
|
return "Drummania"
|
||||||
|
case "gf":
|
||||||
|
return "Guitar Freaks"
|
||||||
|
default:
|
||||||
|
return "Unknown"
|
||||||
|
}
|
||||||
|
}
|
||||||
-
|
-
|
||||||
|
|
||||||
div
|
div
|
||||||
|
|
@ -33,4 +46,39 @@ div
|
||||||
button.button.is-primary(type="submit")
|
button.button.is-primary(type="submit")
|
||||||
span.icon
|
span.icon
|
||||||
i.mdi.mdi-check
|
i.mdi.mdi-check
|
||||||
span Submit
|
span Submit
|
||||||
|
|
||||||
|
div
|
||||||
|
each pr in profile
|
||||||
|
.card
|
||||||
|
.card-header
|
||||||
|
p.card-header-title
|
||||||
|
span.icon
|
||||||
|
i.mdi.mdi-account-details
|
||||||
|
| Profile Detail (#{getFullGameName(pr.game)} #{pr.version})
|
||||||
|
.card-content
|
||||||
|
form(method="post")
|
||||||
|
.field
|
||||||
|
label.label Skill
|
||||||
|
.control
|
||||||
|
input.input(type="text" name="skill", value=(pr.skill/100) readonly)
|
||||||
|
.field
|
||||||
|
label.label Skill (All Songs)
|
||||||
|
.control
|
||||||
|
input.input(type="text" name="all_skill", value=(pr.all_skill/100) readonly)
|
||||||
|
.field
|
||||||
|
label.label Stages Cleared
|
||||||
|
.control
|
||||||
|
input.input(type="text" name="clear_num", value=pr.clear_num readonly)
|
||||||
|
.field
|
||||||
|
label.label Full Combos
|
||||||
|
.control
|
||||||
|
input.input(type="text" name="full_num", value=pr.full_num readonly)
|
||||||
|
.field
|
||||||
|
label.label Excellent Full Combos
|
||||||
|
.control
|
||||||
|
input.input(type="text" name="exce_num", value=pr.exce_num readonly)
|
||||||
|
.field
|
||||||
|
label.label Sessions
|
||||||
|
.control
|
||||||
|
input.input(type="text" name="session_cnt", value=pr.session_cnt readonly)
|
||||||
Loading…
Reference in New Issue
Block a user