diff --git a/README.md b/README.md index 1e55b9c..30edd67 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # DanceDanceRevolution -**Plugin Version:** fork-mdx-3.0.0b +**Plugin Version:** fork-mdx-3.0.1 -**Supported game versions:** WORLD (2024061300) +**Supported game versions:** WORLD (2024091000) **Unsupported game versions:** Everything below A20 is unsupported. A20 untested. A3 unsupported. @@ -17,6 +17,21 @@ Changelog =========== +## fork-mdx-3.0.1 + +### New: + +1. Main: + - Updated events list & event loading code: + - Galaxy Play + - EXTRA SAVIOR + - MYSTICAL Re:UNION (songs automatically unlocked on login atm) + - Attempts to fix ghost data loading: + - Added ghost id to score and ghost data + - Ghost data gets created when there is no existing data; and it gets updated when getting a higher or the same score. Side effect of this is when you have set a high score prior to this update, the ghost data won't be updated unless you break or match that high score. + - Unfortunately I could not find a way to match the old scores to their respective ghost data, since the old ghost data only stored the song id and difficulty, and not the style (single/double.) + + ## fork-mdx-3.0.0b ### New: @@ -41,25 +56,11 @@ Changelog - Added musicdata for new WORLD songs (ddr@asphyxia/data/world.ts:SONGS_WORLD) -## fork-mdx-3.0.0 - -### New: - -1. Main: - - 2024061300 support (DDR World) - - DDR profile registration for new and existing Asphyxia profiles - - For Asphyxia profiles with no prior DDR A20/A3 profiles registered. - - Transfer from A3 not supported (yet?) - - Profile saving and loading (probably incomplete) - - Score saving and loading (probably incomplete) - - ### To do: -1. Look for more missing features (I don't play DDR so idk what's missing lol) -2. Check flare skill value consistency -3. Transfer old save data from A3 to World (?) -4. Update re-rated song difficulties -5. WebUI Profile page -6. More work on score_str -7. Rival load +1. Look for more missing features +2. Refactor getLastScoreId and addScoreKey +3. Update re-rated song difficulties +4. WebUI stuff +5. More work on score_str +6. Rival load diff --git a/data/world.ts b/data/world.ts index 5346974..6f39cd6 100644 --- a/data/world.ts +++ b/data/world.ts @@ -69,10 +69,8 @@ export const EVENTS_WORLD = [ { id: 37, no: 1, cond: 1, rwrd: 38665, type: 81 }, { id: 38, no: 1, cond: 1, rwrd: 38665, type: 82 }, { id: 39, no: 1, cond: 1, rwrd: 38665, type: 83 }, { id: 40, no: 1, cond: 1, rwrd: 38665, type: 84 }, { id: 41, no: 1, cond: 1, rwrd: 38669, type: 81 }, { id: 42, no: 1, cond: 1, rwrd: 38669, type: 82 }, { id: 43, no: 1, cond: 1, rwrd: 38669, type: 83 }, { id: 44, no: 1, cond: 1, rwrd: 38669, type: 84 }, { id: 45, no: 1, cond: 1, rwrd: 38659, type: 81 }, { id: 46, no: 1, cond: 1, rwrd: 38659, type: 82 }, { id: 47, no: 1, cond: 1, rwrd: 38659, type: 83 }, { id: 48, no: 1, cond: 1, rwrd: 38659, type: 84 }, - { id: 49, no: 0, cond: 2, rwrd: 38736, type: 27 }, { id: 50, no: 0, cond: 2, rwrd: 38735, type: 27 }, { id: 51, no: 0, cond: 2, rwrd: 38728, type: 27 }, { id: 52, no: 0, cond: 1, rwrd: 38624, type: 27 }, { id: 53, no: 0, cond: 1, rwrd: 38623, type: 27 }, { id: 54, no: 0, cond: 1, rwrd: 38628, type: 27 }, - { id: 55, no: 0, cond: 1, rwrd: 38736, type: 25 }, { id: 56, no: 1, cond: 1, rwrd: 38736, type: 25 }, { id: 57, no: 2, cond: 1, rwrd: 38736, type: 25 }, { id: 58, no: 3, cond: 1, rwrd: 38736, type: 25 }, { id: 59, no: 0, cond: 1, rwrd: 38735, type: 25 }, { id: 60, no: 1, cond: 1, rwrd: 38735, type: 25 }, { id: 61, no: 2, cond: 1, rwrd: 38735, type: 25 }, { id: 62, no: 3, cond: 1, rwrd: 38735, type: 25 }, { id: 63, no: 0, cond: 1, rwrd: 38728, type: 25 }, { id: 64, no: 1, cond: 1, rwrd: 38728, type: 25 }, { id: 65, no: 2, cond: 1, rwrd: 38728, type: 25 }, { id: 66, no: 3, cond: 1, rwrd: 38728, type: 25 }, @@ -81,11 +79,11 @@ export const EVENTS_WORLD = [ { id: 77, no: 0, cond: 1, rwrd: 38628, type: 25 }, { id: 78, no: 1, cond: 1, rwrd: 38628, type: 25 }, { id: 79, no: 2, cond: 1, rwrd: 38628, type: 25 }, { id: 80, no: 3, cond: 1, rwrd: 38628, type: 25 }, { id: 81, no: 0, cond: 1, rwrd: 1185, type: 201, save: 1, dep: [67, 68, 69, 70, 72, 73, 74, 75, 77, 78, 79, 80] }, { id: 82, no: 0, cond: 1, rwrd: 1186, type: 201, save: 1, dep: [67, 68, 69, 70, 71, 72, 73, 74, 75, 77, 78, 79, 80] }, - { id: 83, no: 0, cond: 1, rwrd: 38746, type: 17, comp: 0, save: 1 }, { id: 84, no: 0, cond: 1, rwrd: 38745, type: 17, comp: 0, save: 1 }, { id: 85, no: 0, cond: 1, rwrd: 38744, type: 17, comp: 0, save: 1 }, { id: 86, no: 0, cond: 1, rwrd: 38747, type: 17, comp: 0, save: 1 }, { id: 87, no: 0, cond: 1, rwrd: 38748, type: 17, comp: 0, save: 1 }, - { id: 88, no: 0, cond: 1, rwrd: 1189, type: 201, save: 1 } + { id: 88, no: 0, cond: 1, rwrd: 1189, type: 201, save: 1 }, + { id: 89, no: 0, cond: 1, rwrd: 1188, type: 201, save: 1 } ] \ No newline at end of file diff --git a/handlers/ddrworld.ts b/handlers/ddrworld.ts index 053cbce..b115722 100644 --- a/handlers/ddrworld.ts +++ b/handlers/ddrworld.ts @@ -1,16 +1,46 @@ import { Profile } from "../models/profile"; -import { ProfileWorld, ScoreWorld, EventWorld, GhostWorld } from "../models/ddrworld"; +import { ProfileWorld, ScoreWorld, EventWorld, GhostWorld, RivalWorld } from "../models/ddrworld"; import { SONGS_WORLD, EVENTS_WORLD } from "../data/world"; +// needs to be faster +function getLastGhostId(ghost: any) { + return ghost.reduce(function(a, b) { + let aId = (a && !a.ghostId) ? 0 : a.ghostId + let bId = (!b.ghostId) ? 0 : b.ghostId + return (a && aId > bId) ? aId : bId + }) +} + async function saveScores(refid: string, songId: number, style: number, difficulty: number, rank: number, clearKind: number, score: number, exScore: number, maxCombo: number, flareForce: number, ghostSize: number, ghost: string) { - let stepScore = await DB.Find(refid, {collection: "score3", songId: songId, style: style, difficulty: difficulty}) - if(stepScore.length > 0) { - rank = (rank < stepScore[0].rank) ? rank : stepScore[0].rank; - clearKind = (clearKind != 6 && clearKind > stepScore[0].clearKind) ? clearKind : stepScore[0].clearKind; - score = (score > stepScore[0].score) ? score : stepScore[0].score; - exScore = (exScore > stepScore[0].exScore) ? exScore : stepScore[0].exScore; - maxCombo = (maxCombo > stepScore[0].maxCombo) ? maxCombo : stepScore[0].maxCombo; - flareForce = (flareForce > stepScore[0].flareForce) ? flareForce : stepScore[0].flareForce; + let ghostData = await DB.Find(null, {collection: "ghost3"}) + let lastGhostId = getLastGhostId(ghostData) + let stepScore = await DB.FindOne(refid, {collection: "score3", songId: songId, style: style, difficulty: difficulty}) + let ghostId = 0 + if(lastGhostId === 0) { + ghostId = 1 + } else ghostId = lastGhostId += 1 + /* + Ghost data gets created when there is no existing data and it gets updated when getting a higher or the same score + Side effect of this is when you have set a high score prior to this update, the ghost data wouldn't be updated unless you break or match that high score. + Unfortunately I could not find a way to match the old scores to their respective ghost data, since the old ghost data only stored the song id and difficulty, and not the style (single/double.) Stupid me. + Still needs more work. + */ + if(stepScore) { + ghostId = (stepScore.ghostId) ? stepScore.ghostId : ghostId + let stepGhost = await DB.FindOne(null, {collection: "ghost3", ghostId: ghostId }) + if(stepGhost) { + if(score >= stepScore.score) console.log("overwriting ghostdata") + ghostSize = (score >= stepScore.score) ? ghostSize : stepGhost.ghostSize + ghost = (score >= stepScore.score) ? ghost : stepGhost.ghost + } + + rank = (rank < stepScore.rank) ? rank : stepScore.rank; + clearKind = (clearKind != 6 && clearKind > stepScore.clearKind) ? clearKind : stepScore.clearKind; + score = (score > stepScore.score) ? score : stepScore.score; + exScore = (exScore > stepScore.exScore) ? exScore : stepScore.exScore; + maxCombo = (maxCombo > stepScore.maxCombo) ? maxCombo : stepScore.maxCombo; + flareForce = (flareForce > stepScore.flareForce) ? flareForce : stepScore.flareForce; + } await DB.Upsert(refid, { @@ -20,19 +50,18 @@ async function saveScores(refid: string, songId: number, style: number, difficul difficulty }, { $set: { + ghostId, rank, clearKind, score, - exScore, - maxCombo, - flareForce + exScore } }); + console.log("saving ghostid: " + ghostId) await DB.Upsert(refid, { collection: "ghost3", - songId, - difficulty + ghostId, }, { $set: { ghostSize, @@ -41,6 +70,31 @@ async function saveScores(refid: string, songId: number, style: number, difficul }); } +// async function addGhostId(refid: string) { +// const ghost = await DB.Find(null, { collection: "ghost3" }); +// if(ghost) { +// let lastGhostId = getLastScoreId(ghost) +// if(lastGhostId === 0) { +// console.log("Modifying score data to add ghost id.") +// for(const scoreData of scores) { +// let songId = scoreData.songId +// let style = scoreData.style +// let difficulty = scoreData.difficulty +// let rank = scoreData.rank +// let clearKind = scoreData.clearKind +// let score = scoreData.score +// let exScore = scoreData.exScore +// let maxCombo = scoreData.maxCombo +// let flareForce = scoreData.flareForce +// let ghostSize = (scoreData.ghostSize) ? scoreData.ghostSize : 0 +// let ghost = (scoreData.ghost) ? scoreData.ghost : '0' +// await DB.Remove(refid, {collection: "score3", songId: songId, style: style, difficulty: difficulty}) +// await saveScores(refid, songId, style, difficulty, rank, clearKind, score, exScore, maxCombo, flareForce, ghostSize, ghost) +// } +// } +// } +// } + export const playerdatanew: EPR = async (info, data, send) => { const refid = $(data).str("data.refid"); let ddrCode = _.random(1, 99999999) @@ -141,7 +195,7 @@ export const playerdatasave: EPR = async (info, data, send) => { let flareForce = $(data).number("data.result.flare_force"); let ghostSize = $(data).number("data.result.ghostsize"); let ghost = $(data).str("data.result.ghost"); - saveScores(refid, songId, style, difficulty, rank, clearKind, score, exScore, maxCombo, flareForce, ghostSize, ghost) + await saveScores(refid, songId, style, difficulty, rank, clearKind, score, exScore, maxCombo, flareForce, ghostSize, ghost) } else if($(data).number("data.savekind") === 3) { let profile = await DB.FindOne(refid, {collection: "profile3"}) @@ -249,7 +303,7 @@ export const playerdataload: EPR = async (info, data, send) => { const refid = $(data).str("data.refid"); const profile = await DB.FindOne(refid, { collection: "profile3" }); - if (!profile || refid.startsWith("X000")) { + if (!profile || !profile.dancerName || refid.startsWith("X000")) { return send.object({ result: K.ITEM("s32", 0), refid: K.ITEM("str", refid), @@ -257,17 +311,17 @@ export const playerdataload: EPR = async (info, data, send) => { servertime: K.ITEM("u64", BigInt(getDate())), is_locked: K.ITEM('bool', false), common: { - ddrcode: K.ITEM("s32", 0), + ddrcode: K.ITEM("s32", profile ? profile.ddrCode : 0), dancername: K.ITEM("str", ''), - is_new: K.ITEM('bool', true), - is_registering: K.ITEM('bool', false), + is_new: K.ITEM('bool', (!profile || refid.startsWith("X000")) ? true : false), + is_registering: K.ITEM('bool', (profile && !profile.dancerName) ? true : false), + is_takeover: K.ITEM('bool', false), area: K.ITEM("s32", 0), extrastar: K.ITEM("s32", 0), playcount: K.ITEM("s32", 0), weight: K.ITEM("s32", 0), today_cal: K.ITEM("u64", BigInt(0)), is_disp_weight: K.ITEM("bool", false), - is_takeover: K.ITEM('bool', false), pre_playable_num: K.ITEM("s32", 0) }, option: { @@ -352,8 +406,8 @@ export const playerdataload: EPR = async (info, data, send) => { }) } else { + // await addGhostId(refid) const scores = await DB.Find(refid, { collection: "score3" }); - let scoreFin = [] if(scores) { for(const scoreData of scores) { @@ -369,14 +423,14 @@ export const playerdataload: EPR = async (info, data, send) => { */ scr[(scoreData.style === 0) ? 'score_single' : 'score_double'] = [ { - score_str: K.ITEM('str', scoreData.difficulty + ',1,' + scoreData.rank + ',' + scoreData.clearKind + ',' + scoreData.score + ',' + scoreData.exScore + ',' + scoreData.flareForce + ',' + scoreData.flareForce) + score_str: K.ITEM('str', scoreData.difficulty + ',1,' + scoreData.rank + ',' + scoreData.clearKind + ',' + scoreData.score + ',' + scoreData.ghostId + ',' + scoreData.flareForce + ',' + scoreData.flareForce) } ] scoreFin.push(scr) } else { scoreFin[mcodeIndex][(scoreData.style === 0) ? 'score_single' : 'score_double'].push({ - score_str: K.ITEM('str', scoreData.difficulty + ',1,' + scoreData.rank + ',' + scoreData.clearKind + ',' + scoreData.score + ',' + scoreData.exScore + ',' + scoreData.flareForce + ',' + scoreData.flareForce) + score_str: K.ITEM('str', scoreData.difficulty + ',1,' + scoreData.rank + ',' + scoreData.clearKind + ',' + scoreData.score + ',' + scoreData.ghostId + ',' + scoreData.flareForce + ',' + scoreData.flareForce) }) } } @@ -559,9 +613,11 @@ export const rivaldataload: EPR = async (info, data, send) => { }; export const ghostdataload: EPR = async (info, data, send) => { + // Choosing world, area and machine #1 target scores doesn't seem to call this endpoint yet (or at all) const refid = $(data).str("data.refid"); const ghostId = $(data).number("data.ghostid"); - let ghostData = await DB.FindOne(refid, {collection: 'ghost3', songId: ghostId}) + console.log("loading ghostid: " + ghostId) + let ghostData = await DB.FindOne(null, {collection: 'ghost3', ghostId: ghostId}) if(ghostData) { return send.object({ result: K.ITEM("s32", 0), diff --git a/models/ddrworld.ts b/models/ddrworld.ts index cafbf9e..23c9e41 100644 --- a/models/ddrworld.ts +++ b/models/ddrworld.ts @@ -10,9 +10,11 @@ export interface RivalWorld { export interface ScoreWorld { collection: "score3"; + scoreId: number; songId: number; style: number; difficulty: Difficulty; + ghostId: number; rank: Rank; clearKind: ClearKind; score: number; @@ -24,8 +26,7 @@ export interface ScoreWorld { export interface GhostWorld { collection: "ghost3" - songId: number; - difficulty: number; + ghostId: number; ghostSize: number; ghost: string; }