mirror of
https://github.com/asphyxia-core/plugins.git
synced 2026-03-21 17:34:46 -05:00
886 lines
31 KiB
TypeScript
886 lines
31 KiB
TypeScript
/// <reference lib="es2020.bigint" />
|
|
|
|
import { getDefaultPlayerInfo, PlayerInfo } from "../models/playerinfo";
|
|
import { PlayerRanking } from "../models/playerranking";
|
|
import { getDefaultProfile, Profile } from "../models/profile";
|
|
import { getDefaultRecord, Record } from "../models/record";
|
|
import { Extra, getDefaultExtra } from "../models/extra";
|
|
import { getVersion, isDM } from "../utils";
|
|
import { getDefaultScores, Scores } from "../models/scores";
|
|
|
|
import { PLUGIN_VER } from "../const";
|
|
import Logger from "../utils/logger"
|
|
import { isAsphyxiaDebugMode, isSharedSongScoresEnabled } from "../utils/index";
|
|
import { SecretMusicEntry } from "../models/secretmusicentry";
|
|
import { CheckPlayerResponse, getCheckPlayerResponse } from "../models/Responses/checkplayerresponse";
|
|
import { getPlayerStickerResponse, PlayerStickerResponse } from "../models/Responses/playerstickerresponse";
|
|
import { getSecretMusicResponse, SecretMusicResponse } from "../models/Responses/secretmusicresponse";
|
|
import { getSaveProfileResponse } from "../models/Responses/saveprofileresponse";
|
|
import { getDefaultBattleDataResponse } from "../models/Responses/battledataresponse";
|
|
import { applySharedFavoriteMusicToExtra, saveSharedFavoriteMusicFromExtra } from "./FavoriteMusic";
|
|
import { getPlayerRecordResponse } from "../models/Responses/playerrecordresponse";
|
|
import { getPlayerPlayInfoResponse, PlayerPlayInfoResponse } from "../models/Responses/playerplayinforesponse";
|
|
import { getMergedSharedScores, mergeScoresIntoShared } from "./SharedScores";
|
|
|
|
const logger = new Logger("profiles")
|
|
|
|
export const regist: EPR = async (info, data, send) => {
|
|
|
|
const refid = $(data).str('player.refid');
|
|
if (!refid) {
|
|
logger.error("Request data is missing required parameter: player.refid")
|
|
return send.deny();
|
|
}
|
|
|
|
const no = getPlayerNo(data);
|
|
const version = getVersion(info);
|
|
const playerInfo = await getOrRegisterPlayerInfo(refid, version, no);
|
|
|
|
await send.object({
|
|
player: K.ATTR({ no: `${no}` }, {
|
|
is_succession: K.ITEM("bool", 0), //FIX THIS with upsert result.
|
|
did: K.ITEM("s32", playerInfo.id)
|
|
})
|
|
})
|
|
|
|
}
|
|
|
|
export const check: EPR = async (info, data, send) => {
|
|
|
|
const refid = $(data).str('player.refid');
|
|
if (!refid) {
|
|
logger.error("Request data is missing required parameter: player.refid")
|
|
return send.deny();
|
|
}
|
|
|
|
const no = getPlayerNo(data);
|
|
const version = getVersion(info)
|
|
const playerInfo = await getOrRegisterPlayerInfo(refid, version, no)
|
|
|
|
const result : CheckPlayerResponse = getCheckPlayerResponse(no, playerInfo.name, playerInfo.id)
|
|
await send.object(result)
|
|
}
|
|
|
|
export const getPlayer: EPR = async (info, data, send) => {
|
|
const refid = $(data).str('player.refid');
|
|
if (!refid) {
|
|
logger.error("Request data is missing required parameter: player.refid")
|
|
return send.deny();
|
|
}
|
|
|
|
const no = getPlayerNo(data);
|
|
const version = getVersion(info);
|
|
const time = BigInt(31536000);
|
|
const dm = isDM(info);
|
|
const game = dm ? 'dm' : 'gf';
|
|
const sharedScoresEnabled = isSharedSongScoresEnabled();
|
|
|
|
logger.debugInfo(`Loading ${game} profile for player ${no} with refid: ${refid}`)
|
|
const name = await DB.FindOne<PlayerInfo>(refid, {
|
|
collection: 'playerinfo',
|
|
version
|
|
})
|
|
const dmProfile = await getProfile(refid, version, 'dm')
|
|
const gfProfile = await getProfile(refid, version, 'gf')
|
|
const dmRecord = await getRecord(refid, version, 'dm')
|
|
const gfRecord = await getRecord(refid, version, 'gf')
|
|
const dmExtra = await getExtra(refid, version, 'dm')
|
|
const gfExtra = await getExtra(refid, version, 'gf')
|
|
const dmScores = sharedScoresEnabled ? await getMergedSharedScores(refid, 'dm') : (await getScore(refid, version, 'dm')).scores
|
|
const gfScores = sharedScoresEnabled ? await getMergedSharedScores(refid, 'gf') : (await getScore(refid, version, 'gf')).scores
|
|
|
|
const profile = dm ? dmProfile : gfProfile;
|
|
const extra = dm ? dmExtra : gfExtra;
|
|
|
|
await applySharedFavoriteMusicToExtra(refid, extra)
|
|
|
|
const record: any = {
|
|
gf: getPlayerRecordResponse(gfProfile, gfRecord),
|
|
dm: getPlayerRecordResponse(dmProfile, dmRecord),
|
|
};
|
|
|
|
// Format scores
|
|
const musicdata = [];
|
|
const scores = dm ? dmScores : gfScores;
|
|
for (const [musicid, score] of _.entries(scores)) {
|
|
musicdata.push(K.ATTR({ musicid }, {
|
|
mdata: K.ARRAY('s16', [
|
|
-1,
|
|
_.get(score, 'diffs.1.clear', false) ? _.get(score, 'diffs.1.perc', -2) : -1,
|
|
_.get(score, 'diffs.2.clear', false) ? _.get(score, 'diffs.2.perc', -2) : -1,
|
|
_.get(score, 'diffs.3.clear', false) ? _.get(score, 'diffs.3.perc', -2) : -1,
|
|
_.get(score, 'diffs.4.clear', false) ? _.get(score, 'diffs.4.perc', -2) : -1,
|
|
_.get(score, 'diffs.5.clear', false) ? _.get(score, 'diffs.5.perc', -2) : -1,
|
|
_.get(score, 'diffs.6.clear', false) ? _.get(score, 'diffs.6.perc', -2) : -1,
|
|
_.get(score, 'diffs.7.clear', false) ? _.get(score, 'diffs.7.perc', -2) : -1,
|
|
_.get(score, 'diffs.8.clear', false) ? _.get(score, 'diffs.8.perc', -2) : -1,
|
|
_.get(score, 'diffs.1.clear', false) ? _.get(score, 'diffs.1.rank', 0) : -1,
|
|
_.get(score, 'diffs.2.clear', false) ? _.get(score, 'diffs.2.rank', 0) : -1,
|
|
_.get(score, 'diffs.3.clear', false) ? _.get(score, 'diffs.3.rank', 0) : -1,
|
|
_.get(score, 'diffs.4.clear', false) ? _.get(score, 'diffs.4.rank', 0) : -1,
|
|
_.get(score, 'diffs.5.clear', false) ? _.get(score, 'diffs.5.rank', 0) : -1,
|
|
_.get(score, 'diffs.6.clear', false) ? _.get(score, 'diffs.6.rank', 0) : -1,
|
|
_.get(score, 'diffs.7.clear', false) ? _.get(score, 'diffs.7.rank', 0) : -1,
|
|
_.get(score, 'diffs.8.clear', false) ? _.get(score, 'diffs.8.rank', 0) : -1,
|
|
0,
|
|
0,
|
|
0,
|
|
]),
|
|
flag: K.ARRAY('u16', [
|
|
_.get(score, 'diffs.1.fc', false) * 2 +
|
|
_.get(score, 'diffs.2.fc', false) * 4 +
|
|
_.get(score, 'diffs.3.fc', false) * 8 +
|
|
_.get(score, 'diffs.4.fc', false) * 16 +
|
|
_.get(score, 'diffs.5.fc', false) * 32 +
|
|
_.get(score, 'diffs.6.fc', false) * 64 +
|
|
_.get(score, 'diffs.7.fc', false) * 128 +
|
|
_.get(score, 'diffs.8.fc', false) * 256,
|
|
_.get(score, 'diffs.1.ex', false) * 2 +
|
|
_.get(score, 'diffs.2.ex', false) * 4 +
|
|
_.get(score, 'diffs.3.ex', false) * 8 +
|
|
_.get(score, 'diffs.4.ex', false) * 16 +
|
|
_.get(score, 'diffs.5.ex', false) * 32 +
|
|
_.get(score, 'diffs.6.ex', false) * 64 +
|
|
_.get(score, 'diffs.7.ex', false) * 128 +
|
|
_.get(score, 'diffs.8.ex', false) * 256,
|
|
_.get(score, 'diffs.1.clear', false) * 2 +
|
|
_.get(score, 'diffs.2.clear', false) * 4 +
|
|
_.get(score, 'diffs.3.clear', false) * 8 +
|
|
_.get(score, 'diffs.4.clear', false) * 16 +
|
|
_.get(score, 'diffs.5.clear', false) * 32 +
|
|
_.get(score, 'diffs.6.clear', false) * 64 +
|
|
_.get(score, 'diffs.7.clear', false) * 128 +
|
|
_.get(score, 'diffs.8.clear', false) * 256,
|
|
0,
|
|
0,
|
|
]),
|
|
sdata: K.ARRAY('s16', score.update),
|
|
meter: K.ARRAY('u64', [
|
|
BigInt(_.get(score, 'diffs.1.meter', '0')),
|
|
BigInt(_.get(score, 'diffs.2.meter', '0')),
|
|
BigInt(_.get(score, 'diffs.3.meter', '0')),
|
|
BigInt(_.get(score, 'diffs.4.meter', '0')),
|
|
BigInt(_.get(score, 'diffs.5.meter', '0')),
|
|
BigInt(_.get(score, 'diffs.6.meter', '0')),
|
|
BigInt(_.get(score, 'diffs.7.meter', '0')),
|
|
BigInt(_.get(score, 'diffs.8.meter', '0')),
|
|
]),
|
|
meter_prog: K.ARRAY('s16', [
|
|
_.get(score, 'diffs.1.prog', 0),
|
|
_.get(score, 'diffs.2.prog', 0),
|
|
_.get(score, 'diffs.3.prog', 0),
|
|
_.get(score, 'diffs.4.prog', 0),
|
|
_.get(score, 'diffs.5.prog', 0),
|
|
_.get(score, 'diffs.6.prog', 0),
|
|
_.get(score, 'diffs.7.prog', 0),
|
|
_.get(score, 'diffs.8.prog', 0),
|
|
]),
|
|
}));
|
|
}
|
|
|
|
const sticker: PlayerStickerResponse[] = getPlayerStickerResponse(name.card);
|
|
const playinfo: PlayerPlayInfoResponse = getPlayerPlayInfoResponse(profile);
|
|
|
|
const playerData: any = {
|
|
playerboard: {
|
|
index: K.ITEM('s32', 1),
|
|
is_active: K.ITEM('bool', _.isArray(name.card) ? 1 : 0),
|
|
sticker,
|
|
},
|
|
player_info: {
|
|
player_type: K.ITEM('s8', 0),
|
|
did: K.ITEM('s32', 13376666),
|
|
name: K.ITEM('str', name.name),
|
|
title: K.ITEM('str', name.title),
|
|
charaid: K.ITEM('s32', 0),
|
|
},
|
|
customdata: {
|
|
playstyle: K.ARRAY('s32', extra.playstyle),
|
|
custom: K.ARRAY('s32', extra.custom),
|
|
},
|
|
playinfo: playinfo,
|
|
tutorial: {
|
|
progress: K.ITEM('s32', profile.progress),
|
|
disp_state: K.ITEM('u32', profile.disp_state),
|
|
},
|
|
skilldata: {
|
|
skill: K.ITEM('s32', profile.skill),
|
|
all_skill: K.ITEM('s32', profile.all_skill),
|
|
old_skill: K.ITEM('s32', 0),
|
|
old_all_skill: K.ITEM('s32', 0),
|
|
},
|
|
favoritemusic: {
|
|
list_1: K.ARRAY('s32', extra.list_1),
|
|
list_2: K.ARRAY('s32', extra.list_2),
|
|
list_3: K.ARRAY('s32', extra.list_3),
|
|
},
|
|
recommend_musicid_list: K.ARRAY('s32', extra.recommend_musicid_list ?? Array(5).fill(-1)),
|
|
record,
|
|
groove: {
|
|
extra_gauge: K.ITEM('s32', (profile.extra_gauge+95)),
|
|
encore_gauge: K.ITEM('s32', profile.encore_gauge),
|
|
encore_cnt: K.ITEM('s32', profile.encore_cnt),
|
|
encore_success: K.ITEM('s32', profile.encore_success),
|
|
unlock_point: K.ITEM('s32', profile.unlock_point),
|
|
},
|
|
musiclist: { '@attr': { nr: musicdata.length }, musicdata },
|
|
deluxe: {
|
|
deluxe_content: K.ITEM('s32', 0),
|
|
target_id: K.ITEM('s32', 0),
|
|
multiply: K.ITEM('s32', 0),
|
|
point: K.ITEM('s32', 0),
|
|
},
|
|
galaxy_parade: {
|
|
score_list: {},
|
|
last_corner_id: K.ITEM('s32', 0),
|
|
chara_list: {},
|
|
last_sort_category: K.ITEM('s32', 0),
|
|
last_sort_order: K.ITEM('s32', 0),
|
|
team_member: {
|
|
chara_id_guitar: K.ITEM('s32', 0),
|
|
chara_id_bass: K.ITEM('s32', 0),
|
|
chara_id_drum: K.ITEM('s32', 0),
|
|
chara_id_free1: K.ITEM('s32', 0),
|
|
chara_id_free2: K.ITEM('s32', 0),
|
|
},
|
|
},
|
|
};
|
|
|
|
const playerRanking = await getPlayerRanking(refid, version, game)
|
|
|
|
const addition: any = {
|
|
monstar_subjugation: {},
|
|
bear_fes: {},
|
|
galaxy_parade: {
|
|
corner_list: {
|
|
corner: {
|
|
is_open: K.ITEM('bool', 0),
|
|
data_ver: K.ITEM('s32', 0),
|
|
genre: K.ITEM('s32', 0),
|
|
corner_id: K.ITEM('s32', 0),
|
|
corner_name: K.ITEM('str', ''),
|
|
start_date_ms: K.ITEM('u64', BigInt(0)),
|
|
end_date_ms: K.ITEM('u64', BigInt(0)),
|
|
requirements_musicid: K.ITEM('s32', 0),
|
|
reward_list: {
|
|
reward: {
|
|
reward_id: K.ITEM('s32', 0),
|
|
reward_kind: K.ITEM('s32', 0),
|
|
reward_itemid: K.ITEM('s32', 0),
|
|
unlock_border: K.ITEM('s32', 0),
|
|
}
|
|
},
|
|
}
|
|
},
|
|
gacha_table: {
|
|
chara_odds: {
|
|
chara_id: K.ITEM('s32', 0),
|
|
odds: K.ITEM('s32', 0),
|
|
}
|
|
},
|
|
bonus: {
|
|
term: K.ITEM('s32', 0),
|
|
stage_bonus: K.ITEM('s32', 0),
|
|
charm_bonus: K.ITEM('s32', 0),
|
|
start_date_ms: K.ITEM('u64', BigInt(0)),
|
|
end_date_ms: K.ITEM('u64', BigInt(0)),
|
|
}
|
|
},
|
|
};
|
|
for (let i = 1; i <= 20; ++i) {
|
|
const obj = { point: K.ITEM('s32', 0) };
|
|
if (i == 1) {
|
|
addition['long_otobear_fes_1'] = obj;
|
|
addition['long_otobear_fes_2'] = obj;
|
|
addition['phrase_combo_challenge'] = obj;
|
|
addition['sdvx_stamprally'] = obj;
|
|
addition['sdvx_stamprally2'] = obj;
|
|
addition['sdvx_stamprally3'] = obj;
|
|
addition['chronicle_1'] = obj;
|
|
addition['gitadora_oracle_1'] = obj;
|
|
addition['gitadora_oracle_2'] = obj;
|
|
} else {
|
|
addition[`phrase_combo_challenge_${i}`] = obj;
|
|
}
|
|
|
|
if (i <= 4) {
|
|
addition.bear_fes[`bear_fes_${i}`] = {
|
|
stage: K.ITEM('s32', 0),
|
|
point: K.ARRAY('s32', [0, 0, 0, 0, 0, 0, 0, 0]),
|
|
};
|
|
}
|
|
|
|
if (i <= 3) {
|
|
addition.monstar_subjugation[`monstar_subjugation_${i}`] = {
|
|
stage: K.ITEM('s32', 0),
|
|
point_1: K.ITEM('s32', 0),
|
|
point_2: K.ITEM('s32', 0),
|
|
point_3: K.ITEM('s32', 0),
|
|
};
|
|
addition[`kouyou_challenge_${i}`] = { point: K.ITEM('s32', 0) };
|
|
addition[`dokidoki_valentine2_${i}`] = { point: K.ITEM('s32', 0) };
|
|
addition[`ohanami_challenge_${i}`] = { point: K.ITEM('s32', 0) };
|
|
addition[`otobear_in_the_tsubo_${i}`] = { point: K.ITEM('s32', 0) };
|
|
addition[`summer_craft_${i}`] = { point: K.ITEM('s32', 0) };
|
|
addition[`wakuteka_whiteday2_${i}`] = {
|
|
point_1: K.ITEM('s32', 0),
|
|
point_2: K.ITEM('s32', 0),
|
|
point_3: K.ITEM('s32', 0),
|
|
};
|
|
}
|
|
}
|
|
|
|
const innerSecretMusic = getSecretMusicResponse(profile)
|
|
const innerFriendData = getFriendDataResponse(profile)
|
|
const innerBattleData = getDefaultBattleDataResponse()
|
|
|
|
const response = {
|
|
player: K.ATTR({ 'no': `${no}` }, {
|
|
now_date: K.ITEM('u64', time),
|
|
secretmusic: {
|
|
music: innerSecretMusic
|
|
},
|
|
chara_list: {},
|
|
title_parts: {},
|
|
information: {
|
|
info: K.ARRAY('u32', Array(50).fill(0)),
|
|
},
|
|
reward: {
|
|
status: K.ARRAY('u32', extra.reward_status ?? Array(50).fill(0)),
|
|
},
|
|
rivaldata: {},
|
|
frienddata: {
|
|
friend: innerFriendData
|
|
},
|
|
|
|
thanks_medal: {
|
|
medal: K.ITEM('s32', 0),
|
|
grant_medal: K.ITEM('s32', 0),
|
|
grant_total_medal: K.ITEM('s32', 0),
|
|
},
|
|
recommend_musicid_list: K.ARRAY('s32', extra.recommend_musicid_list ?? Array(5).fill(-1)),
|
|
skindata: {
|
|
skin: K.ARRAY('u32', Array(100).fill(-1)),
|
|
},
|
|
battledata: innerBattleData,
|
|
is_free_ok: K.ITEM('bool', 0),
|
|
ranking: {
|
|
skill: { rank: K.ITEM('s32', playerRanking.skill), total_nr: K.ITEM('s32', playerRanking.totalPlayers) },
|
|
all_skill: { rank: K.ITEM('s32', playerRanking.all_skill), total_nr: K.ITEM('s32', playerRanking.totalPlayers) },
|
|
},
|
|
stage_result: {},
|
|
monthly_skill: {},
|
|
event_skill: {
|
|
skill: K.ITEM('s32', 0),
|
|
ranking: {
|
|
rank: K.ITEM('s32', 0),
|
|
total_nr: K.ITEM('s32', 0),
|
|
},
|
|
eventlist: {},
|
|
},
|
|
event_score: { eventlist: {} },
|
|
rockwave: { score_list: {} },
|
|
livehouse: {
|
|
score_list: {
|
|
score: {
|
|
term: K.ITEM('u8', -1),
|
|
reward_id: K.ITEM('s32', -1),
|
|
unlock_point: K.ITEM('s32', -1),
|
|
chara_id_guitar: K.ITEM('s32', -1),
|
|
chara_id_bass: K.ITEM('s32', -1),
|
|
chara_id_drum: K.ITEM('s32', -1),
|
|
chara_id_other: K.ITEM('s32', -1),
|
|
leader: K.ITEM('s32', -1),
|
|
},
|
|
last_livehouse: K.ITEM('s32', -1),
|
|
}
|
|
},
|
|
jubeat_omiyage_challenge: {},
|
|
light_mode_reward_item: { itemid: K.ITEM('s32', -1), rarity: K.ITEM('s32', 0) },
|
|
standard_mode_reward_item: { itemid: K.ITEM('s32', -1), rarity: K.ITEM('s32', 0) },
|
|
delux_mode_reward_item: { itemid: K.ITEM('s32', -1), rarity: K.ITEM('s32', 0) },
|
|
kac2018: {
|
|
entry_status: K.ITEM('s32', 0),
|
|
data: {
|
|
term: K.ITEM('s32', 0),
|
|
total_score: K.ITEM('s32', 0),
|
|
score: K.ARRAY('s32', [0, 0, 0, 0, 0, 0]),
|
|
music_type: K.ARRAY('s32', [0, 0, 0, 0, 0, 0]),
|
|
play_count: K.ARRAY('s32', [0, 0, 0, 0, 0, 0]),
|
|
},
|
|
},
|
|
sticker_campaign: {},
|
|
kac2017: {
|
|
entry_status: K.ITEM('s32', 0),
|
|
},
|
|
KAC2016: {
|
|
is_entry: K.ITEM('bool', 0),
|
|
},
|
|
KAC2016_skill_ranking: {
|
|
skill: {
|
|
skill: K.ITEM('s32', -1),
|
|
rank: K.ITEM('s32', -1),
|
|
total_nr: K.ITEM('s32', -1),
|
|
}
|
|
},
|
|
|
|
|
|
|
|
|
|
nostalgia_concert: {},
|
|
bemani_summer_2018: {
|
|
linkage_id: K.ITEM('s32', -1),
|
|
is_entry: K.ITEM('bool', 0),
|
|
target_music_idx: K.ITEM('s32', -1),
|
|
point_1: K.ITEM('s32', 0),
|
|
point_2: K.ITEM('s32', 0),
|
|
point_3: K.ITEM('s32', 0),
|
|
point_4: K.ITEM('s32', 0),
|
|
point_5: K.ITEM('s32', 0),
|
|
point_6: K.ITEM('s32', 0),
|
|
point_7: K.ITEM('s32', 0),
|
|
reward_1: K.ITEM('bool', 0),
|
|
reward_2: K.ITEM('bool', 0),
|
|
reward_3: K.ITEM('bool', 0),
|
|
reward_4: K.ITEM('bool', 0),
|
|
reward_5: K.ITEM('bool', 0),
|
|
reward_6: K.ITEM('bool', 0),
|
|
reward_7: K.ITEM('bool', 0),
|
|
unlock_status_1: K.ITEM('s32', 0),
|
|
unlock_status_2: K.ITEM('s32', 0),
|
|
unlock_status_3: K.ITEM('s32', 0),
|
|
unlock_status_4: K.ITEM('s32', 0),
|
|
unlock_status_5: K.ITEM('s32', 0),
|
|
unlock_status_6: K.ITEM('s32', 0),
|
|
unlock_status_7: K.ITEM('s32', 0),
|
|
},
|
|
thanksgiving: {
|
|
term: K.ITEM("u8", 0),
|
|
score: {
|
|
one_day_play_cnt: K.ITEM("s32", 0),
|
|
one_day_lottery_cnt: K.ITEM("s32", 0),
|
|
lucky_star: K.ITEM("s32", 0),
|
|
bear_mark: K.ITEM("s32", 0),
|
|
play_date_ms: K.ITEM("u64", BigInt(0))
|
|
},
|
|
lottery_result: {
|
|
unlock_bit: K.ITEM("u64", BigInt(0))
|
|
}
|
|
},
|
|
lotterybox: {},
|
|
...addition,
|
|
...playerData,
|
|
finish: K.ITEM('bool', 1),
|
|
}),
|
|
}
|
|
|
|
if (isAsphyxiaDebugMode()) {
|
|
await IO.WriteFile(`apisamples/lastGetPlayerRequest.json`, JSON.stringify(data, null, 4))
|
|
await IO.WriteFile(`apisamples/lastGetPlayerResponse.json`, JSON.stringify(response, null, 4))
|
|
}
|
|
send.object(response);
|
|
}
|
|
|
|
async function getOrRegisterPlayerInfo(refid: string, version: string, no: number) {
|
|
let playerInfo = await DB.FindOne<PlayerInfo>(refid, {
|
|
collection: 'playerinfo',
|
|
version
|
|
});
|
|
|
|
if (!playerInfo) {
|
|
logger.debugInfo(`Registering new profile for player ${no} with refid: ${refid}`);
|
|
playerInfo = await registerUser(refid, version);
|
|
}
|
|
return playerInfo;
|
|
}
|
|
|
|
function getPlayerNo(data: any): number {
|
|
return parseInt($(data).attr("player").no || '1', 10)
|
|
}
|
|
|
|
async function registerUser(refid: string, version: string, id = _.random(0, 99999999)) {
|
|
while (await DB.FindOne<Profile>(null, { collection: 'profile', id })) {
|
|
id = _.random(0, 99999999);
|
|
}
|
|
|
|
const defaultInfo: PlayerInfo = getDefaultPlayerInfo(version, id)
|
|
|
|
const gf = { game: 'gf', version };
|
|
const dm = { game: 'dm', version };
|
|
|
|
await DB.Upsert(refid, { collection: 'playerinfo', version }, defaultInfo);
|
|
await DB.Upsert(refid, { collection: 'profile', ...gf }, getDefaultProfile('gf', version, id));
|
|
await DB.Upsert(refid, { collection: 'profile', ...dm }, getDefaultProfile('dm', version, id));
|
|
await DB.Upsert(refid, { collection: 'record', ...gf }, getDefaultRecord('gf', version));
|
|
await DB.Upsert(refid, { collection: 'record', ...dm }, getDefaultRecord('dm', version));
|
|
await DB.Upsert(refid, { collection: 'extra', ...gf }, getDefaultExtra('gf', version, id));
|
|
await DB.Upsert(refid, { collection: 'extra', ...dm }, getDefaultExtra('dm', version, id));
|
|
await DB.Upsert(refid, { collection: 'scores', ...gf }, getDefaultScores('gf', version));
|
|
await DB.Upsert(refid, { collection: 'scores', ...dm }, getDefaultScores('dm', version));
|
|
|
|
return defaultInfo
|
|
}
|
|
|
|
export const savePlayers: EPR = async (info, data, send) => {
|
|
|
|
const version = getVersion(info);
|
|
const dm = isDM(info);
|
|
const game = dm ? 'dm' : 'gf';
|
|
const sharedScoresEnabled = isSharedSongScoresEnabled();
|
|
|
|
let players = $(data).elements("player")
|
|
|
|
let response = {
|
|
player: [],
|
|
gamemode: _.get(data, 'gamemode'),
|
|
};
|
|
|
|
try
|
|
{
|
|
for (let player of players) {
|
|
|
|
const no = parseInt(player.attr().no || '1', 10)
|
|
// Only save players that are using a profile. Don't try to save guest players.
|
|
const hasCard = player.attr().card === 'use'
|
|
if (!hasCard) {
|
|
logger.debugInfo(`Skipping save for guest ${game} player ${no}.`)
|
|
continue
|
|
}
|
|
|
|
const refid = player.str('refid')
|
|
if (!refid) {
|
|
throw "Request data is missing required parameter: player.refid"
|
|
}
|
|
|
|
await saveSinglePlayer(player, refid, no, version, game, sharedScoresEnabled);
|
|
|
|
let ranking = await getPlayerRanking(refid, version, game)
|
|
let responsePart = getSaveProfileResponse(no, ranking)
|
|
response.player.push(responsePart)
|
|
}
|
|
|
|
if (isAsphyxiaDebugMode()) {
|
|
await IO.WriteFile(`apisamples/lastSavePlayersRequest.json`, JSON.stringify(data, null, 4))
|
|
await IO.WriteFile(`apisamples/lastSavePlayersResponse.json`, JSON.stringify(response, null, 4))
|
|
}
|
|
await send.object(response);
|
|
}
|
|
catch (e) {
|
|
logger.error(e)
|
|
logger.error(e.stack)
|
|
return send.deny();
|
|
}
|
|
};
|
|
|
|
async function saveSinglePlayer(dataplayer: KDataReader, refid: string, no: number, version: string, game: 'gf' | 'dm', sharedScoresEnabled: boolean)
|
|
{
|
|
logger.debugInfo(`Saving ${game} profile for player ${no} with refid: ${refid}`)
|
|
const profile = await getProfile(refid, version, game) as any;
|
|
const extra = await getExtra(refid, version, game) as any;
|
|
const rec = await getRecord(refid, version, game) as any;
|
|
|
|
const autoSet = function (field: keyof Profile, path: string, array = false): void {
|
|
if (array) {
|
|
profile[field] = dataplayer.numbers(path, profile[field])
|
|
} else {
|
|
profile[field] = dataplayer.number(path, profile[field])
|
|
}
|
|
};
|
|
|
|
const autoExtra = (field: keyof Extra, path: string, array = false): void => {
|
|
if (array) {
|
|
extra[field] = dataplayer.numbers(path, extra[field])
|
|
} else {
|
|
extra[field] = dataplayer.number(path, extra[field])
|
|
}
|
|
};
|
|
|
|
const autoRec = (field: keyof Record, path: string, array = false): void => {
|
|
if (array) {
|
|
rec[field] = dataplayer.numbers(path, rec[field])
|
|
} else {
|
|
rec[field] = dataplayer.number(path, rec[field])
|
|
}
|
|
};
|
|
|
|
let newSecretMusic = parseSecretMusic(dataplayer)
|
|
profile.secretmusic = {
|
|
music: newSecretMusic
|
|
}
|
|
|
|
autoSet('max_skill', 'record.max.skill');
|
|
autoSet('max_all_skill', 'record.max.all_skill');
|
|
autoSet('clear_diff', 'record.max.clear_diff');
|
|
autoSet('full_diff', 'record.max.full_diff');
|
|
autoSet('exce_diff', 'record.max.exce_diff');
|
|
autoSet('clear_music_num', 'record.max.clear_music_num');
|
|
autoSet('full_music_num', 'record.max.full_music_num');
|
|
autoSet('exce_music_num', 'record.max.exce_music_num');
|
|
autoSet('clear_seq_num', 'record.max.clear_seq_num');
|
|
autoSet('classic_all_skill', 'record.max.classic_all_skill');
|
|
|
|
autoSet('play', 'playinfo.play');
|
|
autoSet('playtime', 'playinfo.playtime');
|
|
autoSet('playterm', 'playinfo.playterm');
|
|
autoSet('session_cnt', 'playinfo.session_cnt');
|
|
autoSet('extra_stage', 'playinfo.extra_stage');
|
|
autoSet('extra_play', 'playinfo.extra_play');
|
|
autoSet('extra_clear', 'playinfo.extra_clear');
|
|
autoSet('encore_play', 'playinfo.encore_play');
|
|
autoSet('encore_clear', 'playinfo.encore_clear');
|
|
autoSet('pencore_play', 'playinfo.pencore_play');
|
|
autoSet('pencore_clear', 'playinfo.pencore_clear');
|
|
autoSet('max_clear_diff', 'playinfo.max_clear_diff');
|
|
autoSet('max_full_diff', 'playinfo.max_full_diff');
|
|
autoSet('max_exce_diff', 'playinfo.max_exce_diff');
|
|
autoSet('clear_num', 'playinfo.clear_num');
|
|
autoSet('full_num', 'playinfo.full_num');
|
|
autoSet('exce_num', 'playinfo.exce_num');
|
|
autoSet('no_num', 'playinfo.no_num');
|
|
autoSet('e_num', 'playinfo.e_num');
|
|
autoSet('d_num', 'playinfo.d_num');
|
|
autoSet('c_num', 'playinfo.c_num');
|
|
autoSet('b_num', 'playinfo.b_num');
|
|
autoSet('a_num', 'playinfo.a_num');
|
|
autoSet('s_num', 'playinfo.s_num');
|
|
autoSet('ss_num', 'playinfo.ss_num');
|
|
autoSet('last_category', 'playinfo.last_category');
|
|
autoSet('last_musicid', 'playinfo.last_musicid');
|
|
autoSet('last_seq', 'playinfo.last_seq');
|
|
autoSet('disp_level', 'playinfo.disp_level');
|
|
|
|
autoSet('extra_gauge', 'groove.extra_gauge');
|
|
autoSet('encore_gauge', 'groove.encore_gauge');
|
|
autoSet('encore_cnt', 'groove.encore_cnt');
|
|
autoSet('encore_success', 'groove.encore_success');
|
|
autoSet('unlock_point', 'groove.unlock_point');
|
|
|
|
autoSet('progress', 'tutorial.progress');
|
|
autoSet('disp_state', 'tutorial.disp_state');
|
|
|
|
autoSet('skill', 'skilldata.skill');
|
|
autoSet('all_skill', 'skilldata.all_skill');
|
|
|
|
autoRec('diff_100_nr', 'record.diff.diff_100_nr');
|
|
autoRec('diff_150_nr', 'record.diff.diff_150_nr');
|
|
autoRec('diff_200_nr', 'record.diff.diff_200_nr');
|
|
autoRec('diff_250_nr', 'record.diff.diff_250_nr');
|
|
autoRec('diff_300_nr', 'record.diff.diff_300_nr');
|
|
autoRec('diff_350_nr', 'record.diff.diff_350_nr');
|
|
autoRec('diff_400_nr', 'record.diff.diff_400_nr');
|
|
autoRec('diff_450_nr', 'record.diff.diff_450_nr');
|
|
autoRec('diff_500_nr', 'record.diff.diff_500_nr');
|
|
autoRec('diff_550_nr', 'record.diff.diff_550_nr');
|
|
autoRec('diff_600_nr', 'record.diff.diff_600_nr');
|
|
autoRec('diff_650_nr', 'record.diff.diff_650_nr');
|
|
autoRec('diff_700_nr', 'record.diff.diff_700_nr');
|
|
autoRec('diff_750_nr', 'record.diff.diff_750_nr');
|
|
autoRec('diff_800_nr', 'record.diff.diff_800_nr');
|
|
autoRec('diff_850_nr', 'record.diff.diff_850_nr');
|
|
autoRec('diff_900_nr', 'record.diff.diff_900_nr');
|
|
autoRec('diff_950_nr', 'record.diff.diff_950_nr');
|
|
autoRec('diff_100_clear', 'record.diff.diff_100_clear', true);
|
|
autoRec('diff_150_clear', 'record.diff.diff_150_clear', true);
|
|
autoRec('diff_200_clear', 'record.diff.diff_200_clear', true);
|
|
autoRec('diff_250_clear', 'record.diff.diff_250_clear', true);
|
|
autoRec('diff_300_clear', 'record.diff.diff_300_clear', true);
|
|
autoRec('diff_350_clear', 'record.diff.diff_350_clear', true);
|
|
autoRec('diff_400_clear', 'record.diff.diff_400_clear', true);
|
|
autoRec('diff_450_clear', 'record.diff.diff_450_clear', true);
|
|
autoRec('diff_500_clear', 'record.diff.diff_500_clear', true);
|
|
autoRec('diff_550_clear', 'record.diff.diff_550_clear', true);
|
|
autoRec('diff_600_clear', 'record.diff.diff_600_clear', true);
|
|
autoRec('diff_650_clear', 'record.diff.diff_650_clear', true);
|
|
autoRec('diff_700_clear', 'record.diff.diff_700_clear', true);
|
|
autoRec('diff_750_clear', 'record.diff.diff_750_clear', true);
|
|
autoRec('diff_800_clear', 'record.diff.diff_800_clear', true);
|
|
autoRec('diff_850_clear', 'record.diff.diff_850_clear', true);
|
|
autoRec('diff_900_clear', 'record.diff.diff_900_clear', true);
|
|
autoRec('diff_950_clear', 'record.diff.diff_950_clear', true);
|
|
|
|
autoExtra('list_1', 'favoritemusic.music_list_1', true);
|
|
autoExtra('list_2', 'favoritemusic.music_list_2', true);
|
|
autoExtra('list_3', 'favoritemusic.music_list_3', true);
|
|
autoExtra('recommend_musicid_list', 'recommend_musicid_list', true);
|
|
|
|
autoExtra('playstyle', 'customdata.playstyle', true);
|
|
autoExtra('custom', 'customdata.custom', true);
|
|
autoExtra('reward_status', 'reward.status', true)
|
|
|
|
await DB.Upsert(refid, { collection: 'profile', game, version }, profile)
|
|
await DB.Upsert(refid, { collection: 'record', game, version }, rec)
|
|
await DB.Upsert(refid, { collection: 'extra', game, version }, extra)
|
|
|
|
const playedStages = dataplayer.elements('stage');
|
|
logStagesPlayed(playedStages)
|
|
|
|
const scores = await updatePlayerScoreCollection(refid, playedStages, version, game)
|
|
await saveScore(refid, version, game, scores);
|
|
|
|
if (sharedScoresEnabled) {
|
|
await mergeScoresIntoShared(refid, game, scores);
|
|
}
|
|
await saveSharedFavoriteMusicFromExtra(refid, extra)
|
|
}
|
|
|
|
async function updatePlayerScoreCollection(refid, playedStages, version, game) {
|
|
const scores = (await getScore(refid, version, game)).scores;
|
|
for (const stage of playedStages) {
|
|
const mid = stage.number('musicid', -1);
|
|
const seq = stage.number('seq', -1);
|
|
|
|
if (mid < 0 || seq < 0) continue;
|
|
|
|
// const skill = stage.number('skill', 0);
|
|
const newSkill = stage.number('new_skill', 0);
|
|
const clear = stage.bool('clear');
|
|
const fc = stage.bool('fullcombo');
|
|
const ex = stage.bool('excellent');
|
|
const newMeter = stage.bool('is_new_meter');
|
|
|
|
const perc = stage.number('perc', 0);
|
|
const rank = stage.number('rank', 0);
|
|
const meter = stage.bigint('meter', BigInt(0));
|
|
const prog = stage.number('meter_prog', 0);
|
|
|
|
if(!scores[mid]) {
|
|
scores[mid] = {
|
|
update: [0, 0],
|
|
diffs: {}
|
|
}
|
|
}
|
|
|
|
if (newSkill > scores[mid].update[1]) {
|
|
scores[mid].update[0] = seq;
|
|
scores[mid].update[1] = newSkill;
|
|
}
|
|
|
|
scores[mid].diffs[seq] = { //FIXME: Real server is bit complicated. this one is too buggy.
|
|
perc: Math.max(_.get(scores[mid].diffs[seq], 'perc', 0), perc),
|
|
rank: Math.max(_.get(scores[mid].diffs[seq], 'rank', 0), rank),
|
|
meter: newMeter ? meter.toString() : _.get(scores[mid].diffs[seq], 'meter', 0),
|
|
prog: Math.max(_.get(scores[mid].diffs[seq], 'prog', 0), prog),
|
|
clear: _.get(scores[mid].diffs[seq], 'clear') || clear,
|
|
fc: _.get(scores[mid].diffs[seq], 'fc') || fc,
|
|
ex: _.get(scores[mid].diffs[seq], 'ex') || ex,
|
|
};
|
|
}
|
|
|
|
return scores
|
|
}
|
|
|
|
async function getPlayerRanking(refid: string, version: string, game: 'gf' | 'dm') : Promise<PlayerRanking> {
|
|
let profiles = await getAllProfiles(version, game)
|
|
let playerCount = profiles.length
|
|
let sortedProfilesA = profiles.sort((a,b) => b.skill - a.skill)
|
|
let sortedProfilesB = profiles.sort((a,b) => b.all_skill - a.all_skill)
|
|
|
|
let idxA = _.findIndex(sortedProfilesA, (e) => e.__refid === refid)
|
|
idxA = idxA > -1 ? idxA + 1 : playerCount // Default to last place if not found in the DB.
|
|
let idxB = _.findIndex(sortedProfilesB, (e) => e.__refid === refid)
|
|
idxB = idxB > -1 ? idxB + 1 : playerCount // Default to last place if not found in the DB.
|
|
|
|
return {
|
|
refid,
|
|
skill: idxA,
|
|
all_skill: idxB,
|
|
totalPlayers: playerCount
|
|
}
|
|
}
|
|
|
|
async function getAllProfiles( version: string, game: 'gf' | 'dm') {
|
|
return await DB.Find<Profile>(null, {
|
|
collection: 'profile',
|
|
version: version,
|
|
game: game
|
|
})
|
|
}
|
|
|
|
async function getProfile(refid: string, version: string, game: 'gf' | 'dm') {
|
|
return await DB.FindOne<Profile>(refid, {
|
|
collection: 'profile',
|
|
version: version,
|
|
game: game
|
|
})
|
|
}
|
|
|
|
async function getExtra(refid: string, version: string, game: 'gf' | 'dm') {
|
|
return await DB.FindOne<Extra>(refid, {
|
|
collection: 'extra',
|
|
version: version,
|
|
game: game
|
|
})
|
|
}
|
|
|
|
async function getRecord(refid: string, version: string, game: 'gf' | 'dm') {
|
|
return await DB.FindOne<Record>(refid, {
|
|
collection: 'record',
|
|
version: version,
|
|
game: game
|
|
})
|
|
}
|
|
|
|
async function getScore(refid: string, version: string, game: 'gf' | 'dm'): Promise<Scores> {
|
|
return (await DB.FindOne<Scores>(refid, {
|
|
collection: 'scores',
|
|
version: version,
|
|
game: game
|
|
})) || {
|
|
collection: 'scores',
|
|
version: version,
|
|
pluginVer: PLUGIN_VER,
|
|
game: game,
|
|
scores: {}
|
|
}
|
|
}
|
|
|
|
async function saveScore(refid: string, version: string, game: 'gf' | 'dm', scores: Scores['scores']) {
|
|
return await DB.Upsert<Scores>(refid, {
|
|
collection: 'scores',
|
|
version,
|
|
game
|
|
}, {
|
|
collection: 'scores',
|
|
version,
|
|
game,
|
|
scores
|
|
})
|
|
}
|
|
|
|
function parseSecretMusic(playerData: KDataReader) : SecretMusicEntry[]
|
|
{
|
|
let response : SecretMusicEntry[] = []
|
|
|
|
let elements = playerData.element('secretmusic')?.elements('music')
|
|
if (!elements) {
|
|
return response
|
|
}
|
|
|
|
for (let el of elements) {
|
|
let item : SecretMusicEntry = {
|
|
musicid: el.number('musicid'),
|
|
seq: el.number('seq'),
|
|
kind: el.number('kind')
|
|
}
|
|
|
|
response.push(item)
|
|
}
|
|
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)
|
|
}
|