mirror of https://github.com/hykilpikonna/AquaDX
Merge branch 'v1-dev' into pr/99
commit
3a69717a9d
|
@ -92,7 +92,7 @@
|
|||
user = u
|
||||
return fetchData()
|
||||
}).catch((e) => { loading = false; error = e.message });
|
||||
|
||||
|
||||
let DDSreader: DDS | undefined;
|
||||
|
||||
let USERBOX_PROGRESS = 0;
|
||||
|
@ -150,7 +150,7 @@
|
|||
if (databaseExists || USERBOX_URL_STATE.value) {
|
||||
DDSreader = new DDS(ddsDB);
|
||||
USERBOX_INSTALLED = databaseExists || USERBOX_URL_STATE.value != "";
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
</script>
|
||||
|
@ -183,10 +183,10 @@
|
|||
</div>
|
||||
{:else}
|
||||
<div class="chuni-userbox-container">
|
||||
<ChuniUserplateComponent chuniIsUserbox={true} on:click={() => userboxSelected = "nameplateId"} chuniCharacter={userbox.characterId} chuniLevel={userbox.level.toString()} chuniRating={userbox.playerRating / 100}
|
||||
<ChuniUserplateComponent chuniIsUserbox={true} on:click={() => userboxSelected = "nameplateId"} chuniCharacter={userbox.characterId} chuniLevel={userbox.level.toString()} chuniRating={userbox.playerRating / 100}
|
||||
chuniNameplate={userbox.nameplateId} chuniName={userbox.userName} chuniTrophyName={allItems.trophy[userbox.trophyId].name}></ChuniUserplateComponent>
|
||||
<ChuniPenguinComponent chuniWear={userbox.avatarWear} chuniHead={userbox.avatarHead} chuniBack={userbox.avatarBack}
|
||||
chuniFront={userbox.avatarFront} chuniFace={userbox.avatarFace} chuniItem={userbox.avatarItem}
|
||||
<ChuniPenguinComponent chuniWear={userbox.avatarWear} chuniHead={userbox.avatarHead} chuniBack={userbox.avatarBack}
|
||||
chuniFront={userbox.avatarFront} chuniFace={userbox.avatarFace} chuniItem={userbox.avatarItem}
|
||||
chuniSkin={userbox.avatarSkin}></ChuniPenguinComponent>
|
||||
</div>
|
||||
<div class="chuni-userbox-row">
|
||||
|
@ -258,26 +258,11 @@
|
|||
<p>
|
||||
<button on:click={() => USERBOX_SETUP_RUN = !USERBOX_SETUP_RUN}>{t(!USERBOX_INSTALLED ? `userbox.new.activate_first` : `userbox.new.activate_update`)}</button>
|
||||
</p>
|
||||
{/if}
|
||||
{/if}
|
||||
<ChuniMatchingSettings/>
|
||||
<!--{#if !USERBOX_SUPPORT || !USERBOX_INSTALLED || !USERBOX_ENABLED.value}
|
||||
<h2>{t("userbox.header.preview")}</h2>
|
||||
<p class="notice">{t("userbox.preview.notice")}</p>
|
||||
<input bind:value={preview} placeholder={t("userbox.preview.url")}/>
|
||||
{#if preview}
|
||||
<div class="preview">
|
||||
{#each userItems.filter(v => v.iKey != 'trophy' && v.iKey != 'systemVoice') as { iKey, ubKey, items }, i}
|
||||
<div>
|
||||
<span>{ts(`userbox.${ubKey}`)}</span>
|
||||
<img src={`${preview}/${iKey}/${userbox[ubKey].toString().padStart(8, '0')}.png`} alt="" on:error={coverNotFound} />
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
{/if}
|
||||
{/if}-->
|
||||
</div>
|
||||
{/if}
|
||||
|
||||
|
||||
{#if USERBOX_SETUP_RUN && !error}
|
||||
<div class="overlay" transition:fade>
|
||||
<div>
|
||||
|
@ -328,7 +313,7 @@ p.notice
|
|||
opacity: 0.6
|
||||
margin-top: 0
|
||||
|
||||
.progress
|
||||
.progress
|
||||
width: 100%
|
||||
height: 10px
|
||||
box-shadow: 0 0 1px 1px vars.$ov-lighter
|
||||
|
@ -463,10 +448,10 @@ p.notice
|
|||
&.focused
|
||||
filter: brightness(75%)
|
||||
|
||||
.chuni-userbox
|
||||
.chuni-userbox
|
||||
width: calc(100% - 20px)
|
||||
height: 350px
|
||||
|
||||
|
||||
display: flex
|
||||
flex-direction: row
|
||||
flex-wrap: wrap
|
||||
|
|
|
@ -161,4 +161,4 @@ export interface ChusanMatchingOption {
|
|||
matching: string
|
||||
reflector: string
|
||||
coop: string[]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -102,7 +102,7 @@ const zhHome: typeof EN_REF_HOME = {
|
|||
'home.linkcard.account-card': "账户卡",
|
||||
'home.linkcard.registered': "注册于",
|
||||
'home.linkcard.lastused': "上次使用",
|
||||
'home.linkcard.enter-info': "请输入以下信息",
|
||||
'home.linkcard.enter-info': "请输入以下信息,或将 aime.txt / felica.txt 文件拖放到此区域",
|
||||
'home.linkcard.access-code': "卡背面的20位卡号 (如果没有, 请尝试在游戏中扫描您的卡, 并输入屏幕上显示的卡号)",
|
||||
'home.linkcard.enter-sn1': "在您的手机",
|
||||
'home.linkcard.enter-sn2': "上下载 NFC Tools 并扫描您的卡。然后输入显示的 SN 号。",
|
||||
|
@ -148,10 +148,14 @@ const zhSettings: typeof EN_REF_SETTINGS = {
|
|||
'settings.fields.waccaInfiniteWp.desc': '将 WP 设置为 999999',
|
||||
'settings.fields.waccaAlwaysVip.name': 'Wacca: 永久会员',
|
||||
'settings.fields.waccaAlwaysVip.desc': '将 VIP 到期时间设置为 2077-01-01',
|
||||
'settings.fields.chusanTeamName.name': '中二: 队伍名称',
|
||||
'settings.fields.chusanTeamName.name': '队伍名称',
|
||||
'settings.fields.chusanTeamName.desc': '自定义显示在个人资料顶部的文本。',
|
||||
'settings.fields.chusanInfinitePenguins.name': '中二: 无限企鹅',
|
||||
'settings.fields.chusanInfinitePenguins.name': '我是桐谷遥',
|
||||
'settings.fields.chusanInfinitePenguins.desc': '将角色界限突破的企鹅雕像数量设置为 999。',
|
||||
'settings.fields.chusanMatchingReflector.name': '全国对战 Reflector',
|
||||
'settings.fields.chusanMatchingReflector.desc': '全国对战服务器的 UDP 反射服务器的 URL',
|
||||
'settings.fields.chusanMatchingServer.name': '全国对战服务器',
|
||||
'settings.fields.chusanMatchingServer.desc': '全国对战服务器的 URL',
|
||||
'settings.fields.rounding.name': '分数舍入',
|
||||
'settings.fields.rounding.desc': '把分数四舍五入到一位小数',
|
||||
'settings.fields.optOutOfLeaderboard.name': '不参与排行榜',
|
||||
|
@ -168,10 +172,12 @@ const zhSettings: typeof EN_REF_SETTINGS = {
|
|||
'settings.profile.unset': '未设置',
|
||||
'settings.profile.unchanged': '未更改',
|
||||
'settings.export': '导出玩家数据',
|
||||
'settings.cabNotice': '注意:下面这些设置只会影响你自己的机器,如果你是在其他人的机器上玩的话,请联系机主来改设置'
|
||||
}
|
||||
|
||||
export const zhUserbox: typeof EN_REF_USERBOX = {
|
||||
'userbox.header.general': '游戏设置',
|
||||
'userbox.header.matching': '全国对战',
|
||||
'userbox.header.userbox': 'UserBox 设置',
|
||||
'userbox.header.preview': 'UserBox 预览',
|
||||
'userbox.nameplateId': '名牌',
|
||||
|
@ -189,7 +195,15 @@ export const zhUserbox: typeof EN_REF_USERBOX = {
|
|||
'userbox.preview.notice': '「生存战略」:为了尊重版权,我们不会提供游戏内物品的图片。但是如果你认识其他愿意提供图床的人,在这里输入 URL 就可以显示出预览。',
|
||||
'userbox.preview.url': '图床 URL',
|
||||
'userbox.error.nodata': '未找到中二数据',
|
||||
|
||||
|
||||
'userbox.matching.select': '选择对战服务器',
|
||||
'userbox.matching.select.sub': '选择你想加入的跨服全国对战服务器',
|
||||
'userbox.matching.option.ui': '房间列表',
|
||||
'userbox.matching.option.guide': '教程',
|
||||
'userbox.matching.option.collab': '合作伙伴',
|
||||
'userbox.matching.custom.name': '自定义',
|
||||
'userbox.matching.custom.sub': '输入其他的匹配 URL',
|
||||
|
||||
'userbox.new.name': 'AquaBox',
|
||||
'userbox.new.setup': '将 Chuni(Lumi 或更高版本)的游戏文件夹拖放到下方区域,以显示带有名牌和头像的 UserBox。所有文件都在浏览器中处理。',
|
||||
'userbox.new.setup.processing_file': '正在处理文件',
|
||||
|
|
|
@ -312,4 +312,6 @@ export const SETTING = {
|
|||
post('/api/v2/settings/get', {}),
|
||||
set: (key: string, value: any) =>
|
||||
post('/api/v2/settings/set', { key, value: `${value}` }),
|
||||
detailSet: (game: string, field: string, value: any) =>
|
||||
post(`/api/v2/game/${game}/user-detail-set`, { field, value }),
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ const validateDirectories = async (base: FileSystemDirectoryEntry, path: string)
|
|||
let newDirectory = await getDirectory(directory, part).catch(_ => null);
|
||||
if (newDirectory && isDirectory(newDirectory)) {
|
||||
directory = newDirectory;
|
||||
} else
|
||||
} else
|
||||
return false;
|
||||
};
|
||||
return true
|
||||
|
@ -38,7 +38,7 @@ const getDirectoryFromPath = async (base: FileSystemDirectoryEntry, path: string
|
|||
let newDirectory = await getDirectory(directory, part).catch(_ => null);
|
||||
if (newDirectory && isDirectory(newDirectory)) {
|
||||
directory = newDirectory;
|
||||
} else
|
||||
} else
|
||||
return null;
|
||||
};
|
||||
return directory;
|
||||
|
@ -81,7 +81,7 @@ const DIRECTORY_PATHS = ([
|
|||
processName: "Surfboard Textures",
|
||||
useFileName: true,
|
||||
path: "surfboard",
|
||||
filter: (name: string) =>
|
||||
filter: (name: string) =>
|
||||
([
|
||||
"CHU_UI_Common_Avatar_body_00.dds",
|
||||
"CHU_UI_Common_Avatar_face_00.dds",
|
||||
|
@ -134,7 +134,7 @@ export const scanOptionFolder = async (optionFolder: FileSystemDirectoryEntry, p
|
|||
let objectStore = transaction.objectStore('dds');
|
||||
for (let object of data)
|
||||
objectStore.put(object)
|
||||
|
||||
|
||||
// await transaction completion
|
||||
await new Promise(r => transaction.addEventListener("complete", r, {once: true}))
|
||||
};
|
||||
|
@ -163,7 +163,7 @@ export function initializeDb() : Promise<void> {
|
|||
export async function userboxFileProcess(folder: FileSystemEntry, progressUpdate: (progress: number, progressString: string) => void): Promise<string | null> {
|
||||
if (!isDirectory(folder))
|
||||
return t("userbox.new.error.invalidFolder")
|
||||
if (!(await validateDirectories(folder, "bin/option")) || !(await validateDirectories(folder, "data/A000")))
|
||||
if (!(await validateDirectories(folder, "bin/option")) && !(await validateDirectories(folder, "data/A000")))
|
||||
return t("userbox.new.error.invalidFolder");
|
||||
|
||||
initializeDb();
|
||||
|
@ -179,4 +179,4 @@ export async function userboxFileProcess(folder: FileSystemEntry, progressUpdate
|
|||
location.reload();
|
||||
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
|
|
@ -161,13 +161,10 @@
|
|||
let inputAC = ""
|
||||
let errorAC = ""
|
||||
|
||||
function inputACChange(e: any) {
|
||||
e = e as InputEvent
|
||||
function inputACChange() {
|
||||
// Add spaces to the input
|
||||
const old = inputAC
|
||||
if (e.inputType === "insertText" && inputAC.length % 5 === 4 && inputAC.length < 24)
|
||||
inputAC += " "
|
||||
inputAC = inputAC.slice(0, 24)
|
||||
inputAC = inputAC.replace(/\D/g, '').replace(/(.{4})/g, '$1 ').replace(/ $/, '')
|
||||
if (inputAC !== old) errorAC = ""
|
||||
}
|
||||
|
||||
|
@ -176,13 +173,10 @@
|
|||
let inputSN = ""
|
||||
let errorSN = ""
|
||||
|
||||
function inputSNChange(e: any) {
|
||||
e = e as InputEvent
|
||||
function inputSNChange() {
|
||||
// Add colons to the input
|
||||
const old = inputSN
|
||||
if (e.inputType === "insertText" && inputSN.length % 3 === 2 && inputSN.length < 23)
|
||||
inputSN += ":"
|
||||
inputSN = inputSN.toUpperCase().slice(0, 23)
|
||||
inputSN = inputSN.toUpperCase().replace(/[^0-9A-F]/g, '').replace(/(.{2})/g, '$1:').replace(/:$/, '')
|
||||
if (inputSN !== old) errorSN = ""
|
||||
}
|
||||
|
||||
|
@ -209,9 +203,29 @@
|
|||
function isInput(e: KeyboardEvent) {
|
||||
return e.key.length === 1 && !e.altKey && !e.ctrlKey && !e.metaKey && !e.shiftKey
|
||||
}
|
||||
|
||||
async function dropFile(e: DragEvent) {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
const file = e.dataTransfer?.files[0]
|
||||
if (!file) return
|
||||
switch (file.name.toLowerCase()) {
|
||||
case "aime.txt":
|
||||
inputSN = ""
|
||||
inputAC = await file.text()
|
||||
inputACChange()
|
||||
break
|
||||
case "felica.txt":
|
||||
inputAC = ""
|
||||
inputSN = await file.text()
|
||||
inputSNChange()
|
||||
break
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="link-card">
|
||||
<!-- svelte-ignore a11y-no-static-element-interactions -->
|
||||
<div class="link-card" on:drop={dropFile} on:dragover={(e) => e.preventDefault()}>
|
||||
<h2>{t('home.linkcard.cards')}</h2>
|
||||
<p>{t('home.linkcard.description')}:</p>
|
||||
|
||||
|
|
|
@ -195,7 +195,7 @@
|
|||
|
||||
<div class="rank">
|
||||
<span>{t('UserHome.ServerRank')}</span>
|
||||
<span>#{+d.user.serverRank.toLocaleString() + 1}</span>
|
||||
<span>#{(d.user.serverRank + 1).toLocaleString()}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -1,251 +1,255 @@
|
|||
<script lang="ts">
|
||||
import { Turnstile } from "svelte-turnstile";
|
||||
import { slide } from 'svelte/transition';
|
||||
import { TURNSTILE_SITE_KEY } from "../libs/config";
|
||||
import Icon from "@iconify/svelte";
|
||||
import { USER } from "../libs/sdk";
|
||||
import { t } from "../libs/i18n"
|
||||
|
||||
let params = new URLSearchParams(window.location.search)
|
||||
|
||||
let state = "home"
|
||||
$: isSignup = state === "signup"
|
||||
let submitting = false
|
||||
|
||||
let email = ""
|
||||
let password = ""
|
||||
let username = ""
|
||||
let turnstile = ""
|
||||
let turnstileReset: () => void | undefined;
|
||||
|
||||
let error = ""
|
||||
let verifyMsg = ""
|
||||
|
||||
if (params.get('confirm-email')) {
|
||||
state = 'verify'
|
||||
verifyMsg = t("welcome.verifying")
|
||||
submitting = true
|
||||
|
||||
// Send request to server
|
||||
USER.confirmEmail(params.get('confirm-email')!)
|
||||
.then(() => {
|
||||
verifyMsg = t('welcome.verified')
|
||||
submitting = false
|
||||
|
||||
// Clear the query param
|
||||
window.history.replaceState({}, document.title, window.location.pathname)
|
||||
})
|
||||
.catch(e => verifyMsg = t('welcome.verification-failed', { message: e.message }))
|
||||
}
|
||||
|
||||
async function submit(): Promise<any> {
|
||||
submitting = true
|
||||
|
||||
// Check if username and password are valid
|
||||
if (email === "" || password === "") {
|
||||
error = t("welcome.email-password-missing")
|
||||
return submitting = false
|
||||
}
|
||||
|
||||
if (turnstile === "") {
|
||||
// Sleep for 100ms to allow Turnstile to finish
|
||||
error = t("welcome.waiting-turnstile")
|
||||
return setTimeout(submit, 100)
|
||||
}
|
||||
|
||||
// Signup
|
||||
if (isSignup) {
|
||||
if (username === "") {
|
||||
error = t("welcome.username-missing")
|
||||
return submitting = false
|
||||
}
|
||||
|
||||
// Send request to server
|
||||
await USER.register({ username, email, password, turnstile })
|
||||
.then(() => {
|
||||
// Show verify email message
|
||||
state = 'verify'
|
||||
verifyMsg = t("welcome.verification-sent", { email })
|
||||
})
|
||||
.catch(e => {
|
||||
error = e.message
|
||||
submitting = false
|
||||
turnstileReset()
|
||||
})
|
||||
}
|
||||
else {
|
||||
// Send request to server
|
||||
await USER.login({ email, password, turnstile })
|
||||
.then(() => window.location.href = "/home")
|
||||
.catch(e => {
|
||||
if (e.message === 'Email not verified - STATE_0') {
|
||||
state = 'verify'
|
||||
verifyMsg = t("welcome.verify-state-0")
|
||||
}
|
||||
else if (e.message === 'Email not verified - STATE_1') {
|
||||
state = 'verify'
|
||||
verifyMsg = t("welcome.verify-state-1")
|
||||
}
|
||||
else if (e.message === 'Email not verified - STATE_2') {
|
||||
state = 'verify'
|
||||
verifyMsg = t("welcome.verify-state-2")
|
||||
}
|
||||
else {
|
||||
error = e.message
|
||||
submitting = false
|
||||
turnstileReset()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
submitting = false
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<main id="home" class="no-margin">
|
||||
<div>
|
||||
<h1 id="title">AquaNet</h1>
|
||||
{#if state === "home"}
|
||||
<div class="btn-group" transition:slide>
|
||||
<button on:click={() => state = 'login'}>{t('welcome.btn-login')}</button>
|
||||
<button on:click={() => state = 'signup'}>{t('welcome.btn-signup')}</button>
|
||||
</div>
|
||||
{:else if state === "login" || state === "signup"}
|
||||
<div class="login-form" transition:slide>
|
||||
{#if error}
|
||||
<span class="error">{error}</span>
|
||||
{/if}
|
||||
<div on:click={() => state = 'home'} on:keypress={() => state = 'home'}
|
||||
role="button" tabindex="0" class="clickable">
|
||||
<Icon icon="line-md:chevron-small-left" />
|
||||
<span>{t('back')}</span>
|
||||
</div>
|
||||
{#if isSignup}
|
||||
<input type="text" placeholder={t('username')} bind:value={username}>
|
||||
{/if}
|
||||
<input type="email" placeholder={t('email')} bind:value={email}>
|
||||
<input type="password" placeholder={t('password')} bind:value={password}>
|
||||
<button on:click={submit}>
|
||||
{#if submitting}
|
||||
<Icon icon="line-md:loading-twotone-loop"/>
|
||||
{:else}
|
||||
{isSignup ? t('welcome.btn-signup') : t('welcome.btn-login')}
|
||||
{/if}
|
||||
</button>
|
||||
<Turnstile siteKey={TURNSTILE_SITE_KEY} bind:reset={turnstileReset}
|
||||
on:turnstile-callback={e => console.log(turnstile = e.detail.token)}
|
||||
on:turnstile-error={_ => console.log(error = t("welcome.turnstile-error"))}
|
||||
on:turnstile-expired={_ => window.location.reload()}
|
||||
on:turnstile-timeout={_ => console.log(error = t('welcome.turnstile-timeout'))} />
|
||||
</div>
|
||||
{:else if state === "verify"}
|
||||
<div class="login-form" transition:slide>
|
||||
<span>{verifyMsg}</span>
|
||||
{#if !submitting}
|
||||
<button on:click={() => state = 'home'} transition:slide>{t('back')}</button>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<div class="light-pollution">
|
||||
<div class="l1"></div>
|
||||
<div class="l2"></div>
|
||||
<div class="l3"></div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<style lang="sass">
|
||||
@use "../vars"
|
||||
|
||||
.login-form
|
||||
display: flex
|
||||
flex-direction: column
|
||||
gap: 8px
|
||||
width: calc(100% - 12px)
|
||||
max-width: 300px
|
||||
|
||||
div.clickable
|
||||
display: flex
|
||||
align-items: center
|
||||
|
||||
#home
|
||||
color: vars.$c-main
|
||||
position: relative
|
||||
width: 100%
|
||||
height: 100%
|
||||
padding-left: 100px
|
||||
overflow: hidden
|
||||
background-color: black
|
||||
|
||||
box-sizing: border-box
|
||||
|
||||
display: flex
|
||||
flex-direction: column
|
||||
justify-content: center
|
||||
|
||||
margin-top: -(vars.$nav-height)
|
||||
|
||||
// Content container
|
||||
> div
|
||||
display: flex
|
||||
flex-direction: column
|
||||
align-items: flex-start
|
||||
width: max-content
|
||||
|
||||
// Switching state container
|
||||
> div
|
||||
transition: vars.$transition
|
||||
|
||||
#title
|
||||
font-family: Quicksand, vars.$font
|
||||
user-select: none
|
||||
|
||||
// Gap between text characters
|
||||
letter-spacing: 0.2em
|
||||
margin-top: 0
|
||||
margin-bottom: 32px
|
||||
opacity: 0.9
|
||||
|
||||
.btn-group
|
||||
display: flex
|
||||
gap: 8px
|
||||
|
||||
.light-pollution
|
||||
pointer-events: none
|
||||
opacity: 0.8
|
||||
|
||||
> div
|
||||
position: absolute
|
||||
z-index: 1
|
||||
|
||||
.l1
|
||||
left: -560px
|
||||
top: 90px
|
||||
height: 1130px
|
||||
width: 1500px
|
||||
$color: rgb(158, 110, 230)
|
||||
background: radial-gradient(50% 50% at 50% 50%, rgba($color, 0.28) 0%, rgba(0,0,0,0) 100%)
|
||||
|
||||
.l2
|
||||
left: -200px
|
||||
top: 560px
|
||||
height: 1200px
|
||||
width: 1500px
|
||||
$color: rgb(92, 195, 250)
|
||||
background: radial-gradient(50% 50% at 50% 50%, rgba($color, 0.28) 0%, rgba(0,0,0,0) 100%)
|
||||
|
||||
.l3
|
||||
left: -600px
|
||||
opacity: 0.7
|
||||
top: -630px
|
||||
width: 1500px
|
||||
height: 1000px
|
||||
$color: rgb(230, 110, 156)
|
||||
background: radial-gradient(50% 50% at 50% 50%, rgba($color, 0.28) 0%, rgba(0,0,0,0) 100%)
|
||||
|
||||
@media (max-width: 500px)
|
||||
align-items: center
|
||||
padding-left: 0
|
||||
</style>
|
||||
<script lang="ts">
|
||||
import { Turnstile } from "svelte-turnstile";
|
||||
import { slide } from 'svelte/transition';
|
||||
import { TURNSTILE_SITE_KEY } from "../libs/config";
|
||||
import Icon from "@iconify/svelte";
|
||||
import { USER } from "../libs/sdk";
|
||||
import { t } from "../libs/i18n"
|
||||
|
||||
let params = new URLSearchParams(window.location.search)
|
||||
|
||||
let state = "home"
|
||||
$: isSignup = state === "signup"
|
||||
let submitting = false
|
||||
|
||||
let email = ""
|
||||
let password = ""
|
||||
let username = ""
|
||||
let turnstile = ""
|
||||
let turnstileReset: () => void | undefined;
|
||||
|
||||
let error = ""
|
||||
let verifyMsg = ""
|
||||
|
||||
if (USER.isLoggedIn()) {
|
||||
window.location.href = "/home"
|
||||
}
|
||||
|
||||
if (params.get('confirm-email')) {
|
||||
state = 'verify'
|
||||
verifyMsg = t("welcome.verifying")
|
||||
submitting = true
|
||||
|
||||
// Send request to server
|
||||
USER.confirmEmail(params.get('confirm-email')!)
|
||||
.then(() => {
|
||||
verifyMsg = t('welcome.verified')
|
||||
submitting = false
|
||||
|
||||
// Clear the query param
|
||||
window.history.replaceState({}, document.title, window.location.pathname)
|
||||
})
|
||||
.catch(e => verifyMsg = t('welcome.verification-failed', { message: e.message }))
|
||||
}
|
||||
|
||||
async function submit(): Promise<any> {
|
||||
submitting = true
|
||||
|
||||
// Check if username and password are valid
|
||||
if (email === "" || password === "") {
|
||||
error = t("welcome.email-password-missing")
|
||||
return submitting = false
|
||||
}
|
||||
|
||||
if (turnstile === "") {
|
||||
// Sleep for 100ms to allow Turnstile to finish
|
||||
error = t("welcome.waiting-turnstile")
|
||||
return setTimeout(submit, 100)
|
||||
}
|
||||
|
||||
// Signup
|
||||
if (isSignup) {
|
||||
if (username === "") {
|
||||
error = t("welcome.username-missing")
|
||||
return submitting = false
|
||||
}
|
||||
|
||||
// Send request to server
|
||||
await USER.register({ username, email, password, turnstile })
|
||||
.then(() => {
|
||||
// Show verify email message
|
||||
state = 'verify'
|
||||
verifyMsg = t("welcome.verification-sent", { email })
|
||||
})
|
||||
.catch(e => {
|
||||
error = e.message
|
||||
submitting = false
|
||||
turnstileReset()
|
||||
})
|
||||
}
|
||||
else {
|
||||
// Send request to server
|
||||
await USER.login({ email, password, turnstile })
|
||||
.then(() => window.location.href = "/home")
|
||||
.catch(e => {
|
||||
if (e.message === 'Email not verified - STATE_0') {
|
||||
state = 'verify'
|
||||
verifyMsg = t("welcome.verify-state-0")
|
||||
}
|
||||
else if (e.message === 'Email not verified - STATE_1') {
|
||||
state = 'verify'
|
||||
verifyMsg = t("welcome.verify-state-1")
|
||||
}
|
||||
else if (e.message === 'Email not verified - STATE_2') {
|
||||
state = 'verify'
|
||||
verifyMsg = t("welcome.verify-state-2")
|
||||
}
|
||||
else {
|
||||
error = e.message
|
||||
submitting = false
|
||||
turnstileReset()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
submitting = false
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<main id="home" class="no-margin">
|
||||
<div>
|
||||
<h1 id="title">AquaNet</h1>
|
||||
{#if state === "home"}
|
||||
<div class="btn-group" transition:slide>
|
||||
<button on:click={() => state = 'login'}>{t('welcome.btn-login')}</button>
|
||||
<button on:click={() => state = 'signup'}>{t('welcome.btn-signup')}</button>
|
||||
</div>
|
||||
{:else if state === "login" || state === "signup"}
|
||||
<div class="login-form" transition:slide>
|
||||
{#if error}
|
||||
<span class="error">{error}</span>
|
||||
{/if}
|
||||
<div on:click={() => state = 'home'} on:keypress={() => state = 'home'}
|
||||
role="button" tabindex="0" class="clickable">
|
||||
<Icon icon="line-md:chevron-small-left" />
|
||||
<span>{t('back')}</span>
|
||||
</div>
|
||||
{#if isSignup}
|
||||
<input type="text" placeholder={t('username')} bind:value={username}>
|
||||
{/if}
|
||||
<input type="email" placeholder={t('email')} bind:value={email}>
|
||||
<input type="password" placeholder={t('password')} bind:value={password}>
|
||||
<button on:click={submit}>
|
||||
{#if submitting}
|
||||
<Icon icon="line-md:loading-twotone-loop"/>
|
||||
{:else}
|
||||
{isSignup ? t('welcome.btn-signup') : t('welcome.btn-login')}
|
||||
{/if}
|
||||
</button>
|
||||
<Turnstile siteKey={TURNSTILE_SITE_KEY} bind:reset={turnstileReset}
|
||||
on:turnstile-callback={e => console.log(turnstile = e.detail.token)}
|
||||
on:turnstile-error={_ => console.log(error = t("welcome.turnstile-error"))}
|
||||
on:turnstile-expired={_ => window.location.reload()}
|
||||
on:turnstile-timeout={_ => console.log(error = t('welcome.turnstile-timeout'))} />
|
||||
</div>
|
||||
{:else if state === "verify"}
|
||||
<div class="login-form" transition:slide>
|
||||
<span>{verifyMsg}</span>
|
||||
{#if !submitting}
|
||||
<button on:click={() => state = 'home'} transition:slide>{t('back')}</button>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<div class="light-pollution">
|
||||
<div class="l1"></div>
|
||||
<div class="l2"></div>
|
||||
<div class="l3"></div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<style lang="sass">
|
||||
@use "../vars"
|
||||
|
||||
.login-form
|
||||
display: flex
|
||||
flex-direction: column
|
||||
gap: 8px
|
||||
width: calc(100% - 12px)
|
||||
max-width: 300px
|
||||
|
||||
div.clickable
|
||||
display: flex
|
||||
align-items: center
|
||||
|
||||
#home
|
||||
color: vars.$c-main
|
||||
position: relative
|
||||
width: 100%
|
||||
height: 100%
|
||||
padding-left: 100px
|
||||
overflow: hidden
|
||||
background-color: black
|
||||
|
||||
box-sizing: border-box
|
||||
|
||||
display: flex
|
||||
flex-direction: column
|
||||
justify-content: center
|
||||
|
||||
margin-top: -(vars.$nav-height)
|
||||
|
||||
// Content container
|
||||
> div
|
||||
display: flex
|
||||
flex-direction: column
|
||||
align-items: flex-start
|
||||
width: max-content
|
||||
|
||||
// Switching state container
|
||||
> div
|
||||
transition: vars.$transition
|
||||
|
||||
#title
|
||||
font-family: Quicksand, vars.$font
|
||||
user-select: none
|
||||
|
||||
// Gap between text characters
|
||||
letter-spacing: 0.2em
|
||||
margin-top: 0
|
||||
margin-bottom: 32px
|
||||
opacity: 0.9
|
||||
|
||||
.btn-group
|
||||
display: flex
|
||||
gap: 8px
|
||||
|
||||
.light-pollution
|
||||
pointer-events: none
|
||||
opacity: 0.8
|
||||
|
||||
> div
|
||||
position: absolute
|
||||
z-index: 1
|
||||
|
||||
.l1
|
||||
left: -560px
|
||||
top: 90px
|
||||
height: 1130px
|
||||
width: 1500px
|
||||
$color: rgb(158, 110, 230)
|
||||
background: radial-gradient(50% 50% at 50% 50%, rgba($color, 0.28) 0%, rgba(0,0,0,0) 100%)
|
||||
|
||||
.l2
|
||||
left: -200px
|
||||
top: 560px
|
||||
height: 1200px
|
||||
width: 1500px
|
||||
$color: rgb(92, 195, 250)
|
||||
background: radial-gradient(50% 50% at 50% 50%, rgba($color, 0.28) 0%, rgba(0,0,0,0) 100%)
|
||||
|
||||
.l3
|
||||
left: -600px
|
||||
opacity: 0.7
|
||||
top: -630px
|
||||
width: 1500px
|
||||
height: 1000px
|
||||
$color: rgb(230, 110, 156)
|
||||
background: radial-gradient(50% 50% at 50% 50%, rgba($color, 0.28) 0%, rgba(0,0,0,0) 100%)
|
||||
|
||||
@media (max-width: 500px)
|
||||
align-items: center
|
||||
padding-left: 0
|
||||
</style>
|
||||
|
|
|
@ -16,7 +16,7 @@ Below is a list of games supported by this server.
|
|||
| Game | Ver | Codename | Thanks to |
|
||||
|----------------------------|------|---------------|--------------------------------------------|
|
||||
| SDHD: CHUNITHM (Chusan) | 2.27 | LUMINOUS PLUS | [@rinsama](https://github.com/mxihan) |
|
||||
| SDEZ: MaiMai DX | 1.40 | BUDDiES | [@肥宅虾哥](https://github.com/FeiZhaixiage) |
|
||||
| SDEZ: MaiMai DX | 1.45 | BUDDiES PLUS | [@肥宅虾哥](https://github.com/FeiZhaixiage) |
|
||||
| SDGA: MaiMai DX (International) | 1.45 | BUDDiES PLUS | [@Clansty](https://github.com/clansty) |
|
||||
| SDED: Card Maker | 1.39 | | [@Becods](https://github.com/Becods) |
|
||||
| SBZV: Project DIVA Arcade | 7.10 | Future Tone | |
|
||||
|
|
|
@ -13,8 +13,8 @@ plugins {
|
|||
kotlin("plugin.jpa") version ktVer
|
||||
kotlin("plugin.serialization") version ktVer
|
||||
kotlin("plugin.allopen") version ktVer
|
||||
id("io.freefair.lombok") version "8.11"
|
||||
id("org.springframework.boot") version "3.4.1"
|
||||
id("io.freefair.lombok") version "8.6"
|
||||
id("org.springframework.boot") version "3.2.3"
|
||||
id("com.github.ben-manes.versions") version "0.51.0"
|
||||
id("org.hibernate.orm") version "6.4.4.Final"
|
||||
application
|
||||
|
@ -38,13 +38,13 @@ dependencies {
|
|||
implementation("io.netty:netty-all")
|
||||
implementation("org.apache.commons:commons-lang3:3.14.0")
|
||||
implementation("org.apache.httpcomponents.client5:httpclient5")
|
||||
implementation("org.flywaydb:flyway-core:11.1.0")
|
||||
implementation("org.flywaydb:flyway-mysql:11.1.0")
|
||||
implementation("org.flywaydb:flyway-core:10.10.0")
|
||||
implementation("org.flywaydb:flyway-mysql:10.10.0")
|
||||
testImplementation("org.springframework.boot:spring-boot-starter-test") {
|
||||
exclude(group = "org.junit.vintage", module = "junit-vintage-engine")
|
||||
}
|
||||
testImplementation("org.springframework.security:spring-security-test")
|
||||
implementation("net.logstash.logback:logstash-logback-encoder:8.0")
|
||||
implementation("net.logstash.logback:logstash-logback-encoder:7.4")
|
||||
|
||||
// Metrics
|
||||
implementation("org.springframework.boot:spring-boot-starter-actuator")
|
||||
|
@ -64,11 +64,11 @@ dependencies {
|
|||
// =============================
|
||||
|
||||
// Network
|
||||
implementation("io.ktor:ktor-client-core:2.3.13")
|
||||
implementation("io.ktor:ktor-client-cio:2.3.13")
|
||||
implementation("io.ktor:ktor-client-content-negotiation:2.3.13")
|
||||
implementation("io.ktor:ktor-client-encoding:2.3.13")
|
||||
implementation("io.ktor:ktor-serialization-kotlinx-json:2.3.13")
|
||||
implementation("io.ktor:ktor-client-core:2.3.8")
|
||||
implementation("io.ktor:ktor-client-cio:2.3.8")
|
||||
implementation("io.ktor:ktor-client-content-negotiation:2.3.8")
|
||||
implementation("io.ktor:ktor-client-encoding:2.3.8")
|
||||
implementation("io.ktor:ktor-serialization-kotlinx-json:2.3.8")
|
||||
implementation("org.jetbrains.kotlin:kotlin-reflect")
|
||||
|
||||
// Somehow these are needed for ktor even though they're not in the documentation
|
||||
|
@ -76,16 +76,16 @@ dependencies {
|
|||
runtimeOnly("org.jetbrains.kotlinx:kotlinx-coroutines-reactor:1.8.0")
|
||||
|
||||
// Email
|
||||
implementation("org.simplejavamail:simple-java-mail:8.12.4")
|
||||
implementation("org.simplejavamail:spring-module:8.12.4")
|
||||
implementation("org.simplejavamail:simple-java-mail:8.6.3")
|
||||
implementation("org.simplejavamail:spring-module:8.6.3")
|
||||
|
||||
// GeoIP
|
||||
implementation("com.maxmind.geoip2:geoip2:4.2.1")
|
||||
implementation("com.maxmind.geoip2:geoip2:4.2.0")
|
||||
|
||||
// JWT Authentication
|
||||
implementation("io.jsonwebtoken:jjwt-api:0.12.6")
|
||||
runtimeOnly("io.jsonwebtoken:jjwt-impl:0.12.6")
|
||||
runtimeOnly("io.jsonwebtoken:jjwt-jackson:0.12.6")
|
||||
implementation("io.jsonwebtoken:jjwt-api:0.12.5")
|
||||
runtimeOnly("io.jsonwebtoken:jjwt-impl:0.12.5")
|
||||
runtimeOnly("io.jsonwebtoken:jjwt-jackson:0.12.5")
|
||||
|
||||
// Content validation
|
||||
implementation("org.apache.tika:tika-core:2.9.1")
|
||||
|
@ -94,8 +94,7 @@ dependencies {
|
|||
implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.17.0")
|
||||
|
||||
// Serialization
|
||||
// DO NOT UPDATE THIS TO >2.18.0: https://github.com/FasterXML/jackson-module-kotlin/issues/874
|
||||
implementation("com.fasterxml.jackson.module:jackson-module-kotlin:2.17.3")
|
||||
implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
|
||||
|
||||
// Testing
|
||||
testImplementation("io.kotest:kotest-runner-junit5-jvm:5.8.1")
|
||||
|
|
|
@ -53,9 +53,6 @@ game.chusan.reflector-url=http://reflector.naominet.live:18080/
|
|||
## This sets the matching server url.
|
||||
## When this is set, we will sync with the external matching url so that we can match with more players.
|
||||
game.chusan.external-matching=https://chu3-match.sega.ink/
|
||||
## When this is set to true, we will proxy all matching requests sent to the external matching server.
|
||||
## This option enhances security by masking the user ID and keychip.
|
||||
game.chusan.proxied-matching=false
|
||||
## This enables user use login bonus function if set to true.
|
||||
## NOTE: THIS IS NOT TESTED, it's implemented by someone very inexperienced and might not work.
|
||||
game.chusan.loginbonus-enable=false
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
# Chunithm National Matching Guide
|
||||
|
||||
The national matching game mode allows up to 4 players on any server (YES, ANY SERVER) to play together.
|
||||
In this game mode, for example, you can play with RinNET or Missless players as well.
|
||||
This is a guide on how to set up your client for national matching.
|
||||
|
||||
This is tested on Chusan 2.27.
|
||||
|
||||
## Pre-requisites
|
||||
|
||||
- Play the normal game at least once so that you have a profile on the server.
|
||||
- NAT Type must not be Symmetric ([Check here](https://www.checkmynat.com/))
|
||||
- Your firewall must be turned off (or [add a rule that allows chusanApp](#firewall-rules))
|
||||
|
||||
## Setting Up
|
||||
|
||||

|
||||
|
||||
1. Go to the AquaNet website and set your matching server to "Yukiotoko"
|
||||
(To go to the settings page, click on the gear icon in the top right corner of your profile, switch to chuni tab, scroll down, click "Select Matching Server")
|
||||
2. Make sure you use [Dniel97's open-source segatools](https://gitea.tendokyu.moe/Dniel97/SEGAguide/wiki/SDHD)
|
||||
If you're using fufubot segatools, please override it with Dniel97's version (don't forget to update `segatools.ini`).
|
||||
3. Patch your `chusanApp.exe` using [Two-Torial's open-source patcher](https://patcher.two-torial.xyz/)
|
||||
(Make sure you disable "Set all timer to 999", enable "No encryption", "No TLS", "Patch for head-to-head play")
|
||||
4. Add the option [ARRR](https://pixeldrain.com/u/D2jjN3of).
|
||||
If you're playing with friends, make sure they have the same options as you.
|
||||
5. Pet your cat 🐈
|
||||
6. Launch!
|
||||
|
||||
|
||||
### Firewall Rules
|
||||
|
||||
Below is a simple command to add firewall rules for Chunithm.
|
||||
|
||||
```shell
|
||||
@echo off
|
||||
set /p gamedirectory = Make sure this is run as admin and enter game path (e.g. C:\SegaGames\Chunithm\bin\chusanApp.exe)\n
|
||||
netsh advfirewall firewall add rule name="Chunithm National Matching Inbound" dir=in action=allow profile=any program="%gamedirectory%" enable=yes
|
||||
netsh advfirewall firewall add rule name="Chunithm National Matching Outbound" dir=out action=allow profile=any program="%gamedirectory%" enable=yes
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
**Q: Game crashes when entering match mode**
|
||||
|
||||
Make sure you are using Dniel97's segatools.
|
||||
|
||||
**Q: After matching, timer shows 999 seconds and nobody can start**
|
||||
|
||||
Make sure you have patched your `chusanApp.exe` correctly.
|
||||
|
||||
**Q: Online battle icon gray / "Unable to select after the event time"**
|
||||
|
||||
Make sure your time zone is set to JST (UTC+9).
|
||||
|
||||
**Q: This window show up when joining.**
|
||||
|
||||

|
||||
|
||||
If there is only one player, then yea it's because there are not enough players.
|
||||
Otherwise, it's because one of the players has a bad network environment (e.g. Symmetric NAT).
|
||||
Try again with someone who played this mode before, if it still doesn't work, then it's probably you.
|
||||
|
||||
**Q: Why did I play two of the same songs in a row?**
|
||||
|
||||
When other people picked a song that you don't have, the game will play the same song as the previous one.
|
||||
Make sure you have up-to-date options in your game.
|
||||
(Or they might have selected a custom chart, in that case there's not much you can do)
|
||||
|
||||
## How to Play
|
||||
|
||||
When you enter the matching mode, it will assign to you a matching room if other people are online, or create a new room otherwise.
|
||||
Then, after four people are present or after a specific amount of time has passed, the game will start.
|
||||
Everyone will be asked to pick a song at the start, even though your song might not be the first one to be played.
|
||||
After songs are picked, other players will play the song on the SAME DIFFICULTY as what you picked.
|
||||
(So be a nice person and don't pick 15 if there are new players alright? 🥺)
|
||||
|
||||
If there are less than 4 players when the timer runs out, the game will fill in the empty slots with bots.
|
||||
The bots will randomly select a song (mostly under Lv10).
|
Binary file not shown.
After Width: | Height: | Size: 297 KiB |
Binary file not shown.
After Width: | Height: | Size: 86 KiB |
|
@ -6,6 +6,8 @@ import io.ktor.client.engine.cio.*
|
|||
import io.ktor.client.plugins.contentnegotiation.*
|
||||
import io.ktor.serialization.kotlinx.json.*
|
||||
import jakarta.persistence.Query
|
||||
import jakarta.servlet.http.HttpServletRequest
|
||||
import jakarta.servlet.http.HttpServletResponse
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import org.apache.tika.Tika
|
||||
|
@ -16,6 +18,7 @@ import org.springframework.http.HttpStatus
|
|||
import org.springframework.http.ResponseEntity.BodyBuilder
|
||||
import org.springframework.web.bind.annotation.*
|
||||
import java.lang.reflect.Field
|
||||
import java.nio.charset.StandardCharsets
|
||||
import java.nio.file.Path
|
||||
import java.security.MessageDigest
|
||||
import java.time.LocalDate
|
||||
|
@ -44,6 +47,19 @@ typealias JavaSerializable = java.io.Serializable
|
|||
typealias JDict = Map<String, Any?>
|
||||
typealias MutJDict = MutableMap<String, Any?>
|
||||
|
||||
fun HttpServletRequest.details() = mapOf(
|
||||
"method" to method,
|
||||
"uri" to requestURI,
|
||||
"query" to queryString,
|
||||
"remote" to remoteAddr,
|
||||
"headers" to headerNames.asSequence().associateWith { getHeader(it) }
|
||||
)
|
||||
|
||||
fun HttpServletResponse.details() = mapOf(
|
||||
"status" to status,
|
||||
"headers" to headerNames.asSequence().associateWith { getHeader(it) },
|
||||
)
|
||||
|
||||
@Target(AnnotationTarget.CLASS, AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY, AnnotationTarget.PROPERTY_GETTER)
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
annotation class Doc(
|
||||
|
@ -120,6 +136,7 @@ fun LocalDateTime.isoDateTime() = format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
|
|||
fun String.isoDateTime() = LocalDateTime.parse(this, DateTimeFormatter.ISO_LOCAL_DATE_TIME)
|
||||
val URL_SAFE_DT = DateTimeFormatter.ofPattern("yyyy-MM-dd_HH-mm-ss")
|
||||
fun LocalDateTime.urlSafeStr() = format(URL_SAFE_DT)
|
||||
val DATE_2018 = LocalDateTime.parse("2018-01-01T00:00:00")
|
||||
|
||||
val ALT_DATETIME_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
|
||||
fun Str.asDateTime() = try { LocalDateTime.parse(this, DateTimeFormatter.ISO_LOCAL_DATE_TIME) }
|
||||
|
@ -173,17 +190,22 @@ val Any?.truthy get() = when (this) {
|
|||
fun <T> ls(vararg args: T) = args.toList()
|
||||
inline fun <reified T> arr(vararg args: T) = arrayOf(*args)
|
||||
operator fun <K, V> Map<K, V>.plus(map: Map<K, V>) =
|
||||
(if (this is MutableMap) this else toMutableMap()).apply { putAll(map) }
|
||||
(if (this is MutableMap) this else mut).apply { putAll(map) }
|
||||
operator fun <K, V> MutableMap<K, V>.plusAssign(map: Map<K, V>) { putAll(map) }
|
||||
fun <K, V: Any> Map<K, V?>.vNotNull(): Map<K, V> = filterValues { it != null }.mapValues { it.value!! }
|
||||
fun <T> MutableList<T>.popAll(list: List<T>) = list.also { removeAll(it) }
|
||||
fun <T> MutableList<T>.popAll(vararg items: T) = popAll(items.toList())
|
||||
inline fun <T> Iterable<T>.mapApply(block: T.() -> Unit) = map { it.apply(block) }
|
||||
inline fun <T> Iterable<T>.mapApplyI(block: T.(Int) -> Unit) = mapIndexed { i, e -> e.apply { block(i) } }
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun <K, V: Any> Map<K, V?>.recursiveNotNull(): Map<K, V> = mapNotNull { (k, v) ->
|
||||
k to if (v is Map<*, *>) (v as Map<Any?, Any?>).recursiveNotNull() else v
|
||||
}.toMap() as Map<K, V>
|
||||
|
||||
val <T> List<T>.mut get() = toMutableList()
|
||||
val <K, V> Map<K, V>.mut get() = toMutableMap()
|
||||
val <T> Set<T>.mut get() = toMutableSet()
|
||||
|
||||
// Optionals
|
||||
operator fun <T> Optional<T>.invoke(): T? = orElse(null)
|
||||
fun <T> Optional<T>.expect(message: Str = "Value is not present") = orElseGet { (400 - message) }
|
||||
|
@ -195,6 +217,7 @@ fun Str.center(width: Int, padChar: Char = ' ') = padStart((length + width) / 2,
|
|||
fun Str.splitLines() = replace("\r\n", "\n").split('\n')
|
||||
@OptIn(ExperimentalStdlibApi::class)
|
||||
fun Str.md5() = MD5.digest(toByteArray(Charsets.UTF_8)).toHexString()
|
||||
fun Str.fromChusanUsername() = String(this.toByteArray(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8)
|
||||
|
||||
// Coroutine
|
||||
suspend fun <T> async(block: suspend kotlinx.coroutines.CoroutineScope.() -> T): T = withContext(Dispatchers.IO) { block() }
|
||||
|
|
|
@ -1,316 +0,0 @@
|
|||
package icu.samnyan.aqua.api.controller.sega.game.chuni.v2;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import icu.samnyan.aqua.api.model.MessageResponse;
|
||||
import icu.samnyan.aqua.api.model.ReducedPageResponse;
|
||||
import icu.samnyan.aqua.api.model.resp.sega.chuni.v2.RecentResp;
|
||||
import icu.samnyan.aqua.api.model.resp.sega.chuni.v2.external.Chu3DataExport;
|
||||
import icu.samnyan.aqua.api.util.ApiMapper;
|
||||
import icu.samnyan.aqua.sega.chusan.model.userdata.*;
|
||||
import icu.samnyan.aqua.sega.chusan.service.*;
|
||||
import icu.samnyan.aqua.sega.general.service.CardService;
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* For all aimeId parameter, should use String
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("api/game/chuni/v2")
|
||||
@ConditionalOnProperty(prefix = "aquaviewer.api", name = "enabled", havingValue = "true")
|
||||
@AllArgsConstructor
|
||||
public class ApiChuniV2PlayerDataController {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(ApiChuniV2PlayerDataController.class);
|
||||
|
||||
private final ApiMapper mapper;
|
||||
|
||||
private final CardService cardService;
|
||||
|
||||
private final UserActivityService userActivityService;
|
||||
private final UserCharacterService userCharacterService;
|
||||
private final UserChargeService userChargeService;
|
||||
private final UserCourseService userCourseService;
|
||||
private final UserDataService userDataService;
|
||||
private final UserDuelService userDuelService;
|
||||
private final UserGameOptionService userGameOptionService;
|
||||
private final UserItemService userItemService;
|
||||
private final UserMapAreaService userMapAreaService;
|
||||
private final UserMusicDetailService userMusicDetailService;
|
||||
private final UserPlaylogService userPlaylogService;
|
||||
private final UserGeneralDataService userGeneralDataService;
|
||||
|
||||
@PutMapping("profile/username")
|
||||
public Chu3UserData updateName(@RequestBody Map<String, Object> request) {
|
||||
Chu3UserData profile = userDataService.getUserByExtId((String) request.get("aimeId")).orElseThrow();
|
||||
profile.setUserName((String) request.get("userName"));
|
||||
return userDataService.saveUserData(profile);
|
||||
}
|
||||
|
||||
@PutMapping("profile/romversion")
|
||||
public Chu3UserData updateRomVersion(@RequestBody Map<String, Object> request) {
|
||||
Chu3UserData profile = userDataService.getUserByExtId((String) request.get("aimeId")).orElseThrow();
|
||||
profile.setLastRomVersion((String) request.get("romVersion"));
|
||||
return userDataService.saveUserData(profile);
|
||||
}
|
||||
|
||||
@PutMapping("profile/dataversion")
|
||||
public Chu3UserData updateDataVersion(@RequestBody Map<String, Object> request) {
|
||||
Chu3UserData profile = userDataService.getUserByExtId((String) request.get("aimeId")).orElseThrow();
|
||||
profile.setLastDataVersion((String) request.get("dataVersion"));
|
||||
return userDataService.saveUserData(profile);
|
||||
}
|
||||
|
||||
@PutMapping("profile/plate")
|
||||
public Chu3UserData updatePlate(@RequestBody Map<String, Object> request) {
|
||||
Chu3UserData profile = userDataService.getUserByExtId((String) request.get("aimeId")).orElseThrow();
|
||||
profile.setNameplateId((Integer) request.get("nameplateId"));
|
||||
return userDataService.saveUserData(profile);
|
||||
}
|
||||
|
||||
@PutMapping("profile/frame")
|
||||
public Chu3UserData updateFrame(@RequestBody Map<String, Object> request) {
|
||||
Chu3UserData profile = userDataService.getUserByExtId((String) request.get("aimeId")).orElseThrow();
|
||||
profile.setFrameId((Integer) request.get("frameId"));
|
||||
return userDataService.saveUserData(profile);
|
||||
}
|
||||
|
||||
@PutMapping("profile/trophy")
|
||||
public Chu3UserData updateTrophy(@RequestBody Map<String, Object> request) {
|
||||
Chu3UserData profile = userDataService.getUserByExtId((String) request.get("aimeId")).orElseThrow();
|
||||
profile.setTrophyId((Integer) request.get("trophyId"));
|
||||
return userDataService.saveUserData(profile);
|
||||
}
|
||||
|
||||
@PutMapping("profile/mapicon")
|
||||
public Chu3UserData updateMapIcon(@RequestBody Map<String, Object> request) {
|
||||
Chu3UserData profile = userDataService.getUserByExtId((String) request.get("aimeId")).orElseThrow();
|
||||
profile.setMapIconId((Integer) request.get("mapiconId"));
|
||||
return userDataService.saveUserData(profile);
|
||||
}
|
||||
|
||||
@PutMapping("profile/sysvoice")
|
||||
public Chu3UserData updateSystemVoice(@RequestBody Map<String, Object> request) {
|
||||
Chu3UserData profile = userDataService.getUserByExtId((String) request.get("aimeId")).orElseThrow();
|
||||
profile.setVoiceId((Integer) request.get("voiceId"));
|
||||
return userDataService.saveUserData(profile);
|
||||
}
|
||||
|
||||
@PutMapping("profile/avatar")
|
||||
public Chu3UserData updateAvatar(@RequestBody Map<String, Object> request) {
|
||||
Chu3UserData profile = userDataService.getUserByExtId((String) request.get("aimeId")).orElseThrow();
|
||||
int category = (Integer) request.get("category");
|
||||
switch (category) {
|
||||
case 1:
|
||||
profile.setAvatarWear((Integer) request.get("accId"));
|
||||
break;
|
||||
case 2:
|
||||
profile.setAvatarHead((Integer) request.get("accId"));
|
||||
break;
|
||||
case 3:
|
||||
profile.setAvatarFace((Integer) request.get("accId"));
|
||||
break;
|
||||
case 4:
|
||||
profile.setAvatarSkin((Integer) request.get("accId"));
|
||||
break;
|
||||
case 5:
|
||||
profile.setAvatarItem((Integer) request.get("accId"));
|
||||
break;
|
||||
case 6:
|
||||
profile.setAvatarFront((Integer) request.get("accId"));
|
||||
break;
|
||||
case 7:
|
||||
profile.setAvatarBack((Integer) request.get("accId"));
|
||||
break;
|
||||
}
|
||||
|
||||
return userDataService.saveUserData(profile);
|
||||
}
|
||||
|
||||
@PutMapping("profile/privacy")
|
||||
public ResponseEntity<Object> updatePrivacy(@RequestBody Map<String, Object> request) {
|
||||
Chu3UserData profile = userDataService.getUserByExtId((String) request.get("aimeId")).orElseThrow();
|
||||
UserGameOption option = userGameOptionService.getByUser(profile).orElseThrow();
|
||||
int privacy = (Integer) request.get("privacy");
|
||||
if (privacy != 1 && privacy != 0) {
|
||||
return ResponseEntity.badRequest().body(new MessageResponse("Wrong data"));
|
||||
}
|
||||
option.setPrivacy(privacy);
|
||||
return ResponseEntity.ok(userDataService.saveUserData(profile));
|
||||
}
|
||||
|
||||
@GetMapping("recent")
|
||||
public ReducedPageResponse<RecentResp> getRecentPlay(@RequestParam String aimeId,
|
||||
@RequestParam(required = false, defaultValue = "0") int page,
|
||||
@RequestParam(required = false, defaultValue = "10") int size) {
|
||||
Page<UserPlaylog> playLogs = userPlaylogService.getRecentPlays(aimeId, PageRequest.of(page, size, Sort.by(Sort.Direction.DESC, "userPlayDate")));
|
||||
return new ReducedPageResponse<>(mapper.convert(playLogs.getContent(), new TypeReference<>() {
|
||||
}), playLogs.getPageable().getPageNumber(), playLogs.getTotalPages(), playLogs.getTotalElements());
|
||||
}
|
||||
|
||||
@GetMapping("song/{id}")
|
||||
public List<UserMusicDetail> getSongDetail(@RequestParam String aimeId, @PathVariable int id) {
|
||||
return userMusicDetailService.getByUserIdAndMusicId(aimeId, id);
|
||||
}
|
||||
|
||||
@GetMapping("song/{id}/{level}")
|
||||
public List<UserPlaylog> getLevelPlaylog(@RequestParam String aimeId, @PathVariable int id, @PathVariable int level) {
|
||||
return userPlaylogService.getByUserIdAndMusicIdAndLevel(aimeId, id, level);
|
||||
}
|
||||
|
||||
@GetMapping("song/{id}/isfavorite")
|
||||
public boolean getSongFavorite(@RequestParam String aimeId, @PathVariable String id) {
|
||||
Optional<UserGeneralData> favOptional;
|
||||
favOptional = userGeneralDataService.getByUserIdAndKey(aimeId, "favorite_music");
|
||||
if(favOptional.isPresent()) {
|
||||
String val = favOptional.get().getPropertyValue();
|
||||
if(StringUtils.isNotBlank(val) && val.contains(",")) {
|
||||
String[] records = val.split(",");
|
||||
for (String record : records) {
|
||||
if (record.equals(id)) return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@PutMapping("song/{id}/favorite")
|
||||
public void updateSongFavorite(@RequestParam String aimeId, @PathVariable String id) {
|
||||
Chu3UserData profile = userDataService.getUserByExtId(aimeId).orElseThrow();
|
||||
UserGeneralData userGeneralData = userGeneralDataService.getByUserAndKey(profile, "favorite_music")
|
||||
.orElseGet(() -> new UserGeneralData(profile, "favorite_music"));
|
||||
List<String> favoriteSongs = new LinkedList<String>(Arrays.asList(userGeneralData.getPropertyValue().split(",")));
|
||||
|
||||
if(!favoriteSongs.remove(id))
|
||||
{
|
||||
favoriteSongs.add(id);
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
favoriteSongs.forEach(favSong -> {
|
||||
if(!favSong.isEmpty()) sb.append(favSong).append(",");
|
||||
});
|
||||
|
||||
userGeneralData.setPropertyValue(sb.toString());
|
||||
userGeneralDataService.save(userGeneralData);
|
||||
}
|
||||
|
||||
@GetMapping("character")
|
||||
public ReducedPageResponse<UserCharacter> getCharacter(@RequestParam String aimeId,
|
||||
@RequestParam(required = false, defaultValue = "0") int page,
|
||||
@RequestParam(required = false, defaultValue = "10") int size) {
|
||||
Page<UserCharacter> characters = userCharacterService.getByUserId(aimeId, page, size);
|
||||
return new ReducedPageResponse<>(characters.getContent(), characters.getPageable().getPageNumber(), characters.getTotalPages(), characters.getTotalElements());
|
||||
}
|
||||
|
||||
@PostMapping("character")
|
||||
public ResponseEntity<Object> updateCharacter(@RequestBody Map<String, Object> request) {
|
||||
Chu3UserData profile = userDataService.getUserByExtId((String) request.get("aimeId")).orElseThrow();
|
||||
Integer characterId = (Integer) request.get("characterId");
|
||||
Optional<UserCharacter> characterOptional = userCharacterService.getByUserAndCharacterId(profile, characterId);
|
||||
UserCharacter character;
|
||||
if(characterOptional.isPresent()) {
|
||||
character = characterOptional.get();
|
||||
} else {
|
||||
character = new UserCharacter(profile);
|
||||
character.setCharacterId(characterId);
|
||||
}
|
||||
if(request.containsKey("level")) {
|
||||
character.setLevel((Integer) request.get("level"));
|
||||
}
|
||||
|
||||
return ResponseEntity.ok(userCharacterService.save(character));
|
||||
}
|
||||
|
||||
@GetMapping("course")
|
||||
public List<UserCourse> getCourse(@RequestParam String aimeId) {
|
||||
return userCourseService.getByUserId(aimeId);
|
||||
}
|
||||
|
||||
@GetMapping("duel")
|
||||
public List<UserDuel> getDuel(@RequestParam String aimeId) {
|
||||
return userDuelService.getByUserId(aimeId);
|
||||
}
|
||||
|
||||
@GetMapping("item")
|
||||
public ReducedPageResponse<UserItem> getItem(@RequestParam String aimeId,
|
||||
@RequestParam(required = false, defaultValue = "0") int page,
|
||||
@RequestParam(required = false, defaultValue = "10") int size) {
|
||||
Page<UserItem> items = userItemService.getByUserId(aimeId, page, size);
|
||||
return new ReducedPageResponse<>(items.getContent(), items.getPageable().getPageNumber(), items.getTotalPages(), items.getTotalElements());
|
||||
}
|
||||
|
||||
@GetMapping("item/{itemKind}")
|
||||
public List<UserItem> getItemByKind(@RequestParam String aimeId, @PathVariable int itemKind) {
|
||||
return userItemService.getByUserAndItemKind(aimeId, itemKind);
|
||||
}
|
||||
|
||||
@PostMapping("item")
|
||||
public ResponseEntity<Object> updateItem(@RequestBody Map<String, Object> request) {
|
||||
Chu3UserData profile = userDataService.getUserByExtId((String) request.get("aimeId")).orElseThrow();
|
||||
Integer itemId = (Integer) request.get("itemId");
|
||||
Integer itemKind = (Integer) request.get("itemKind");
|
||||
Optional<UserItem> itemOptional = userItemService.getByUserAndItemIdAndKind(profile, itemId,itemKind);
|
||||
UserItem item;
|
||||
if(itemOptional.isPresent()) {
|
||||
item = itemOptional.get();
|
||||
} else {
|
||||
item = new UserItem(profile);
|
||||
item.setItemId(itemId);
|
||||
item.setItemKind(itemKind);
|
||||
}
|
||||
if(request.containsKey("stock")) {
|
||||
item.setStock((Integer) request.get("stock"));
|
||||
}
|
||||
return ResponseEntity.ok(userItemService.save(item));
|
||||
}
|
||||
|
||||
@GetMapping("general")
|
||||
public ResponseEntity<Object> getGeneralData(@RequestParam String aimeId, @RequestParam String key) {
|
||||
Optional<UserGeneralData> userGeneralDataOptional = userGeneralDataService.getByUserIdAndKey(aimeId,key);
|
||||
return userGeneralDataOptional.<ResponseEntity<Object>>map(ResponseEntity::ok)
|
||||
.orElseGet(() -> ResponseEntity.status(HttpStatus.NOT_FOUND).body(new MessageResponse("User or value not found.")));
|
||||
}
|
||||
|
||||
@GetMapping("export")
|
||||
public ResponseEntity<Object> exportAllUserData(@RequestParam String aimeId) {
|
||||
Chu3DataExport data = new Chu3DataExport();
|
||||
try {
|
||||
data.setGameId("SDHD");
|
||||
data.setUserData(userDataService.getUserByExtId(aimeId).orElseThrow());
|
||||
data.setUserActivityList(userActivityService.getByUserId(aimeId));
|
||||
data.setUserCharacterList(userCharacterService.getByUserId(aimeId));
|
||||
data.setUserChargeList(userChargeService.getByUserId(aimeId));
|
||||
data.setUserCourseList(userCourseService.getByUserId(aimeId));
|
||||
data.setUserDuelList(userDuelService.getByUserId(aimeId));
|
||||
data.setUserGameOption(userGameOptionService.getByUserId(aimeId).orElseThrow());
|
||||
data.setUserItemList(userItemService.getByUserId(aimeId));
|
||||
data.setUserMapList(userMapAreaService.getByUserId(aimeId));
|
||||
data.setUserMusicDetailList(userMusicDetailService.getByUserId(aimeId));
|
||||
data.setUserPlaylogList(userPlaylogService.getByUserId(aimeId));
|
||||
} catch (NoSuchElementException e) {
|
||||
return ResponseEntity.status(HttpStatus.NOT_FOUND)
|
||||
.body(new MessageResponse("User not found"));
|
||||
} catch (Exception e) {
|
||||
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||
.body(new MessageResponse("Error during data export. Reason: " + e.getMessage()));
|
||||
}
|
||||
// Set filename
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.set("content-disposition", "attachment; filename=chusan_" + aimeId + "_exported.json");
|
||||
return new ResponseEntity<>(data, headers, HttpStatus.OK);
|
||||
}
|
||||
}
|
|
@ -57,11 +57,11 @@ class BotController(
|
|||
us.cardRepo.findByExtId(cardId.long)(),
|
||||
us.cardRepo.findByLuid(cardId)(),
|
||||
us.cardRepo.findById(cardId.long)(),
|
||||
).toMutableList()
|
||||
).mut
|
||||
cards += cards.flatMap {
|
||||
(it.aquaUser?.cards ?: emptyList()) + listOfNotNull(it.aquaUser?.ghostCard)
|
||||
}
|
||||
cards = cards.distinctBy { it.id }.toMutableList()
|
||||
cards = cards.distinctBy { it.id }.mut
|
||||
|
||||
return cards.map { card ->
|
||||
// Find all games played by this card
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package icu.samnyan.aqua.net
|
||||
|
||||
import ext.HTTP
|
||||
import ext.mut
|
||||
import ext.toJson
|
||||
import icu.samnyan.aqua.net.games.BaseEntity
|
||||
import io.ktor.client.call.*
|
||||
|
@ -54,8 +55,8 @@ class AquaNetSafetyService(
|
|||
*/
|
||||
suspend fun isSafeBatch(rawContents: List<String>): List<Boolean> {
|
||||
val contents = rawContents.map { Normalizer.normalize(it, Normalizer.Form.NFKC) }
|
||||
val origMap = safety.findAll().associateBy { it.content }.toMutableMap()
|
||||
val map = safety.findAll().associateBy { it.content.lowercase().trim() }.toMutableMap()
|
||||
val origMap = safety.findAll().associateBy { it.content }.mut
|
||||
val map = safety.findAll().associateBy { it.content.lowercase().trim() }.mut
|
||||
|
||||
// Process unseen content with OpenAI
|
||||
val news = contents.filter { it.lowercase().trim() !in map && it !in contents }.map { inp ->
|
||||
|
|
|
@ -37,6 +37,12 @@ class AquaGameOptions(
|
|||
|
||||
@SettingField("chu3")
|
||||
var chusanInfinitePenguins: Boolean = false,
|
||||
|
||||
@SettingField("chu3-matching")
|
||||
var chusanMatchingServer: String = "",
|
||||
|
||||
@SettingField("chu3-matching")
|
||||
var chusanMatchingReflector: String = "",
|
||||
)
|
||||
|
||||
interface AquaGameOptionsRepo : JpaRepository<AquaGameOptions, Long>
|
||||
|
|
|
@ -24,6 +24,7 @@ abstract class GameApiController<T : IUserData>(val name: String, userDataClass:
|
|||
abstract val playlogRepo: GenericPlaylogRepo<*>
|
||||
abstract val shownRanks: List<Pair<Int, String>>
|
||||
abstract val settableFields: Map<String, (T, String) -> Unit>
|
||||
open val gettableFields: Set<String> = setOf()
|
||||
|
||||
@API("trend")
|
||||
abstract suspend fun trend(@RP username: String): List<TrendOut>
|
||||
|
@ -110,7 +111,8 @@ abstract class GameApiController<T : IUserData>(val name: String, userDataClass:
|
|||
fun playlog(@RP id: Long): IGenericGamePlaylog = playlogRepo.findById(id).getOrNull() ?: (404 - "Playlog not found")
|
||||
|
||||
val userDetailFields by lazy { userDataClass.gettersMap().let { vm ->
|
||||
settableFields.map { (k, _) -> k to (vm[k] ?: error("Field $k not found")) }.toMap()
|
||||
(settableFields.keys.toSet() + gettableFields)
|
||||
.associateWith { k -> (vm[k] ?: error("Field $k not found")) }
|
||||
} }
|
||||
|
||||
@API("user-detail")
|
||||
|
@ -144,13 +146,13 @@ abstract class GameApiController<T : IUserData>(val name: String, userDataClass:
|
|||
plays.forEach { play ->
|
||||
val lvl = musicMapping[play.musicId]?.notes?.getOrNull(if (play.level == 10) 0 else play.level)?.lv ?: return@forEach
|
||||
shownRanks.find { (s, _) -> play.achievement > s }?.let { (_, v) ->
|
||||
val ranks = detailedRanks.getOrPut(lvl.toInt()) { rankMap.toMutableMap() }
|
||||
val ranks = detailedRanks.getOrPut(lvl.toInt()) { rankMap.mut }
|
||||
ranks[v] = ranks[v]!! + 1
|
||||
}
|
||||
}
|
||||
|
||||
// Collapse detailed ranks to get non-detailed ranks map<rank, count>
|
||||
val ranks = shownRanks.associate { (_, v) -> v to 0 }.toMutableMap().also { ranks ->
|
||||
val ranks = shownRanks.associate { (_, v) -> v to 0 }.mut.also { ranks ->
|
||||
plays.forEach { play ->
|
||||
shownRanks.find { (s, _) -> play.achievement > s }?.let { (_, v) -> ranks[v] = ranks[v]!! + 1 }
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package icu.samnyan.aqua.net.games
|
|||
|
||||
import ext.isoDate
|
||||
import ext.minus
|
||||
import ext.mut
|
||||
import java.time.LocalDate
|
||||
|
||||
const val LETTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
|
||||
|
@ -20,7 +21,7 @@ fun usernameCheck(chars: String): (IUserData, String) -> Unit = { u, v ->
|
|||
u.userName = v
|
||||
if (v.isBlank()) { 400 - "Username cannot be blank" }
|
||||
if (v.length > 8) { 400 - "Username too long" }
|
||||
v.find { it !in chars }?.let { 400 - "Invalid character '$it' in username" }
|
||||
// v.find { it !in chars }?.let { 400 - "Invalid character '$it' in username" }
|
||||
}
|
||||
|
||||
fun toFullWidth(input: String): String {
|
||||
|
@ -60,7 +61,7 @@ fun findTrend(log: List<TrendLog>): List<TrendOut> {
|
|||
val trend = d.distinctBy { it.date }
|
||||
.map { TrendOut(it.date, maxRating[it.date] ?: 0,
|
||||
playCounts[it.date] ?: 0) }
|
||||
.sortedBy { it.date }.toMutableList()
|
||||
.sortedBy { it.date }.mut
|
||||
|
||||
// Fill in the missing dates (min date and current date)
|
||||
trend[0].let { if (it.date > minDate) trend.add(0, TrendOut(minDate, 0, 0)) }
|
||||
|
|
|
@ -38,6 +38,7 @@ class Chusan(
|
|||
"avatarFront" to { u, v -> u.avatarFront = v.int },
|
||||
"avatarBack" to { u, v -> u.avatarBack = v.int },
|
||||
) }
|
||||
override val gettableFields: Set<String> = setOf("level", "playerRating", "characterId")
|
||||
|
||||
override suspend fun userSummary(@RP username: Str, @RP token: String?) = us.cardByName(username) { card ->
|
||||
// Summary values: total plays, player rating, server-wide ranking
|
||||
|
@ -61,15 +62,4 @@ class Chusan(
|
|||
val u = userDataRepo.findByCard(it.ghostCard) ?: (404 - "Game data not found")
|
||||
mapOf("user" to u, "items" to rp.userItem.findAllByUser(u))
|
||||
}
|
||||
|
||||
@API("user-box-all-items")
|
||||
fun userBoxAllItems() = allItems
|
||||
val allItems by lazy { mapOf(
|
||||
"nameplate" to rp.gameNamePlate.findAll(),
|
||||
"frame" to rp.gameFrame.findAll(),
|
||||
"trophy" to rp.gameTrophy.findAll(),
|
||||
"mapicon" to rp.gameMapIcon.findAll(),
|
||||
"sysvoice" to rp.gameSystemVoice.findAll(),
|
||||
"avatar" to rp.gameAvatarAcc.findAll(),
|
||||
) }
|
||||
}
|
||||
|
|
|
@ -26,9 +26,7 @@ class Maimai2(
|
|||
// Only show > S rank
|
||||
override val shownRanks = mai2Scores.filter { it.first >= 97 * 10000 }
|
||||
override val settableFields: Map<String, (Mai2UserDetail, String) -> Unit> by lazy {
|
||||
mapOf(
|
||||
"userName" to usernameCheck(SEGA_USERNAME_CAHRS),
|
||||
)
|
||||
mapOf("userName" to usernameCheck(SEGA_USERNAME_CAHRS))
|
||||
}
|
||||
|
||||
override suspend fun userSummary(@RP username: Str, @RP token: String?) = us.cardByName(username) { card ->
|
||||
|
@ -127,7 +125,7 @@ class Maimai2(
|
|||
user = repos.userData.findByCardExtId(myCard.extId).orElse(null) ?: (404 - "User not found")
|
||||
propertyKey = "favorite_rival"
|
||||
}
|
||||
val myRivalList = myRival.propertyValue.split(',').filter { it.isNotEmpty() }.toMutableSet()
|
||||
val myRivalList = myRival.propertyValue.split(',').filter { it.isNotEmpty() }.mut
|
||||
|
||||
if (isAdd && myRivalList.size >= 4) {
|
||||
(400 - "Rival list is full")
|
||||
|
|
|
@ -2,9 +2,9 @@ package icu.samnyan.aqua.sega.aimedb
|
|||
|
||||
import ext.toHex
|
||||
import icu.samnyan.aqua.net.db.AquaUserServices
|
||||
import icu.samnyan.aqua.sega.allnet.AllNetProps
|
||||
import icu.samnyan.aqua.sega.general.model.Card
|
||||
import icu.samnyan.aqua.sega.general.service.CardService
|
||||
import icu.samnyan.aqua.sega.allnet.AllNetProps
|
||||
import io.netty.buffer.ByteBuf
|
||||
import io.netty.buffer.ByteBufUtil
|
||||
import io.netty.buffer.Unpooled
|
||||
|
@ -67,7 +67,8 @@ class AimeDB(
|
|||
logger.info("AimeDB /${handler.name} : (game ${base.gameId}, keychip ${base.keychipId})")
|
||||
|
||||
// Check keychip
|
||||
if (!us.validKeychip(base.keychipId)) {
|
||||
// We do not check for type 0x13 because of a bug in duolinguo.dll
|
||||
if (!us.validKeychip(base.keychipId) && type != 0x13) {
|
||||
if (allNetProps.keychipPermissiveForTesting) {
|
||||
logger.warn("> Accepted invalid keychip ${base.keychipId} in permissive mode")
|
||||
} else {
|
||||
|
|
|
@ -139,7 +139,7 @@ class AllNet(
|
|||
val ver = reqMap["ver"] ?: "1.0"
|
||||
|
||||
val formatVer = reqMap["format_ver"] ?: ""
|
||||
val resp = props.map.toMutableMap() + mapOf(
|
||||
val resp = props.map.mut + mapOf(
|
||||
"uri" to switchUri(localAddr, localPort, gameId, ver, session),
|
||||
"host" to props.host.ifBlank { localAddr },
|
||||
)
|
||||
|
|
|
@ -4,9 +4,10 @@ import ext.*
|
|||
import icu.samnyan.aqua.net.db.AquaUserServices
|
||||
import icu.samnyan.aqua.net.utils.simpleDescribe
|
||||
import icu.samnyan.aqua.sega.allnet.TokenChecker
|
||||
import icu.samnyan.aqua.sega.chusan.handler.*
|
||||
import icu.samnyan.aqua.sega.chusan.handler.chusanInit
|
||||
import icu.samnyan.aqua.sega.chusan.model.Chu3Repos
|
||||
import icu.samnyan.aqua.sega.general.*
|
||||
import icu.samnyan.aqua.sega.general.MeowApi
|
||||
import icu.samnyan.aqua.sega.general.RequestContext
|
||||
import icu.samnyan.aqua.sega.util.jackson.BasicMapper
|
||||
import icu.samnyan.aqua.sega.util.jackson.StringMapper
|
||||
import icu.samnyan.aqua.spring.Metrics
|
||||
|
@ -14,7 +15,6 @@ import jakarta.servlet.http.HttpServletRequest
|
|||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.web.bind.annotation.RestController
|
||||
import kotlin.collections.set
|
||||
import kotlin.reflect.full.declaredMemberProperties
|
||||
|
||||
/**
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
|
@ -23,12 +23,6 @@ import kotlin.reflect.full.declaredMemberProperties
|
|||
@RestController
|
||||
@API(value = ["/g/chu3/{version}/ChuniServlet", "/g/chu3/{version}"])
|
||||
class ChusanController(
|
||||
val gameLogin: GameLoginHandler,
|
||||
val upsertUserAll: UpsertUserAllHandler,
|
||||
val cmUpsertUserGacha: CMUpsertUserGachaHandler,
|
||||
val cmUpsertUserPrintSubtract: CMUpsertUserPrintSubtractHandler,
|
||||
val cmUpsertUserPrintCancel: CMUpsertUserPrintCancelHandler,
|
||||
|
||||
val mapper: StringMapper,
|
||||
val cmMapper: BasicMapper,
|
||||
val db: Chu3Repos,
|
||||
|
@ -41,23 +35,12 @@ class ChusanController(
|
|||
}) {
|
||||
val log = LoggerFactory.getLogger(ChusanController::class.java)
|
||||
|
||||
// Below are code related to handling the handlers
|
||||
val externalHandlers = mutableListOf("GameLoginApi", "UpsertUserAllApi",
|
||||
"CMUpsertUserGachaApi", "CMUpsertUserPrintCancelApi", "CMUpsertUserPrintSubtractApi")
|
||||
|
||||
val noopEndpoint = setOf("UpsertClientBookkeepingApi", "UpsertClientDevelopApi", "UpsertClientErrorApi",
|
||||
"UpsertClientSettingApi", "UpsertClientTestmodeApi", "CreateTokenApi", "RemoveTokenApi", "UpsertClientUploadApi",
|
||||
"PrinterLoginApi", "PrinterLogoutApi", "Ping", "GameLogoutApi", "RemoveMatchingMemberApi")
|
||||
|
||||
init { chusanInit() }
|
||||
|
||||
val members = this::class.declaredMemberProperties
|
||||
val handlers: Map<String, SpecialHandler> = initH + externalHandlers.associateWith { api ->
|
||||
val name = api.replace("Api", "").lowercase()
|
||||
(members.find { it.name.lowercase() == name } ?: members.find { it.name.lowercase() == name.replace("cm", "") })
|
||||
?.let { (it.call(this) as BaseHandler).toSpecial() }
|
||||
?: throw IllegalArgumentException("Chu3: No handler found for $api")
|
||||
}
|
||||
val handlers = initH
|
||||
|
||||
@API("/{endpoint}", "/MatchingServer/{endpoint}")
|
||||
fun handle(@PV endpoint: Str, @RB data: MutableMap<Str, Any>, @PV version: Str, req: HttpServletRequest): Any {
|
||||
|
@ -72,6 +55,8 @@ class ChusanController(
|
|||
}
|
||||
|
||||
if (api.startsWith("CM") && api !in handlers) api = api.removePrefix("CM")
|
||||
val token = TokenChecker.getCurrentSession()?.token?.substring(0, 6) ?: "NO-TOKEN"
|
||||
log.info("Chu3 < $api : ${data.toJson()} : [$token]")
|
||||
|
||||
if (api !in noopEndpoint && !handlers.containsKey(api)) {
|
||||
log.warn("Chu3 > $api not found")
|
||||
|
@ -84,8 +69,6 @@ class ChusanController(
|
|||
log.info("Chu3 > $api no-op")
|
||||
return """{"returnCode":"1"}"""
|
||||
}
|
||||
val token = TokenChecker.getCurrentSession()?.token?.substring(0, 6) ?: "NO-TOKEN"
|
||||
log.info("Chu3 < $api : ${data.toJson()} : [$token]")
|
||||
|
||||
return try {
|
||||
Metrics.timer("aquadx_chusan_api_latency", "api" to api).recordCallable {
|
||||
|
|
|
@ -10,5 +10,4 @@ class ChusanProps {
|
|||
var loginBonusEnable = false
|
||||
var externalMatching: String? = null
|
||||
var reflectorUrl: String? = null
|
||||
var proxiedMatching: Boolean = false
|
||||
}
|
|
@ -1,101 +0,0 @@
|
|||
package icu.samnyan.aqua.sega.chusan.handler;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import icu.samnyan.aqua.sega.chusan.model.Chu3UserCardPrintStateRepo;
|
||||
import icu.samnyan.aqua.sega.chusan.model.Chu3UserGachaRepo;
|
||||
import icu.samnyan.aqua.sega.general.BaseHandler;
|
||||
import icu.samnyan.aqua.sega.chusan.model.gamedata.GameGachaCard;
|
||||
import icu.samnyan.aqua.sega.chusan.model.request.UpsertUserGacha;
|
||||
import icu.samnyan.aqua.sega.chusan.model.userdata.UserCardPrintState;
|
||||
import icu.samnyan.aqua.sega.chusan.model.userdata.Chu3UserData;
|
||||
import icu.samnyan.aqua.sega.chusan.model.userdata.UserGacha;
|
||||
import icu.samnyan.aqua.sega.chusan.model.userdata.UserItem;
|
||||
import icu.samnyan.aqua.sega.chusan.service.UserDataService;
|
||||
import icu.samnyan.aqua.sega.chusan.service.UserItemService;
|
||||
import icu.samnyan.aqua.sega.util.jackson.BasicMapper;
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
@Component("ChusanCMUpsertUserGachaHandler")
|
||||
public class CMUpsertUserGachaHandler implements BaseHandler {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(CMUpsertUserGachaHandler.class);
|
||||
private final Chu3UserCardPrintStateRepo userCardPrintStateRepository;
|
||||
private final Chu3UserGachaRepo userGachaRepository;
|
||||
private final UserDataService userDataService;
|
||||
private final UserItemService userItemService;
|
||||
private final BasicMapper mapper;
|
||||
|
||||
@Override
|
||||
public Object handle(Map<String, ?> request) throws JsonProcessingException {
|
||||
String userId = String.valueOf(request.get("userId"));
|
||||
int gachaId = ((Number) request.get("gachaId")).intValue();
|
||||
int placeId = ((Number) request.get("placeId")).intValue();
|
||||
|
||||
UpsertUserGacha upsertUserGacha = mapper.convert(request.get("cmUpsertUserGacha"), UpsertUserGacha.class);
|
||||
List<UserCardPrintState> userCardPrintStateList = new ArrayList<>();
|
||||
Chu3UserData userData;
|
||||
|
||||
Optional<Chu3UserData> userOptional = userDataService.getUserByExtId(userId);
|
||||
if (userOptional.isPresent()) {
|
||||
userData = userOptional.get();
|
||||
} else {
|
||||
logger.error("User not found. userId: {}", userId);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (upsertUserGacha.getGameGachaCardList() != null) {
|
||||
for (GameGachaCard gameGachaCard : upsertUserGacha.getGameGachaCardList()) {
|
||||
UserCardPrintState userCardPrintState = new UserCardPrintState();
|
||||
userCardPrintState.setHasCompleted(false);
|
||||
userCardPrintState.setLimitDate(LocalDateTime.of(2029, 01, 01, 0, 0));
|
||||
userCardPrintState.setPlaceId(placeId);
|
||||
userCardPrintState.setCardId(gameGachaCard.getCardId());
|
||||
userCardPrintState.setGachaId(gachaId);
|
||||
userCardPrintState.setUser(userData);
|
||||
userCardPrintStateRepository.save(userCardPrintState);
|
||||
}
|
||||
}
|
||||
|
||||
List<UserItem> userItemListToSave = new ArrayList<>();
|
||||
List<UserItem> userItemList = upsertUserGacha.getUserItemList();
|
||||
|
||||
userItemList.forEach(newUserItem -> {
|
||||
int itemId = newUserItem.getItemId();
|
||||
int itemKind = newUserItem.getItemKind();
|
||||
|
||||
Optional<UserItem> userItemOptional = userItemService.getByUserAndItemIdAndKind(userData, itemId, itemKind);
|
||||
UserItem userItem = userItemOptional.orElseGet(() -> new UserItem(userData));
|
||||
|
||||
newUserItem.setId(userItem.getId());
|
||||
newUserItem.setUser(userItem.getUser());
|
||||
|
||||
userItemListToSave.add(newUserItem);
|
||||
});
|
||||
userItemService.saveAll(userItemListToSave);
|
||||
|
||||
if (upsertUserGacha.getUserGacha() != null) {
|
||||
UserGacha newUserGacha = upsertUserGacha.getUserGacha();
|
||||
newUserGacha.setUser(userData);
|
||||
userGachaRepository.save(newUserGacha);
|
||||
}
|
||||
|
||||
userCardPrintStateList = userCardPrintStateRepository.findByUserAndGachaIdAndHasCompleted(userData, gachaId, false);
|
||||
Map<String, Object> resultMap = new LinkedHashMap<>();
|
||||
resultMap.put("returnCode", 1);
|
||||
resultMap.put("apiName", "CMUpsertUserGachaApi");
|
||||
resultMap.put("userCardPrintStateList", userCardPrintStateList);
|
||||
|
||||
return resultMap;
|
||||
}
|
||||
}
|
|
@ -1,57 +0,0 @@
|
|||
package icu.samnyan.aqua.sega.chusan.handler;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import icu.samnyan.aqua.sega.chusan.model.Chu3UserCardPrintStateRepo;
|
||||
import icu.samnyan.aqua.sega.general.BaseHandler;
|
||||
import icu.samnyan.aqua.sega.chusan.model.userdata.UserCardPrintState;
|
||||
import icu.samnyan.aqua.sega.util.jackson.BasicMapper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@Component("ChusanCMUpsertUserPrintCancelHandler")
|
||||
public class CMUpsertUserPrintCancelHandler implements BaseHandler {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(CMUpsertUserPrintCancelHandler.class);
|
||||
private final Chu3UserCardPrintStateRepo userCardPrintStateRepository;
|
||||
private final BasicMapper mapper;
|
||||
|
||||
@Autowired
|
||||
public CMUpsertUserPrintCancelHandler(Chu3UserCardPrintStateRepo userCardPrintStateRepository, BasicMapper mapper) {
|
||||
this.userCardPrintStateRepository = userCardPrintStateRepository;
|
||||
this.mapper = mapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String handle(Map<String, ?> request) throws JsonProcessingException {
|
||||
String userId = String.valueOf(request.get("userId"));
|
||||
List<Integer> orderIdList = mapper.convert(request.get("orderIdList"), new TypeReference<List<Integer>>() {});
|
||||
|
||||
for (Integer orderId : orderIdList) {
|
||||
Optional<UserCardPrintState> userCardPrintStateOptional = userCardPrintStateRepository.findById(orderId.longValue());
|
||||
if (userCardPrintStateOptional.isPresent()) {
|
||||
UserCardPrintState newUserCardPrintState = userCardPrintStateOptional.get();
|
||||
newUserCardPrintState.setHasCompleted(true);
|
||||
userCardPrintStateRepository.save(newUserCardPrintState);
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, Object> resultMap = new LinkedHashMap<>();
|
||||
resultMap.put("returnCode", 1);
|
||||
resultMap.put("apiName", "CMUpsertUserPrintCancelApi");
|
||||
|
||||
String json = mapper.write(resultMap);
|
||||
logger.info("Response: " + json);
|
||||
return json;
|
||||
}
|
||||
}
|
|
@ -1,81 +0,0 @@
|
|||
package icu.samnyan.aqua.sega.chusan.handler;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import icu.samnyan.aqua.sega.chusan.model.Chu3UserCardPrintStateRepo;
|
||||
import icu.samnyan.aqua.sega.general.BaseHandler;
|
||||
import icu.samnyan.aqua.sega.chusan.model.userdata.UserCardPrintState;
|
||||
import icu.samnyan.aqua.sega.chusan.model.userdata.Chu3UserData;
|
||||
import icu.samnyan.aqua.sega.chusan.model.userdata.UserItem;
|
||||
import icu.samnyan.aqua.sega.chusan.service.UserDataService;
|
||||
import icu.samnyan.aqua.sega.chusan.service.UserItemService;
|
||||
import icu.samnyan.aqua.sega.util.jackson.BasicMapper;
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
@Component("ChusanCMUpsertUserPrintSubtractHandler")
|
||||
public class CMUpsertUserPrintSubtractHandler implements BaseHandler {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(CMUpsertUserPrintSubtractHandler.class);
|
||||
private final Chu3UserCardPrintStateRepo userCardPrintStateRepository;
|
||||
private final UserItemService userItemService;
|
||||
private final UserDataService userDataService;
|
||||
private final BasicMapper mapper;
|
||||
|
||||
@Override
|
||||
public String handle(Map<String, ?> request) throws JsonProcessingException {
|
||||
String userId = String.valueOf(request.get("userId"));
|
||||
UserCardPrintState userCardPrintState = mapper.convert(request.get("userCardPrintState"), UserCardPrintState.class);
|
||||
List<UserItem> userItemList = mapper.convert(request.get("userItemList"), new TypeReference<List<UserItem>>() {});
|
||||
|
||||
Chu3UserData userData;
|
||||
|
||||
Optional<Chu3UserData> userOptional = userDataService.getUserByExtId(userId);
|
||||
if (userOptional.isPresent()) {
|
||||
userData = userOptional.get();
|
||||
} else {
|
||||
logger.error("User not found. userId: {}", userId);
|
||||
return null;
|
||||
}
|
||||
|
||||
List<UserItem> userItemListToSave = new ArrayList<>();
|
||||
|
||||
userItemList.forEach(newUserItem -> {
|
||||
int itemId = newUserItem.getItemId();
|
||||
int itemKind = newUserItem.getItemKind();
|
||||
|
||||
Optional<UserItem> userItemOptional = userItemService.getByUserAndItemIdAndKind(userData, itemId, itemKind);
|
||||
UserItem userItem = userItemOptional.orElseGet(() -> new UserItem(userData));
|
||||
|
||||
newUserItem.setId(userItem.getId());
|
||||
newUserItem.setUser(userItem.getUser());
|
||||
|
||||
userItemListToSave.add(newUserItem);
|
||||
});
|
||||
userItemService.saveAll(userItemListToSave);
|
||||
|
||||
Optional<UserCardPrintState> userCardPrintStateOptional = userCardPrintStateRepository.findById(userCardPrintState.getId());
|
||||
if (userCardPrintStateOptional.isPresent()) {
|
||||
UserCardPrintState newUserCardPrintState = userCardPrintStateOptional.get();
|
||||
newUserCardPrintState.setHasCompleted(true);
|
||||
userCardPrintStateRepository.save(newUserCardPrintState);
|
||||
}
|
||||
|
||||
Map<String, Object> resultMap = new LinkedHashMap<>();
|
||||
resultMap.put("returnCode", 1);
|
||||
resultMap.put("apiName", "CMUpsertUserPrintSubtractApi");
|
||||
|
||||
String json = mapper.write(resultMap);
|
||||
logger.info("Response: " + json);
|
||||
return json;
|
||||
}
|
||||
}
|
|
@ -1,9 +1,10 @@
|
|||
package icu.samnyan.aqua.sega.chusan
|
||||
package icu.samnyan.aqua.sega.chusan.handler
|
||||
|
||||
import ext.*
|
||||
import icu.samnyan.aqua.sega.allnet.TokenChecker
|
||||
import icu.samnyan.aqua.sega.chusan.ChusanController
|
||||
import icu.samnyan.aqua.sega.chusan.ChusanData
|
||||
import icu.samnyan.aqua.sega.chusan.model.request.UserCMissionResp
|
||||
import icu.samnyan.aqua.sega.chusan.model.response.data.UserEmoney
|
||||
import icu.samnyan.aqua.sega.chusan.model.userdata.UserCharge
|
||||
import icu.samnyan.aqua.sega.chusan.model.userdata.UserItem
|
||||
import icu.samnyan.aqua.sega.chusan.model.userdata.UserMusicDetail
|
||||
import icu.samnyan.aqua.sega.general.model.response.UserRecentRating
|
||||
|
@ -12,6 +13,8 @@ import java.time.format.DateTimeFormatter
|
|||
@Suppress("UNCHECKED_CAST")
|
||||
fun ChusanController.chusanInit() {
|
||||
matchingApiInit()
|
||||
cmApiInit()
|
||||
upsertApiInit()
|
||||
|
||||
// Stub handlers
|
||||
"GetGameRanking" { """{"type":"${data["type"]}","length":"0","gameRankingList":[]}""" }
|
||||
|
@ -25,11 +28,18 @@ fun ChusanController.chusanInit() {
|
|||
"GetUserRegion" { """{"userId":"${data["userId"]}","length":"0","userRegionList":[]}""" }
|
||||
"GetUserPrintedCard" { """{"userId":"${data["userId"]}","length":0,"nextIndex":-1,"userPrintedCardList":[]}""" }
|
||||
"GetUserSymbolChatSetting" { """{"userId":"${data["userId"]}","length":"0","symbolChatInfoList":[]}""" }
|
||||
"GetUserNetBattleData" { """{"userId":"${data["userId"]}","userNetBattleData":{"recentNBSelectMusicList":[],"recentNBMusicList":[]}}""" }
|
||||
"GetUserNetBattleRankingInfo" { """{"userId":"${data["userId"]}","length":"0","userNetBattleRankingInfoList":{}}""" }
|
||||
|
||||
"CMUpsertUserPrint" { """{"returnCode":1,"orderId":"0","serialId":"FAKECARDIMAG12345678","apiName":"CMUpsertUserPrintApi"}""" }
|
||||
"CMUpsertUserPrintlog" { """{"returnCode":1,"orderId":"0","serialId":"FAKECARDIMAG12345678","apiName":"CMUpsertUserPrintlogApi"}""" }
|
||||
// Net battle data
|
||||
"GetUserNetBattleData" api@ {
|
||||
val u = db.userData.findByCard_ExtId(uid)() ?: return@api null
|
||||
val misc = db.userMisc.findSingleByUser(u)()
|
||||
val recent = db.netBattleLog.findTop20ByUserOrderByIdDesc(u)
|
||||
mapOf("userId" to uid, "userNetBattleData" to mapOf(
|
||||
"recentNBSelectMusicList" to (misc?.recentNbSelect ?: empty),
|
||||
"recentNBMusicList" to recent.map { it.toDict(u.userName) },
|
||||
))
|
||||
}
|
||||
"GetUserNetBattleRankingInfo" { """{"userId":"${data["userId"]}","length":"0","userNetBattleRankingInfoList":{}}""" }
|
||||
|
||||
// User handlers
|
||||
"GetUserData" {
|
||||
|
@ -57,7 +67,6 @@ fun ChusanController.chusanInit() {
|
|||
|
||||
"GetUserCMission" {
|
||||
parsing { UserCMissionResp().apply {
|
||||
userId = uid
|
||||
missionId = parsing { data["missionId"]!!.int }
|
||||
} }.apply {
|
||||
db.userCMission.findByUser_Card_ExtIdAndMissionId(uid, missionId)()?.let {
|
||||
|
@ -92,7 +101,7 @@ fun ChusanController.chusanInit() {
|
|||
data["nextIndex"] = rawIndex % 10000000000L
|
||||
mapOf("itemKind" to kind) grabs {
|
||||
// TODO: All unlock
|
||||
val items = db.userItem.findAllByUser_Card_ExtIdAndItemKind(uid, kind).toMutableList()
|
||||
val items = db.userItem.findAllByUser_Card_ExtIdAndItemKind(uid, kind).mut
|
||||
|
||||
// Check game options
|
||||
db.userData.findByCard_ExtId(uid)()?.card?.aquaUser?.gameOptions?.let {
|
||||
|
@ -112,14 +121,12 @@ fun ChusanController.chusanInit() {
|
|||
"GetUserFavoriteItem".pagedWithKind("userFavoriteItemList") {
|
||||
val kind = parsing { data["kind"]!!.int }
|
||||
mapOf("kind" to kind) grabs {
|
||||
// TODO: Actually store this info at UpsertUserAll
|
||||
val fav = when (kind) {
|
||||
1 -> "favorite_music"
|
||||
3 -> "favorite_chara"
|
||||
else -> null
|
||||
}?.let { db.userGeneralData.findByUser_Card_ExtIdAndPropertyKey(uid, it)() }?.propertyValue
|
||||
|
||||
fav?.ifBlank { null }?.split(",")?.map { it.int } ?: emptyList()
|
||||
val misc = db.userMisc.findSingleByUser_Card_ExtId(uid)()
|
||||
when (kind) {
|
||||
1 -> misc?.favMusic ?: empty
|
||||
3 -> empty // TODO: Favorite character
|
||||
else -> empty
|
||||
}.map { mapOf("id" to it) }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -147,7 +154,7 @@ fun ChusanController.chusanInit() {
|
|||
// Compatibility: Older chusan uses boolean for isSuccess
|
||||
fun checkAncient(d: List<UserMusicDetail>) =
|
||||
data["version"]?.double?.let { if (it >= 2.15) d else d.map {
|
||||
d.toJson().jsonMap().toMutableMap().apply { this["isSuccess"] = this["isSuccess"].truthy }
|
||||
d.toJson().jsonMap().mut.apply { this["isSuccess"] = this["isSuccess"].truthy }
|
||||
} } ?: d
|
||||
|
||||
db.userMusicDetail.findByUser_Card_ExtId(uid).groupBy { it.musicId }
|
||||
|
@ -193,19 +200,16 @@ fun ChusanController.chusanInit() {
|
|||
// Special thanks to skogaby
|
||||
// Hardcode so that the reboot time always started 3 hours ago and ended 2 hours ago
|
||||
val fmt = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss")
|
||||
|
||||
// Get the request url as te address
|
||||
val addr = (req.getHeader("wrapper original url") ?: req.requestURL.toString())
|
||||
.removeSuffix("GetGameSettingApi").removeSuffix("ChuniServlet/")
|
||||
val now = jstNow()
|
||||
|
||||
val matching = if (!props.externalMatching.isNullOrBlank() && !props.proxiedMatching) mapOf(
|
||||
"matchingUri" to props.externalMatching,
|
||||
"matchingUriX" to props.externalMatching,
|
||||
) else mapOf(
|
||||
"matchingUri" to addr,
|
||||
"matchingUriX" to addr
|
||||
)
|
||||
// Set the matching & reflector to the one set in the game options, or the external matching server
|
||||
val opts = TokenChecker.getCurrentSession()?.user?.gameOptions
|
||||
val matching = opts?.chusanMatchingServer?.ifBlank { null } ?:
|
||||
props.externalMatching?.ifBlank { null } ?:
|
||||
(req.getHeader("wrapper original url") ?: req.requestURL.toString())
|
||||
.removeSuffix("GetGameSettingApi").removeSuffix("ChuniServlet/")
|
||||
val reflector = opts?.chusanMatchingReflector?.ifBlank { null } ?:
|
||||
props.reflectorUrl
|
||||
|
||||
mapOf(
|
||||
"gameSetting" to mapOf(
|
||||
|
@ -223,39 +227,70 @@ fun ChusanController.chusanInit() {
|
|||
"matchEndTime" to now.plusHours(7).format(fmt),
|
||||
"matchTimeLimit" to 10,
|
||||
"matchErrorLimit" to 10,
|
||||
"matchingUri" to addr,
|
||||
"matchingUriX" to addr,
|
||||
"udpHolePunchUri" to props.reflectorUrl,
|
||||
"reflectorUri" to props.reflectorUrl,
|
||||
) + matching,
|
||||
"matchingUri" to matching.ensureEndingSlash(),
|
||||
"matchingUriX" to matching.ensureEndingSlash(),
|
||||
"udpHolePunchUri" to reflector?.ensureEndingSlash(),
|
||||
"reflectorUri" to reflector?.ensureEndingSlash(),
|
||||
),
|
||||
"isDumpUpload" to false,
|
||||
"isAou" to false
|
||||
)
|
||||
}
|
||||
|
||||
// Upserts
|
||||
"UpsertUserChargelog" {
|
||||
val charge = parsing { mapper.convert<UserCharge>(data["userCharge"] as JDict) }
|
||||
charge.user = db.userData.findByCard_ExtId(uid)() ?: (400 - "User not found")
|
||||
charge.id = db.userCharge.findByUser_Card_ExtIdAndChargeId(uid, charge.chargeId)?.id ?: 0
|
||||
db.userCharge.save(charge)
|
||||
"""{"returnCode":"1"}"""
|
||||
}
|
||||
|
||||
// Static
|
||||
"GetGameEvent" static { db.gameEvent.findByEnable(true).let { mapOf("type" to 1, "length" to it.size, "gameEventList" to it) } }
|
||||
"GetGameCharge" static { db.gameCharge.findAll().let { mapOf("length" to it.size, "gameChargeList" to it) } }
|
||||
"GetGameGacha" static { db.gameGacha.findAll().let { mapOf("length" to it.size, "gameGachaList" to it, "registIdList" to empty) } }
|
||||
"GetGameMapAreaCondition" static { ChusanData.mapAreaCondition }
|
||||
|
||||
// CardMaker (TODO: Somebody test this, I don't have a card maker)
|
||||
"CMGetUserData" {
|
||||
val user = db.userData.findByCard_ExtId(uid)() ?: (400 - "User not found")
|
||||
user.userEmoney = UserEmoney()
|
||||
mapOf("userId" to uid, "userData" to user, "userEmoney" to user.userEmoney)
|
||||
}
|
||||
"CMGetUserPreview" {
|
||||
val user = db.userData.findByCard_ExtId(uid)() ?: (400 - "User not found")
|
||||
mapOf("userName" to user.userName, "level" to user.level, "medal" to user.medal, "lastDataVersion" to user.lastDataVersion, "isLogin" to false)
|
||||
// TODO: Test login bonus
|
||||
"GameLogin" {
|
||||
// fun process() {
|
||||
// val u = db.userData.findByCard_ExtId(uid)() ?: return
|
||||
// db.userData.save(u.apply { lastLoginDate = LocalDateTime.now() })
|
||||
//
|
||||
// if (!props.loginBonusEnable) return
|
||||
// val bonusList = db.gameLoginBonusPresets.findLoginBonusPresets(1, 1)
|
||||
//
|
||||
// bonusList.forEach { preset ->
|
||||
// // Check if a user already has some progress and if not, add the login bonus entry
|
||||
// val bonus = db.userLoginBonus.findLoginBonus(uid.int, 1, preset.id)()
|
||||
// ?: UserLoginBonus(1, uid.int, preset.id).let { db.userLoginBonus.save(it) }
|
||||
// if (bonus.isFinished) return@forEach
|
||||
//
|
||||
// // last login is 24 hours+ ago
|
||||
// if (bonus.lastUpdateDate.toEpochSecond(ZoneOffset.ofHours(0)) <
|
||||
// (LocalDateTime.now().minusHours(24).toEpochSecond(ZoneOffset.ofHours(0)))
|
||||
// ) {
|
||||
// var bCount = bonus.bonusCount + 1
|
||||
// val lastUpdate = LocalDateTime.now()
|
||||
// val allLoginBonus = db.gameLoginBonus.findGameLoginBonus(1, preset.id)
|
||||
// .ifEmpty { return@forEach }
|
||||
// val maxNeededDays = allLoginBonus[0].needLoginDayCount
|
||||
//
|
||||
// // if all items are redeemed, then don't show the login bonuses.
|
||||
// var finished = false
|
||||
// if (bCount > maxNeededDays) {
|
||||
// if (preset.id < 3000) bCount = 1
|
||||
// else finished = true
|
||||
// }
|
||||
// db.gameLoginBonus.findByRequiredDays(1, preset.id, bCount)()?.let {
|
||||
// db.userItem.save(UserItem(6, it.presentId, it.itemNum).apply { user = u })
|
||||
// }
|
||||
// val toSave = db.userLoginBonus.findLoginBonus(uid.int, 1, preset.id)()
|
||||
// ?: UserLoginBonus().apply { user = uid.int; presetId = preset.id; version = 1 }
|
||||
//
|
||||
// db.userLoginBonus.save(toSave.apply {
|
||||
// bonusCount = bCount
|
||||
// lastUpdateDate = lastUpdate
|
||||
// isWatched = false
|
||||
// isFinished = finished
|
||||
// })
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// process()
|
||||
|
||||
"""{"returnCode":"1"}"""
|
||||
}
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
package icu.samnyan.aqua.sega.chusan.handler
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference
|
||||
import ext.*
|
||||
import icu.samnyan.aqua.sega.chusan.ChusanController
|
||||
import icu.samnyan.aqua.sega.chusan.model.request.UpsertUserGacha
|
||||
import icu.samnyan.aqua.sega.chusan.model.request.UserEmoney
|
||||
import icu.samnyan.aqua.sega.chusan.model.userdata.UserCardPrintState
|
||||
import icu.samnyan.aqua.sega.chusan.model.userdata.UserItem
|
||||
import java.time.LocalDateTime
|
||||
|
||||
fun ChusanController.cmApiInit() {
|
||||
"CMUpsertUserPrint" { """{"returnCode":1,"orderId":"0","serialId":"FAKECARDIMAG12345678","apiName":"CMUpsertUserPrintApi"}""" }
|
||||
"CMUpsertUserPrintlog" { """{"returnCode":1,"orderId":"0","serialId":"FAKECARDIMAG12345678","apiName":"CMUpsertUserPrintlogApi"}""" }
|
||||
|
||||
// CardMaker (TODO: Somebody test this, I don't have a card maker)
|
||||
"CMGetUserData" {
|
||||
val user = db.userData.findByCard_ExtId(uid)() ?: (400 - "User not found")
|
||||
user.userEmoney = UserEmoney()
|
||||
mapOf("userId" to uid, "userData" to user, "userEmoney" to user.userEmoney)
|
||||
}
|
||||
|
||||
"CMGetUserPreview" {
|
||||
val user = db.userData.findByCard_ExtId(uid)() ?: (400 - "User not found")
|
||||
mapOf("userName" to user.userName, "level" to user.level, "medal" to user.medal, "lastDataVersion" to user.lastDataVersion, "isLogin" to false)
|
||||
}
|
||||
|
||||
"CMUpsertUserGacha" api@ {
|
||||
val (gachaId, placeId) = parsing { data["gachaId"]!!.int to data["placeId"]!!.int }
|
||||
|
||||
val u = db.userData.findByCard_ExtId(uid)() ?: return@api null
|
||||
val upsertUserGacha = parsing { mapper.convert(data["cmUpsertUserGacha"], UpsertUserGacha::class.java) }
|
||||
|
||||
upsertUserGacha.gameGachaCardList?.let { lst ->
|
||||
db.userCardPrintState.saveAll(lst.map {
|
||||
UserCardPrintState(
|
||||
hasCompleted = false,
|
||||
limitDate = LocalDateTime.of(2029, 1, 1, 0, 0),
|
||||
placeId = placeId,
|
||||
cardId = it.cardId,
|
||||
gachaId = gachaId
|
||||
).apply { user = u }
|
||||
})
|
||||
}
|
||||
|
||||
upsertUserGacha.userItemList?.let {
|
||||
db.userItem.saveAll(it.mapApply {
|
||||
user = u
|
||||
id = db.userItem.findByUserAndItemIdAndItemKind(u, itemId, itemKind)?.id ?: 0
|
||||
})
|
||||
}
|
||||
|
||||
upsertUserGacha.userGacha?.let {
|
||||
it.user = u
|
||||
db.userGacha.save(it)
|
||||
}
|
||||
|
||||
mapOf(
|
||||
"returnCode" to 1,
|
||||
"apiName" to "CMUpsertUserGachaApi",
|
||||
"userCardPrintStateList" to db.userCardPrintState.findByUserAndGachaIdAndHasCompleted(u, gachaId, false)
|
||||
)
|
||||
}
|
||||
|
||||
"CMUpsertUserPrintCancel" {
|
||||
val orderIdList: List<Long> = cmMapper.convert(data["orderIdList"], object : TypeReference<List<Long>>() {})
|
||||
|
||||
db.userCardPrintState.saveAll(orderIdList.mapNotNull {
|
||||
// TODO: The original code by Eori writes findById but I don't think that is correct...
|
||||
db.userCardPrintState.findById(it)()?.apply {
|
||||
hasCompleted = true
|
||||
}
|
||||
})
|
||||
|
||||
mapOf("returnCode" to 1, "apiName" to "CMUpsertUserPrintCancelApi")
|
||||
}
|
||||
|
||||
"CMUpsertUserPrintSubtract" api@ {
|
||||
val userCardPrintState = cmMapper.convert(data["userCardPrintState"], UserCardPrintState::class.java)
|
||||
val userItemList = cmMapper.convert(data["userItemList"], object : TypeReference<List<UserItem>>() {})
|
||||
|
||||
val u = db.userData.findByCard_ExtId(uid)() ?: return@api null
|
||||
|
||||
db.userItem.saveAll(
|
||||
userItemList.mapApply {
|
||||
id = db.userItem.findByUserAndItemIdAndItemKind(u, itemId, itemKind)?.id ?: 0
|
||||
user = u
|
||||
}
|
||||
)
|
||||
|
||||
// TODO: I also doubt this is correct... it shouldn't be ID
|
||||
db.userCardPrintState.findById(userCardPrintState.id)()?.apply {
|
||||
hasCompleted = true
|
||||
db.userCardPrintState.save(this)
|
||||
}
|
||||
|
||||
mapOf("returnCode" to 1, "apiName" to "CMUpsertUserPrintSubtractApi")
|
||||
}
|
||||
}
|
|
@ -1,15 +1,27 @@
|
|||
@file:Suppress("UNCHECKED_CAST")
|
||||
|
||||
package icu.samnyan.aqua.sega.chusan
|
||||
package icu.samnyan.aqua.sega.chusan.handler
|
||||
|
||||
import ext.*
|
||||
import icu.samnyan.aqua.sega.chusan.model.response.data.MatchingWaitState
|
||||
import ext.JDict
|
||||
import ext.int
|
||||
import ext.millis
|
||||
import ext.parsing
|
||||
import icu.samnyan.aqua.sega.chusan.ChusanController
|
||||
import icu.samnyan.aqua.sega.chusan.model.request.MatchingWaitState
|
||||
import icu.samnyan.aqua.sega.chusan.model.userdata.Chu3MatchingMemberReq
|
||||
import kotlin.collections.MutableList
|
||||
import kotlin.collections.find
|
||||
import kotlin.collections.indices
|
||||
import kotlin.collections.listOf
|
||||
import kotlin.collections.map
|
||||
import kotlin.collections.mapOf
|
||||
import kotlin.collections.mutableListOf
|
||||
import kotlin.collections.mutableMapOf
|
||||
import kotlin.collections.set
|
||||
|
||||
|
||||
fun ChusanController.matchingApiInit() {
|
||||
if (props.externalMatching.isNullOrBlank()) serverOnlyMatching()
|
||||
else if (props.proxiedMatching) proxyMatching()
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -56,49 +68,3 @@ fun ChusanController.serverOnlyMatching() {
|
|||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Matching implementation
|
||||
*/
|
||||
fun ChusanController.proxyMatching() {
|
||||
val ext = props.externalMatching!!
|
||||
|
||||
// ID Cache <obfuscated: original> is used to obfuscate the user ID
|
||||
val processedCache = mutableSetOf<Long>()
|
||||
val idCache = mutableMapOf<Long, Long>()
|
||||
|
||||
fun Chu3MatchingMemberReq.checkFromAquaDX(): Boolean {
|
||||
if (userId in idCache) return true
|
||||
if (userId in processedCache) return false
|
||||
|
||||
// Check if this user is from our server
|
||||
val user = db.userData.findByCard_ExtId(userId)()
|
||||
if (user == null) {
|
||||
// User is from another server, check if they have been checked in
|
||||
if (db.matchingMember.existsByUserIdAndUserName(userId, userName)) {
|
||||
// Check in
|
||||
db.matchingMember.save(this)
|
||||
log.info("[Matching] User $userId ($userName) not found, checking in.")
|
||||
}
|
||||
processedCache.add(userId)
|
||||
}
|
||||
else {
|
||||
// Is from our server, obfuscate the user ID to enhance security
|
||||
val randomId = (0..Int.MAX_VALUE).random().toLong()
|
||||
idCache[randomId] = userId
|
||||
userId = randomId
|
||||
log.info("[Matching] User $userId ($userName) is from our server, obfuscated to $randomId.")
|
||||
}
|
||||
return user != null
|
||||
}
|
||||
|
||||
"BeginMatching" {
|
||||
val member = parsing { mapper.convert<Chu3MatchingMemberReq>(data["matchingMemberInfo"] as JDict) }
|
||||
member.checkFromAquaDX()
|
||||
|
||||
// Forward BeginMatching to external server
|
||||
// val res =
|
||||
}
|
||||
|
||||
TODO("The external matching API is not implemented yet.")
|
||||
}
|
|
@ -0,0 +1,162 @@
|
|||
package icu.samnyan.aqua.sega.chusan.handler
|
||||
|
||||
import ext.*
|
||||
import icu.samnyan.aqua.sega.chusan.ChusanController
|
||||
import icu.samnyan.aqua.sega.chusan.model.request.UpsertUserAll
|
||||
import icu.samnyan.aqua.sega.chusan.model.userdata.*
|
||||
import icu.samnyan.aqua.sega.general.model.response.UserRecentRating
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun ChusanController.upsertApiInit() {
|
||||
"UpsertUserChargelog" {
|
||||
val charge = parsing { mapper.convert<UserCharge>(data["userCharge"] as JDict) }
|
||||
charge.user = db.userData.findByCard_ExtId(uid)() ?: (400 - "User not found")
|
||||
charge.id = db.userCharge.findByUser_Card_ExtIdAndChargeId(uid, charge.chargeId)?.id ?: 0
|
||||
db.userCharge.save(charge)
|
||||
"""{"returnCode":"1"}"""
|
||||
}
|
||||
|
||||
"UpsertUserAll" api@ {
|
||||
val req = mapper.convert(data["upsertUserAll"], UpsertUserAll::class.java)
|
||||
|
||||
req.run {
|
||||
// UserData
|
||||
val oldUser = db.userData.findByCard_ExtId(uid)()
|
||||
val u = (userData?.get(0) ?: return@api null).apply {
|
||||
id = oldUser?.id ?: 0
|
||||
card = oldUser?.card ?: us.cardRepo.findByExtId(uid).expect("Card not found")
|
||||
userName = userName.fromChusanUsername()
|
||||
userNameEx = ""
|
||||
}.also { db.userData.saveAndFlush(it) }
|
||||
|
||||
versionHelper[u.lastClientId] = u.lastDataVersion
|
||||
|
||||
// Set users
|
||||
listOfNotNull(
|
||||
userPlaylogList, userGameOption, userMapAreaList, userCharacterList, userItemList,
|
||||
userMusicDetailList, userActivityList, userChargeList, userCourseList, userDuelList,
|
||||
userNetBattlelogList
|
||||
).flatten().forEach { it.user = u }
|
||||
|
||||
// Ratings
|
||||
fun Iterable<UserRecentRating>.str() = joinToString(",") { "${it.musicId}:${it.difficultId}:${it.score}" }
|
||||
|
||||
ls(
|
||||
userRecentRatingList to "recent_rating_list", userRatingBaseList to "rating_base_list",
|
||||
userRatingBaseHotList to "rating_hot_list", userRatingBaseNextList to "rating_next_list",
|
||||
).filter { it.first != null }.forEach { (list, key) ->
|
||||
val d = db.userGeneralData.findByUserAndPropertyKey(u, key)()
|
||||
?: UserGeneralData().apply { user = u; propertyKey = key }
|
||||
db.userGeneralData.save(d.apply { propertyValue = list!!.str() })
|
||||
}
|
||||
|
||||
val misc = db.userMisc.findSingleByUser(u)() ?: Chu3UserMisc().apply { user = u }
|
||||
|
||||
// Favorites
|
||||
userFavoriteMusicList?.filter { it.musicId != -1 }?.ifEmpty { null }?.let { list ->
|
||||
misc.favMusic = list.map { it.musicId }.mut
|
||||
}
|
||||
|
||||
// Net battle data
|
||||
userNetBattleData?.getOrNull(0)?.let {
|
||||
misc.recentNbSelect = it.recentNBSelectMusicList.map { it.musicId }.mut
|
||||
}
|
||||
|
||||
// Add the battle log songs to misc
|
||||
if (userNetBattlelogList != null) {
|
||||
val music = userMusicDetailList?.map { it.musicId } ?: emptyList()
|
||||
misc.recentNbMusic = (misc.recentNbMusic + music).distinct().takeLast(10).mut
|
||||
}
|
||||
db.userMisc.save(misc)
|
||||
|
||||
// Playlog
|
||||
userPlaylogList?.let { db.userPlaylog.saveAll(it) }
|
||||
userNetBattlelogList?.let { db.netBattleLog.saveAll(it.mapApplyI { i ->
|
||||
userPlaylogList?.getOrNull(i)?.let {
|
||||
musicId = it.musicId
|
||||
difficultyId = it.level
|
||||
score = it.score
|
||||
}
|
||||
|
||||
selectUserName = selectUserName.fromChusanUsername()
|
||||
opponentUserName1 = opponentUserName1.fromChusanUsername()
|
||||
opponentUserName2 = opponentUserName2.fromChusanUsername()
|
||||
opponentUserName3 = opponentUserName3.fromChusanUsername()
|
||||
}) }
|
||||
|
||||
// List data
|
||||
userGameOption?.get(0)?.let { obj ->
|
||||
db.userGameOption.saveAndFlush(obj.apply {
|
||||
id = db.userGameOption.findSingleByUser(u)()?.id ?: 0 }) }
|
||||
|
||||
userMapAreaList?.let { list ->
|
||||
db.userMap.saveAll(list.distinctBy { it.mapAreaId }.mapApply {
|
||||
id = db.userMap.findByUserAndMapAreaId(u, mapAreaId)?.id ?: 0 }) }
|
||||
|
||||
userCharacterList?.let { list ->
|
||||
db.userCharacter.saveAll(list.distinctBy { it.characterId }.mapApply {
|
||||
id = db.userCharacter.findByUserAndCharacterId(u, characterId)?.id ?: 0 }) }
|
||||
|
||||
userItemList?.let { list ->
|
||||
db.userItem.saveAll(list.distinctBy { it.itemId to it.itemKind }.mapApply {
|
||||
id = db.userItem.findByUserAndItemIdAndItemKind(u, itemId, itemKind)?.id ?: 0 }) }
|
||||
|
||||
userMusicDetailList?.let { list ->
|
||||
db.userMusicDetail.saveAll(list.distinctBy { it.musicId to it.level }.mapApply {
|
||||
id = db.userMusicDetail.findByUserAndMusicIdAndLevel(u, musicId, level)?.id ?: 0 }) }
|
||||
|
||||
userActivityList?.let { list ->
|
||||
db.userActivity.saveAll(list.distinctBy { it.activityId to it.kind }.mapApply {
|
||||
id = db.userActivity.findByUserAndActivityIdAndKind(u, activityId, kind)?.id ?: 0 }) }
|
||||
|
||||
userChargeList?.let { list ->
|
||||
db.userCharge.saveAll(list.distinctBy { it.chargeId }.mapApply {
|
||||
id = db.userCharge.findByUserAndChargeId(u, chargeId)()?.id ?: 0 }) }
|
||||
|
||||
userCourseList?.let { list ->
|
||||
db.userCourse.saveAll(list.distinctBy { it.courseId }.mapApply {
|
||||
id = db.userCourse.findByUserAndCourseId(u, courseId)?.id ?: 0 }) }
|
||||
|
||||
userDuelList?.let { list ->
|
||||
db.userDuel.saveAll(list.distinctBy { it.duelId }.mapApply {
|
||||
id = db.userDuel.findByUserAndDuelId(u, duelId)?.id ?: 0 }) }
|
||||
|
||||
// Need testing
|
||||
// userLoginBonusList?.let { list ->
|
||||
// db.userLoginBonus.saveAll(list.distinctBy { it["presetId"] as String }.map {
|
||||
// val id = it["presetId"]!!.int
|
||||
// (db.userLoginBonus.findLoginBonus(uid.int, 1, id)() ?: UserLoginBonus()).apply {
|
||||
// user = u.id.toInt()
|
||||
// presetId = id
|
||||
// lastUpdateDate = LocalDateTime.now()
|
||||
// isWatched = true
|
||||
// }
|
||||
// })
|
||||
// }
|
||||
|
||||
req.userCMissionList?.forEach { d ->
|
||||
(db.userCMission.findByUser_Card_ExtIdAndMissionId(uid, d.missionId)()
|
||||
?: UserCMission().apply {
|
||||
missionId = d.missionId
|
||||
user = u
|
||||
}
|
||||
).apply { point = d.point }.also { db.userCMission.save(it) }
|
||||
|
||||
d.userCMissionProgressList?.forEach inner@ { p ->
|
||||
(db.userCMissionProgress.findByUser_Card_ExtIdAndMissionIdAndOrder(uid, d.missionId, p.order)()
|
||||
?: UserCMissionProgress().apply {
|
||||
missionId = d.missionId
|
||||
order = p.order
|
||||
user = u
|
||||
}
|
||||
).apply {
|
||||
progress = p.progress
|
||||
stage = p.stage
|
||||
}.also { db.userCMissionProgress.save(it) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
"""{"returnCode":1}"""
|
||||
}
|
||||
}
|
|
@ -1,81 +0,0 @@
|
|||
package icu.samnyan.aqua.sega.chusan.handler
|
||||
|
||||
import ext.int
|
||||
import ext.invoke
|
||||
import ext.long
|
||||
import icu.samnyan.aqua.sega.chusan.ChusanProps
|
||||
import icu.samnyan.aqua.sega.chusan.model.Chu3Repos
|
||||
import icu.samnyan.aqua.sega.chusan.model.userdata.UserItem
|
||||
import icu.samnyan.aqua.sega.chusan.model.userdata.UserLoginBonus
|
||||
import icu.samnyan.aqua.sega.general.BaseHandler
|
||||
import lombok.AllArgsConstructor
|
||||
import org.springframework.stereotype.Component
|
||||
import java.time.LocalDateTime
|
||||
import java.time.ZoneOffset
|
||||
|
||||
/**
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
@Component("ChusanGameLoginHandler")
|
||||
class GameLoginHandler(
|
||||
val props: ChusanProps,
|
||||
val db: Chu3Repos
|
||||
) : BaseHandler {
|
||||
|
||||
override fun handle(request: Map<String, Any>): Any? {
|
||||
val uid = request["userId"]!!.long
|
||||
fun process() {
|
||||
val u = db.userData.findByCard_ExtId(uid)() ?: return
|
||||
db.userData.save(u.apply { lastLoginDate = LocalDateTime.now() })
|
||||
|
||||
if (!props.loginBonusEnable) return
|
||||
val bonusList = db.gameLoginBonusPresets.findLoginBonusPresets(1, 1)
|
||||
|
||||
bonusList.forEach { preset ->
|
||||
// Check if a user already has some progress and if not, add the login bonus entry
|
||||
val bonus = db.userLoginBonus.findLoginBonus(uid.int, 1, preset.id)()
|
||||
?: UserLoginBonus(1, uid.int, preset.id).let { db.userLoginBonus.save(it) }
|
||||
if (bonus.isFinished) return@forEach
|
||||
|
||||
// last login is 24 hours+ ago
|
||||
if (bonus.lastUpdateDate.toEpochSecond(ZoneOffset.ofHours(0)) <
|
||||
(LocalDateTime.now().minusHours(24).toEpochSecond(ZoneOffset.ofHours(0)))
|
||||
) {
|
||||
var bCount = bonus.bonusCount + 1
|
||||
val lastUpdate = LocalDateTime.now()
|
||||
val allLoginBonus = db.gameLoginBonus.findGameLoginBonus(1, preset.id)
|
||||
.ifEmpty { return@forEach }
|
||||
val maxNeededDays = allLoginBonus[0].needLoginDayCount
|
||||
|
||||
// if all items are redeemed, then don't show the login bonuses.
|
||||
var finished = false
|
||||
if (bCount > maxNeededDays) {
|
||||
if (preset.id < 3000) bCount = 1
|
||||
else finished = true
|
||||
}
|
||||
db.gameLoginBonus.findByRequiredDays(1, preset.id, bCount)()?.let {
|
||||
db.userItem.save(UserItem(u).apply {
|
||||
itemId = it.presentId
|
||||
itemKind = 6
|
||||
stock = it.itemNum
|
||||
isValid = true
|
||||
})
|
||||
}
|
||||
val toSave = db.userLoginBonus.findLoginBonus(uid.int, 1, preset.id)()
|
||||
?: UserLoginBonus().apply { user = uid.int; presetId = preset.id; version = 1 }
|
||||
|
||||
db.userLoginBonus.save(toSave.apply {
|
||||
bonusCount = bCount
|
||||
lastUpdateDate = lastUpdate
|
||||
isWatched = false
|
||||
isFinished = finished
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
process()
|
||||
|
||||
return """{"returnCode":"1"}"""
|
||||
}
|
||||
}
|
|
@ -1,153 +0,0 @@
|
|||
package icu.samnyan.aqua.sega.chusan.handler
|
||||
|
||||
import ext.*
|
||||
import icu.samnyan.aqua.sega.chusan.ChusanVersionHelper
|
||||
import icu.samnyan.aqua.sega.chusan.model.Chu3Repos
|
||||
import icu.samnyan.aqua.sega.chusan.model.request.UpsertUserAll
|
||||
import icu.samnyan.aqua.sega.chusan.model.userdata.UserCMission
|
||||
import icu.samnyan.aqua.sega.chusan.model.userdata.UserCMissionProgress
|
||||
import icu.samnyan.aqua.sega.chusan.model.userdata.UserGeneralData
|
||||
import icu.samnyan.aqua.sega.chusan.model.userdata.UserLoginBonus
|
||||
import icu.samnyan.aqua.sega.general.BaseHandler
|
||||
import icu.samnyan.aqua.sega.general.dao.CardRepository
|
||||
import icu.samnyan.aqua.sega.general.model.response.UserRecentRating
|
||||
import icu.samnyan.aqua.sega.util.jackson.StringMapper
|
||||
import lombok.AllArgsConstructor
|
||||
import org.springframework.stereotype.Component
|
||||
import java.nio.charset.StandardCharsets
|
||||
import java.time.LocalDateTime
|
||||
|
||||
/**
|
||||
* The handler for save user data. Only send in the end of the session.
|
||||
*
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
@Component("ChusanUpsertUserAllHandler")
|
||||
class UpsertUserAllHandler(
|
||||
val mapper: StringMapper,
|
||||
val rp: Chu3Repos,
|
||||
val cardRepo: CardRepository,
|
||||
val versionHelper: ChusanVersionHelper,
|
||||
) : BaseHandler {
|
||||
val logger = logger()
|
||||
|
||||
override fun handle(request: Map<String, Any>): Any? {
|
||||
val ext = request["userId"]?.long ?: return null
|
||||
val req = mapper.convert(request["upsertUserAll"], UpsertUserAll::class.java)
|
||||
|
||||
req.run {
|
||||
// UserData
|
||||
val oldUser = rp.userData.findByCard_ExtId(ext)()
|
||||
val u = (userData?.get(0) ?: return null).apply {
|
||||
id = oldUser?.id ?: 0
|
||||
card = oldUser?.card ?: cardRepo.findByExtId(ext).expect("Card not found")
|
||||
userName = String(userName.toByteArray(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8)
|
||||
userNameEx = ""
|
||||
}.also { rp.userData.saveAndFlush(it) }
|
||||
|
||||
versionHelper[u.lastClientId] = u.lastDataVersion
|
||||
|
||||
// Set users
|
||||
listOfNotNull(
|
||||
userPlaylogList, userGameOption, userMapAreaList, userCharacterList, userItemList,
|
||||
userMusicDetailList, userActivityList, userChargeList, userCourseList, userDuelList,
|
||||
).flatten().forEach { it.user = u }
|
||||
|
||||
// Ratings
|
||||
fun Iterable<UserRecentRating>.str() = joinToString(",") { "${it.musicId}:${it.difficultId}:${it.score}" }
|
||||
|
||||
ls(
|
||||
userRecentRatingList to "recent_rating_list", userRatingBaseList to "rating_base_list",
|
||||
userRatingBaseHotList to "rating_hot_list", userRatingBaseNextList to "rating_next_list",
|
||||
).filter { it.first != null }.forEach { (list, key) ->
|
||||
val d = rp.userGeneralData.findByUserAndPropertyKey(u, key)()
|
||||
?: UserGeneralData().apply { user = u; propertyKey = key }
|
||||
rp.userGeneralData.save(d.apply { propertyValue = list!!.str() })
|
||||
}
|
||||
|
||||
userFavoriteMusicList?.let { list ->
|
||||
val d = rp.userGeneralData.findByUserAndPropertyKey(u, "favorite_music")()
|
||||
?: UserGeneralData().apply { user = u; propertyKey = "favorite_music" }
|
||||
rp.userGeneralData.save(d.apply { propertyValue = list.joinToString(",") { it.musicId.toString() } })
|
||||
}
|
||||
|
||||
// Playlog
|
||||
userPlaylogList?.let { rp.userPlaylog.saveAll(it) }
|
||||
|
||||
// List data
|
||||
userGameOption?.get(0)?.let { obj ->
|
||||
rp.userGameOption.saveAndFlush(obj.apply {
|
||||
id = rp.userGameOption.findSingleByUser(u)()?.id ?: 0 }) }
|
||||
|
||||
userMapAreaList?.let { list ->
|
||||
rp.userMap.saveAll(list.distinctBy { it.mapAreaId }.mapApply {
|
||||
id = rp.userMap.findByUserAndMapAreaId(u, mapAreaId)?.id ?: 0 }) }
|
||||
|
||||
userCharacterList?.let { list ->
|
||||
rp.userCharacter.saveAll(list.distinctBy { it.characterId }.mapApply {
|
||||
id = rp.userCharacter.findByUserAndCharacterId(u, characterId)?.id ?: 0 }) }
|
||||
|
||||
userItemList?.let { list ->
|
||||
rp.userItem.saveAll(list.distinctBy { it.itemId to it.itemKind }.mapApply {
|
||||
id = rp.userItem.findByUserAndItemIdAndItemKind(u, itemId, itemKind)?.id ?: 0 }) }
|
||||
|
||||
userMusicDetailList?.let { list ->
|
||||
rp.userMusicDetail.saveAll(list.distinctBy { it.musicId to it.level }.mapApply {
|
||||
id = rp.userMusicDetail.findByUserAndMusicIdAndLevel(u, musicId, level)?.id ?: 0 }) }
|
||||
|
||||
userActivityList?.let { list ->
|
||||
rp.userActivity.saveAll(list.distinctBy { it.activityId to it.kind }.mapApply {
|
||||
id = rp.userActivity.findByUserAndActivityIdAndKind(u, activityId, kind)?.id ?: 0 }) }
|
||||
|
||||
userChargeList?.let { list ->
|
||||
rp.userCharge.saveAll(list.distinctBy { it.chargeId }.mapApply {
|
||||
id = rp.userCharge.findByUserAndChargeId(u, chargeId)()?.id ?: 0 }) }
|
||||
|
||||
userCourseList?.let { list ->
|
||||
rp.userCourse.saveAll(list.distinctBy { it.courseId }.mapApply {
|
||||
id = rp.userCourse.findByUserAndCourseId(u, courseId)?.id ?: 0 }) }
|
||||
|
||||
userDuelList?.let { list ->
|
||||
rp.userDuel.saveAll(list.distinctBy { it.duelId }.mapApply {
|
||||
id = rp.userDuel.findByUserAndDuelId(u, duelId)?.id ?: 0 }) }
|
||||
|
||||
// Need testing
|
||||
userLoginBonusList?.let { list ->
|
||||
rp.userLoginBonus.saveAll(list.distinctBy { it["presetId"] as String }.map {
|
||||
val id = it["presetId"]!!.int
|
||||
(rp.userLoginBonus.findLoginBonus(ext.int, 1, id)() ?: UserLoginBonus()).apply {
|
||||
user = u.id.toInt()
|
||||
presetId = id
|
||||
lastUpdateDate = LocalDateTime.now()
|
||||
isWatched = true
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
req.userCMissionList?.forEach { d ->
|
||||
(rp.userCMission.findByUser_Card_ExtIdAndMissionId(ext, d.missionId)()
|
||||
?: UserCMission().apply {
|
||||
missionId = d.missionId
|
||||
user = u
|
||||
}
|
||||
).apply { point = d.point }.also { rp.userCMission.save(it) }
|
||||
|
||||
d.userCMissionProgressList?.forEach inner@ { p ->
|
||||
(rp.userCMissionProgress.findByUser_Card_ExtIdAndMissionIdAndOrder(ext, d.missionId, p.order)()
|
||||
?: UserCMissionProgress().apply {
|
||||
missionId = d.missionId
|
||||
order = p.order
|
||||
user = u
|
||||
}
|
||||
).apply {
|
||||
progress = p.progress
|
||||
stage = p.stage
|
||||
}.also { rp.userCMissionProgress.save(it) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return """{"returnCode":1}"""
|
||||
}
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
package icu.samnyan.aqua.sega.chusan.model
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore
|
||||
import com.fasterxml.jackson.annotation.JsonProperty
|
||||
import icu.samnyan.aqua.net.games.BaseEntity
|
||||
import jakarta.persistence.*
|
||||
import java.time.LocalDateTime
|
||||
|
||||
|
||||
// BaseEntity does not expose id to json, but IdExposedEntity does
|
||||
@MappedSuperclass
|
||||
class IdExposedEntity {
|
||||
@Id
|
||||
var id: Long = 0
|
||||
}
|
||||
|
||||
@Entity(name = "ChusanGameCharge")
|
||||
@Table(name = "chusan_game_charge")
|
||||
class GameCharge: BaseEntity() {
|
||||
var orderId = 0
|
||||
|
||||
@Column(unique = true)
|
||||
var chargeId = 0
|
||||
var price = 0
|
||||
var startDate: LocalDateTime? = null
|
||||
var endDate: LocalDateTime? = null
|
||||
var salePrice = 0
|
||||
var saleStartDate: LocalDateTime? = null
|
||||
var saleEndDate: LocalDateTime? = null
|
||||
}
|
||||
|
||||
@Entity(name = "ChusanGameEvent")
|
||||
@Table(name = "chusan_game_event")
|
||||
class GameEvent: IdExposedEntity() {
|
||||
val type = 0
|
||||
val startDate: LocalDateTime? = null
|
||||
val endDate: LocalDateTime? = null
|
||||
|
||||
@JsonIgnore
|
||||
val enable = false
|
||||
}
|
||||
|
||||
@Entity(name = "ChusanGameGacha")
|
||||
@Table(name = "chusan_game_gacha")
|
||||
class GameGacha : IdExposedEntity() {
|
||||
var gachaId = 0
|
||||
var gachaName: String? = null
|
||||
var type = 0
|
||||
var kind = 0
|
||||
|
||||
@JsonProperty("isCeiling")
|
||||
var isCeiling = false
|
||||
var ceilingCnt = 0
|
||||
var changeRateCnt1 = 0
|
||||
var changeRateCnt2 = 0
|
||||
var startDate: LocalDateTime? = null
|
||||
var endDate: LocalDateTime? = null
|
||||
var noticeStartDate: LocalDateTime? = null
|
||||
var noticeEndDate: LocalDateTime? = null
|
||||
}
|
||||
|
||||
@Entity(name = "ChusanGameGachaCard")
|
||||
@Table(name = "chusan_game_gacha_card")
|
||||
class GameGachaCard : IdExposedEntity() {
|
||||
var gachaId = 0
|
||||
var cardId = 0
|
||||
var rarity = 0
|
||||
var weight = 0
|
||||
|
||||
@JsonProperty("isPickup")
|
||||
var isPickup = false
|
||||
}
|
||||
|
||||
@Entity(name = "ChusanGameLoginBonus")
|
||||
@Table(name = "chusan_game_login_bonus")
|
||||
class GameLoginBonus : IdExposedEntity() {
|
||||
var version = 0
|
||||
var presetId = 0
|
||||
var loginBonusId = 0
|
||||
var loginBonusName: String? = null
|
||||
var presentId = 0
|
||||
var presentName: String? = null
|
||||
var itemNum = 0
|
||||
var needLoginDayCount = 0
|
||||
var loginBonusCategoryType = 0
|
||||
}
|
||||
|
||||
@Entity(name = "ChusanGameLoginBonusPreset")
|
||||
@Table(name = "chusan_game_login_bonus_preset")
|
||||
class GameLoginBonusPreset : IdExposedEntity() {
|
||||
var version = 0
|
||||
var presetName: String? = null
|
||||
var isEnabled = false
|
||||
}
|
|
@ -5,7 +5,6 @@ package icu.samnyan.aqua.sega.chusan.model
|
|||
import icu.samnyan.aqua.net.games.GenericPlaylogRepo
|
||||
import icu.samnyan.aqua.net.games.GenericUserDataRepo
|
||||
import icu.samnyan.aqua.net.games.IUserRepo
|
||||
import icu.samnyan.aqua.sega.chusan.model.gamedata.*
|
||||
import icu.samnyan.aqua.sega.chusan.model.userdata.*
|
||||
import org.springframework.data.domain.Page
|
||||
import org.springframework.data.domain.Pageable
|
||||
|
@ -37,7 +36,7 @@ interface Chu3UserLoginBonusRepo : JpaRepository<UserLoginBonus, Long> {
|
|||
value = "select * from chusan_user_login_bonus where user = ?1 and version = ?2 and preset_id = ?3 limit 1",
|
||||
nativeQuery = true
|
||||
)
|
||||
fun findLoginBonus(userId: Int, version: Int, presetId: Int): Optional<UserLoginBonus>
|
||||
fun findLoginBonus(userId: Int, version: Int, presetId: Long): Optional<UserLoginBonus>
|
||||
}
|
||||
|
||||
interface Chu3UserActivityRepo : Chu3UserLinked<UserActivity> {
|
||||
|
@ -128,13 +127,11 @@ interface Chu3UserCMissionProgressRepo : Chu3UserLinked<UserCMissionProgress> {
|
|||
fun findByUser_Card_ExtIdAndMissionIdAndOrder(extId: Long, missionId: Int, order: Int): Optional<UserCMissionProgress>
|
||||
}
|
||||
|
||||
interface Chu3MatchingMemberRepo : JpaRepository<Chu3MatchingMember, Long> {
|
||||
fun existsByUserIdAndUserName(userId: Long, userName: String): Boolean
|
||||
interface Chu3NetBattleLogRepo : Chu3UserLinked<Chu3NetBattleLog> {
|
||||
fun findTop20ByUserOrderByIdDesc(user: Chu3UserData): List<Chu3NetBattleLog>
|
||||
}
|
||||
|
||||
interface Chu3GameAvatarAccRepo : JpaRepository<AvatarAcc, Long>
|
||||
|
||||
interface Chu3GameCharacterRepo : JpaRepository<Character, Long>
|
||||
interface Chu3UserMiscRepo : Chu3UserLinked<Chu3UserMisc>
|
||||
|
||||
interface Chu3GameChargeRepo : JpaRepository<GameCharge, Long>
|
||||
|
||||
|
@ -142,15 +139,13 @@ interface Chu3GameEventRepo : JpaRepository<GameEvent, Int> {
|
|||
fun findByEnable(enable: Boolean): List<GameEvent>
|
||||
}
|
||||
|
||||
interface Chu3GameFrameRepo : JpaRepository<Frame, Long>
|
||||
|
||||
interface Chu3GameGachaCardRepo : JpaRepository<GameGachaCard, Long> {
|
||||
fun findAllByGachaId(gachaId: Int): List<GameGachaCard>
|
||||
}
|
||||
|
||||
interface Chu3GameGachaRepo : JpaRepository<GameGacha, Long>
|
||||
|
||||
interface Chu3GameLoginBonusPresetsRepo : JpaRepository<GameLoginBonusPreset, Int> {
|
||||
interface Chu3GameLoginBonusPresetsRepo : JpaRepository<GameLoginBonusPreset, Long> {
|
||||
@Query(
|
||||
value = "select * from chusan_game_login_bonus_preset where version = ?1 and is_enabled = ?2",
|
||||
nativeQuery = true
|
||||
|
@ -172,18 +167,6 @@ interface Chu3GameLoginBonusRepo : JpaRepository<GameLoginBonus, Int> {
|
|||
fun findByRequiredDays(version: Int, presetId: Int, requiredDays: Int): Optional<GameLoginBonus>
|
||||
}
|
||||
|
||||
interface Chu3GameMapIconRepo : JpaRepository<MapIcon, Long>
|
||||
|
||||
interface Chu3GameMusicRepo : JpaRepository<Music, Long> {
|
||||
fun findByMusicId(musicId: Int): Optional<Music>
|
||||
}
|
||||
|
||||
interface Chu3GameNamePlateRepo : JpaRepository<NamePlate, Long>
|
||||
|
||||
interface Chu3GameSystemVoiceRepo : JpaRepository<SystemVoice, Long>
|
||||
|
||||
interface Chu3GameTrophyRepo : JpaRepository<Trophy, Long>
|
||||
|
||||
@Component
|
||||
class Chu3Repos(
|
||||
val userLoginBonus: Chu3UserLoginBonusRepo,
|
||||
|
@ -203,19 +186,12 @@ class Chu3Repos(
|
|||
val userPlaylog: Chu3UserPlaylogRepo,
|
||||
val userCMission: Chu3UserCMissionRepo,
|
||||
val userCMissionProgress: Chu3UserCMissionProgressRepo,
|
||||
val matchingMember: Chu3MatchingMemberRepo,
|
||||
val gameAvatarAcc: Chu3GameAvatarAccRepo,
|
||||
val gameCharacter: Chu3GameCharacterRepo,
|
||||
val netBattleLog: Chu3NetBattleLogRepo,
|
||||
val userMisc: Chu3UserMiscRepo,
|
||||
val gameCharge: Chu3GameChargeRepo,
|
||||
val gameEvent: Chu3GameEventRepo,
|
||||
val gameFrame: Chu3GameFrameRepo,
|
||||
val gameGachaCard: Chu3GameGachaCardRepo,
|
||||
val gameGacha: Chu3GameGachaRepo,
|
||||
val gameLoginBonusPresets: Chu3GameLoginBonusPresetsRepo,
|
||||
val gameLoginBonus: Chu3GameLoginBonusRepo,
|
||||
val gameMapIcon: Chu3GameMapIconRepo,
|
||||
val gameMusic: Chu3GameMusicRepo,
|
||||
val gameNamePlate: Chu3GameNamePlateRepo,
|
||||
val gameSystemVoice: Chu3GameSystemVoiceRepo,
|
||||
val gameTrophy: Chu3GameTrophyRepo
|
||||
val gameLoginBonus: Chu3GameLoginBonusRepo
|
||||
)
|
|
@ -1,30 +0,0 @@
|
|||
package icu.samnyan.aqua.sega.chusan.model.gamedata;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Table;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@Entity(name = "AvatarAcc")
|
||||
@Table(name = "chusan_avatar")
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class AvatarAcc implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Id
|
||||
private long id;
|
||||
|
||||
private String name;
|
||||
|
||||
private int category;
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
package icu.samnyan.aqua.sega.chusan.model.gamedata;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Table;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@Entity(name = "ChusanCharacter")
|
||||
@Table(name = "chusan_game_character")
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class Character implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Id
|
||||
private long id;
|
||||
|
||||
private String name;
|
||||
|
||||
private String releaseTag;
|
||||
|
||||
private String worksName;
|
||||
|
||||
private String illustratorName;
|
||||
|
||||
private String addImages;
|
||||
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
package icu.samnyan.aqua.sega.chusan.model.gamedata;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Table;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@Entity(name = "ChusanFrame")
|
||||
@Table(name = "chusan_frame")
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class Frame implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Id
|
||||
private long id;
|
||||
|
||||
private String name;
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
package icu.samnyan.aqua.sega.chusan.model.gamedata;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import jakarta.persistence.*;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@Entity(name = "ChusanGameCharge")
|
||||
@Table(name = "chusan_game_charge")
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class GameCharge implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@JsonIgnore
|
||||
private long id;
|
||||
|
||||
private int orderId;
|
||||
|
||||
@Column(unique = true)
|
||||
private int chargeId;
|
||||
|
||||
private int price;
|
||||
|
||||
private LocalDateTime startDate;
|
||||
|
||||
private LocalDateTime endDate;
|
||||
|
||||
private int salePrice;
|
||||
|
||||
private LocalDateTime saleStartDate;
|
||||
|
||||
private LocalDateTime saleEndDate;
|
||||
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
package icu.samnyan.aqua.sega.chusan.model.gamedata;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Table;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@Entity(name = "ChusanGameEvent")
|
||||
@Table(name = "chusan_game_event")
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class GameEvent implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Id
|
||||
private int id;
|
||||
|
||||
private int type;
|
||||
|
||||
private LocalDateTime startDate;
|
||||
|
||||
private LocalDateTime endDate;
|
||||
|
||||
@JsonIgnore
|
||||
private boolean enable;
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
package icu.samnyan.aqua.sega.chusan.model.gamedata;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import jakarta.persistence.*;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@Entity(name = "ChusanGameGacha")
|
||||
@Table(name = "chusan_game_gacha")
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class GameGacha implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@JsonIgnore
|
||||
private int id;
|
||||
private int gachaId;
|
||||
private String gachaName;
|
||||
private int type;
|
||||
private int kind; // 0
|
||||
@JsonProperty("isCeiling")
|
||||
private boolean isCeiling;
|
||||
private int ceilingCnt;
|
||||
private int changeRateCnt1;
|
||||
private int changeRateCnt2;
|
||||
private LocalDateTime startDate;
|
||||
private LocalDateTime endDate;
|
||||
private LocalDateTime noticeStartDate;
|
||||
private LocalDateTime noticeEndDate;
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
package icu.samnyan.aqua.sega.chusan.model.gamedata;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import jakarta.persistence.*;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@Entity(name = "ChusanGameGachaCard")
|
||||
@Table(name = "chusan_game_gacha_card")
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class GameGachaCard implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@JsonIgnore
|
||||
private int id;
|
||||
private int gachaId;
|
||||
private int cardId;
|
||||
private int rarity;
|
||||
private int weight;
|
||||
@JsonProperty("isPickup")
|
||||
private boolean isPickup;
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
package icu.samnyan.aqua.sega.chusan.model.gamedata;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import jakarta.persistence.*;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Entity(name = "ChusanGameLoginBonus")
|
||||
@Table(name = "chusan_game_login_bonus")
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class GameLoginBonus implements Serializable {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@JsonIgnore
|
||||
private int id;
|
||||
private int version;
|
||||
private int presetId;
|
||||
private int loginBonusId;
|
||||
private String loginBonusName;
|
||||
private int presentId;
|
||||
private String presentName;
|
||||
private int itemNum;
|
||||
private int needLoginDayCount;
|
||||
private int loginBonusCategoryType;
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
package icu.samnyan.aqua.sega.chusan.model.gamedata;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import jakarta.persistence.*;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Entity(name = "ChusanGameLoginBonusPreset")
|
||||
@Table(name = "chusan_game_login_bonus_preset")
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class GameLoginBonusPreset implements Serializable {
|
||||
// No one cares about chuni lol
|
||||
// Maimai and Ongeki all got their login bonus but nothing for chunithm
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@JsonIgnore
|
||||
private int id;
|
||||
private int version;
|
||||
private String presetName;
|
||||
private boolean isEnabled;
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
package icu.samnyan.aqua.sega.chusan.model.gamedata;
|
||||
|
||||
/**
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
public enum Genre {
|
||||
POPS_ANIME("POPS & ANIME"),
|
||||
GAME("GAME"),
|
||||
NICONICO("niconico"),
|
||||
TOUHOU("東方Project"),
|
||||
RESERVE2("Reserve2"),
|
||||
ORIGINAL("Original"),
|
||||
VARIETY("Variety"),
|
||||
IRODORI("イロドリミドリ"),
|
||||
KOTONOHA("言ノ葉Project"),
|
||||
GEKICHUMA("ゲキマイ");
|
||||
|
||||
private String displayName;
|
||||
|
||||
Genre(String displayName) {
|
||||
this.displayName = displayName;
|
||||
}
|
||||
|
||||
public String displayName() {
|
||||
return displayName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return displayName;
|
||||
}
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
package icu.samnyan.aqua.sega.chusan.model.gamedata;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import jakarta.persistence.*;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@Entity(name = "ChusanMusicLevel")
|
||||
@Table(name = "chusan_music_level")
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class Level implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
@JsonIgnore
|
||||
private long id;
|
||||
|
||||
@JsonIgnore
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "music_id")
|
||||
private Music music;
|
||||
|
||||
private boolean enable;
|
||||
|
||||
private int level;
|
||||
|
||||
private int levelDecimal;
|
||||
|
||||
private int diff;
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
package icu.samnyan.aqua.sega.chusan.model.gamedata;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Table;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@Entity(name = "ChusanMapIcon")
|
||||
@Table(name = "chusan_mapicon")
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class MapIcon implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Id
|
||||
private long id;
|
||||
|
||||
private String name;
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
package icu.samnyan.aqua.sega.chusan.model.gamedata;
|
||||
|
||||
import jakarta.persistence.*;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@Entity(name = "ChusanMusic")
|
||||
@Table(name = "chusan_music")
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class Music implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Id
|
||||
private int musicId;
|
||||
|
||||
private String name;
|
||||
|
||||
private String sortName;
|
||||
|
||||
private String artistName;
|
||||
|
||||
private Genre genre;
|
||||
|
||||
private String releaseVersion;
|
||||
|
||||
@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "music")
|
||||
@MapKey(name = "diff")
|
||||
private Map<Integer, Level> levels;
|
||||
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
package icu.samnyan.aqua.sega.chusan.model.gamedata;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Table;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@Entity(name = "ChusanNamePlate")
|
||||
@Table(name = "chusan_nameplate")
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class NamePlate implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Id
|
||||
private long id;
|
||||
|
||||
private String name;
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
package icu.samnyan.aqua.sega.chusan.model.gamedata;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Table;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@Entity(name = "ChusanSystemVoice")
|
||||
@Table(name = "chusan_voice")
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class SystemVoice implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Id
|
||||
private long id;
|
||||
|
||||
private String name;
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
package icu.samnyan.aqua.sega.chusan.model.gamedata;
|
||||
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Table;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@Entity(name = "ChusanTrophy")
|
||||
@Table(name = "chusan_trophy")
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class Trophy implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Id
|
||||
private long id;
|
||||
|
||||
private String name;
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package icu.samnyan.aqua.sega.chusan.model.response.data
|
||||
package icu.samnyan.aqua.sega.chusan.model.request
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty
|
||||
import icu.samnyan.aqua.sega.chusan.model.userdata.Chu3MatchingMemberReq
|
|
@ -5,7 +5,6 @@ import icu.samnyan.aqua.sega.chusan.model.userdata.*
|
|||
import icu.samnyan.aqua.sega.general.model.response.UserRecentRating
|
||||
|
||||
class UserCMissionResp {
|
||||
var userId: Long? = 0
|
||||
var missionId = 0
|
||||
var point = 0
|
||||
var userCMissionProgressList: List<UserCMissionProgress>? = null
|
||||
|
@ -16,6 +15,28 @@ class FavNewMusic(
|
|||
var orderId: Int = 0,
|
||||
)
|
||||
|
||||
class UpsertTeamPoint(
|
||||
// userId exists here, but it should not be used
|
||||
// So I will not include it in the data class
|
||||
var teamId: Long = 0,
|
||||
var orderId: Int = 0,
|
||||
var teamPoint: Long = 0,
|
||||
var aggrDate: String = "",
|
||||
)
|
||||
|
||||
data class UpsertNetBattleData(
|
||||
val recentNBSelectMusicList: List<MusicIdWrapper> = emptyList(),
|
||||
val isRankUpChallengeFailed: Boolean = false,
|
||||
val highestBattleRankId: Long = 0,
|
||||
val battleIconId: Long = 0,
|
||||
val battleIconNum: Long = 0,
|
||||
val avatarEffectPoint: Long = 0,
|
||||
)
|
||||
|
||||
data class MusicIdWrapper(
|
||||
val musicId: Int = 0,
|
||||
)
|
||||
|
||||
class UpsertUserAll(
|
||||
var userData: List<Chu3UserData>? = null,
|
||||
var userGameOption: List<UserGameOption>? = null,
|
||||
|
@ -28,16 +49,17 @@ class UpsertUserAll(
|
|||
var userChargeList: List<UserCharge>? = null,
|
||||
var userCourseList: List<UserCourse>? = null,
|
||||
var userDuelList: List<UserDuel>? = null,
|
||||
var userTeamPoint: List<JDict>? = null,
|
||||
// TODO: Actually implement team
|
||||
var userTeamPoint: List<UpsertTeamPoint>? = null,
|
||||
var userRatingBaseHotList: List<UserRecentRating>? = null,
|
||||
var userRatingBaseList: List<UserRecentRating>? = null,
|
||||
var userRatingBaseNextList: List<UserRecentRating>? = null,
|
||||
var userLoginBonusList: List<JDict>? = null,
|
||||
var userMapAreaList: List<UserMap>? = null,
|
||||
var userOverPowerList: List<JDict>? = null,
|
||||
var userNetBattlelogList: List<JDict>? = null,
|
||||
var userNetBattlelogList: List<Chu3NetBattleLog>? = null,
|
||||
var userEmoneyList: List<JDict>? = null,
|
||||
var userNetBattleData: List<JDict>? = null,
|
||||
var userNetBattleData: List<UpsertNetBattleData>? = null,
|
||||
var userCMissionList: List<UserCMissionResp>? = null,
|
||||
var userFavoriteMusicList: List<FavNewMusic>? = null,
|
||||
)
|
||||
|
|
|
@ -1,50 +0,0 @@
|
|||
package icu.samnyan.aqua.sega.chusan.model.request;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import icu.samnyan.aqua.sega.chusan.model.gamedata.GameGachaCard;
|
||||
import icu.samnyan.aqua.sega.chusan.model.userdata.Chu3UserData;
|
||||
import icu.samnyan.aqua.sega.chusan.model.userdata.UserGacha;
|
||||
import icu.samnyan.aqua.sega.chusan.model.userdata.UserItem;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class UpsertUserGacha implements Serializable {
|
||||
|
||||
@Nullable
|
||||
private Chu3UserData userData;
|
||||
|
||||
@Nullable
|
||||
private UserGacha userGacha;
|
||||
|
||||
@Nullable
|
||||
private List<Object> userCharacterList;
|
||||
|
||||
@Nullable
|
||||
private List<Object> userCardList;
|
||||
|
||||
@Nullable
|
||||
private List<GameGachaCard> gameGachaCardList;
|
||||
|
||||
@Nullable
|
||||
private List<UserItem> userItemList;
|
||||
|
||||
@Nullable
|
||||
@JsonProperty("isNewCharacterList")
|
||||
private String isNewCharacterList;
|
||||
|
||||
@Nullable
|
||||
@JsonProperty("isNewCardList")
|
||||
private String isNewCardList;
|
||||
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package icu.samnyan.aqua.sega.chusan.model.request
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty
|
||||
import icu.samnyan.aqua.sega.chusan.model.GameGachaCard
|
||||
import icu.samnyan.aqua.sega.chusan.model.userdata.Chu3UserData
|
||||
import icu.samnyan.aqua.sega.chusan.model.userdata.UserGacha
|
||||
import icu.samnyan.aqua.sega.chusan.model.userdata.UserItem
|
||||
import java.io.Serializable
|
||||
|
||||
class UpsertUserGacha : Serializable {
|
||||
var userData: Chu3UserData? = null
|
||||
var userGacha: UserGacha? = null
|
||||
var userCharacterList: List<Any>? = null
|
||||
var userCardList: List<Any>? = null
|
||||
var gameGachaCardList: List<GameGachaCard>? = null
|
||||
var userItemList: List<UserItem>? = null
|
||||
|
||||
@JsonProperty("isNewCharacterList")
|
||||
var isNewCharacterList: String? = null
|
||||
@JsonProperty("isNewCardList")
|
||||
var isNewCardList: String? = null
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package icu.samnyan.aqua.sega.chusan.model.request
|
||||
|
||||
class UserEmoney(
|
||||
var type: Int = 0,
|
||||
var emoneyCredit: Int = 69,
|
||||
var emoneyBrand: Int = 2,
|
||||
var ext1: Int = 0,
|
||||
var ext2: Int = 0,
|
||||
var ext3: Int = 0
|
||||
)
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
package icu.samnyan.aqua.sega.chusan.model.response.data;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class GameRanking {
|
||||
private int id;
|
||||
private long point;
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
package icu.samnyan.aqua.sega.chusan.model.response.data;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class SymbolChatInfo {
|
||||
|
||||
private int sceneId;
|
||||
private int symbolChatId;
|
||||
private int orderId;
|
||||
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
package icu.samnyan.aqua.sega.chusan.model.response.data;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class UserEmoney {
|
||||
|
||||
private int type = 0;
|
||||
private int emoneyCredit = 69;
|
||||
private int emoneyBrand = 2;
|
||||
private int ext1 = 0;
|
||||
private int ext2 = 0;
|
||||
private int ext3 = 0;
|
||||
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
package icu.samnyan.aqua.sega.chusan.model.response.data;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class UserFavorite {
|
||||
|
||||
private int id;
|
||||
|
||||
}
|
|
@ -1,13 +1,8 @@
|
|||
package icu.samnyan.aqua.sega.chusan.model.userdata
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty
|
||||
import icu.samnyan.aqua.net.games.BaseEntity
|
||||
import jakarta.persistence.Entity
|
||||
import jakarta.persistence.Table
|
||||
|
||||
@Entity(name = "ChusanMatchingMember")
|
||||
@Table(name = "chusan_matching_member")
|
||||
class Chu3MatchingMember : BaseEntity() {
|
||||
open class Chu3MatchingMember {
|
||||
var userId: Long = 0
|
||||
var regionId = 0
|
||||
var placeId = 0
|
||||
|
|
|
@ -0,0 +1,76 @@
|
|||
package icu.samnyan.aqua.sega.chusan.model.userdata
|
||||
|
||||
import jakarta.persistence.Entity
|
||||
import jakarta.persistence.Table
|
||||
|
||||
@Entity(name = "ChusanNetBattleLog")
|
||||
@Table(name = "chusan_net_battle_log")
|
||||
class Chu3NetBattleLog(
|
||||
var roomId: Long = 0,
|
||||
var track: Int = 0,
|
||||
|
||||
// From playlog
|
||||
var musicId: Int = 0,
|
||||
var difficultyId: Int = 0,
|
||||
var score: Int = 0,
|
||||
|
||||
var selectUserId: Long = 0,
|
||||
var selectUserName: String = "",
|
||||
var opponentUserId1: Long = 0,
|
||||
var opponentUserId2: Long = 0,
|
||||
var opponentUserId3: Long = 0,
|
||||
var opponentUserName1: String = "",
|
||||
var opponentUserName2: String = "",
|
||||
var opponentUserName3: String = "",
|
||||
var opponentRegionId1: Int = 0,
|
||||
var opponentRegionId2: Int = 0,
|
||||
var opponentRegionId3: Int = 0,
|
||||
var opponentRating1: Int = 0,
|
||||
var opponentRating2: Int = 0,
|
||||
var opponentRating3: Int = 0,
|
||||
var opponentBattleRankId1: Int = 0,
|
||||
var opponentBattleRankId2: Int = 0,
|
||||
var opponentBattleRankId3: Int = 0,
|
||||
var opponentClassEmblemMedal1: Int = 0,
|
||||
var opponentClassEmblemMedal2: Int = 0,
|
||||
var opponentClassEmblemMedal3: Int = 0,
|
||||
var opponentClassEmblemBase1: Int = 0,
|
||||
var opponentClassEmblemBase2: Int = 0,
|
||||
var opponentClassEmblemBase3: Int = 0,
|
||||
var opponentScore1: Int = 0,
|
||||
var opponentScore2: Int = 0,
|
||||
var opponentScore3: Int = 0,
|
||||
var opponentCharaIllustId1: Int = 0,
|
||||
var opponentCharaIllustId2: Int = 0,
|
||||
var opponentCharaIllustId3: Int = 0,
|
||||
var opponentCharaLv1: Int = 0,
|
||||
var opponentCharaLv2: Int = 0,
|
||||
var opponentCharaLv3: Int = 0,
|
||||
var opponentRatingEffectColorId1: Int = 0,
|
||||
var opponentRatingEffectColorId2: Int = 0,
|
||||
var opponentRatingEffectColorId3: Int = 0,
|
||||
var battleRuleId: Int = 0,
|
||||
var monthPoLong: Int = 0,
|
||||
var eventPoLong: Int = 0
|
||||
) : Chu3UserEntity() {
|
||||
|
||||
// musicId, difficultyId, userName, score, memberName{1-3}, memberScore{1-3}, selectedMemberNum
|
||||
fun toDict(username: String) = mapOf(
|
||||
"musicId" to musicId,
|
||||
"difficultyId" to difficultyId,
|
||||
"score" to score,
|
||||
"userName" to username,
|
||||
"memberName1" to opponentUserName1,
|
||||
"memberScore1" to opponentScore1,
|
||||
"memberName2" to opponentUserName2,
|
||||
"memberScore2" to opponentScore2,
|
||||
"memberName3" to opponentUserName3,
|
||||
"memberScore3" to opponentScore3,
|
||||
"selectedMemberNum" to listOf(
|
||||
true,
|
||||
selectUserId == opponentUserId1,
|
||||
selectUserId == opponentUserId2,
|
||||
selectUserId == opponentUserId3
|
||||
).lastIndexOf(true)
|
||||
)
|
||||
}
|
|
@ -6,7 +6,7 @@ import com.fasterxml.jackson.annotation.JsonProperty
|
|||
import com.fasterxml.jackson.databind.annotation.JsonSerialize
|
||||
import icu.samnyan.aqua.net.games.BaseEntity
|
||||
import icu.samnyan.aqua.net.games.IUserData
|
||||
import icu.samnyan.aqua.sega.chusan.model.response.data.UserEmoney
|
||||
import icu.samnyan.aqua.sega.chusan.model.request.UserEmoney
|
||||
import icu.samnyan.aqua.sega.general.model.Card
|
||||
import icu.samnyan.aqua.sega.util.jackson.AccessCodeSerializer
|
||||
import jakarta.persistence.*
|
||||
|
|
|
@ -8,9 +8,9 @@ import jakarta.persistence.ManyToOne
|
|||
import jakarta.persistence.MappedSuperclass
|
||||
|
||||
@MappedSuperclass
|
||||
open class Chu3UserEntity : BaseEntity(), IUserEntity<Chu3UserData> {
|
||||
class Chu3UserEntity : BaseEntity(), IUserEntity<Chu3UserData> {
|
||||
@JsonIgnore
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "user_id")
|
||||
public override var user: Chu3UserData = Chu3UserData()
|
||||
override var user: Chu3UserData = Chu3UserData()
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package icu.samnyan.aqua.sega.chusan.model.userdata
|
||||
|
||||
import icu.samnyan.aqua.sega.general.IntegerListConverter
|
||||
import jakarta.persistence.Convert
|
||||
import jakarta.persistence.Entity
|
||||
|
||||
|
||||
@Entity(name = "ChusanUserMisc")
|
||||
class Chu3UserMisc(
|
||||
@Convert(converter = IntegerListConverter::class)
|
||||
var recentNbSelect: MutableList<Int> = mutableListOf(),
|
||||
|
||||
@Convert(converter = IntegerListConverter::class)
|
||||
var recentNbMusic: MutableList<Int> = mutableListOf(),
|
||||
|
||||
@Convert(converter = IntegerListConverter::class)
|
||||
var favMusic: MutableList<Int> = mutableListOf()
|
||||
): Chu3UserEntity()
|
|
@ -8,9 +8,7 @@ import jakarta.persistence.UniqueConstraint
|
|||
|
||||
@Entity(name = "ChusanUserActivity")
|
||||
@Table(name = "chusan_user_activity", uniqueConstraints = [UniqueConstraint(columnNames = ["user_id", "kind", "activity_id"])])
|
||||
class UserActivity(user: Chu3UserData) : Chu3UserEntity() {
|
||||
init { this.user = user }
|
||||
|
||||
class UserActivity : Chu3UserEntity() {
|
||||
var kind = 0
|
||||
@JsonProperty("id")
|
||||
@Column(name = "activity_id")
|
||||
|
|
|
@ -1,15 +1,11 @@
|
|||
package icu.samnyan.aqua.sega.chusan.model.userdata
|
||||
|
||||
import jakarta.persistence.Column
|
||||
import jakarta.persistence.Entity
|
||||
import jakarta.persistence.Table
|
||||
|
||||
@Entity(name = "ChusanUserCMission")
|
||||
@Table(name = "chusan_user_cmission")
|
||||
class UserCMission : Chu3UserEntity() {
|
||||
@Column(name = "mission_id")
|
||||
var missionId = 0
|
||||
|
||||
@Column(name = "point")
|
||||
var point = 0
|
||||
}
|
||||
|
|
|
@ -6,10 +6,11 @@ import java.time.LocalDateTime
|
|||
|
||||
@Entity(name = "ChusanUserCardPrintState")
|
||||
@Table(name = "chusan_user_print_state")
|
||||
class UserCardPrintState : Chu3UserEntity() {
|
||||
var hasCompleted = false
|
||||
var limitDate: LocalDateTime = LocalDateTime.now()
|
||||
var placeId = 0
|
||||
var cardId = 0
|
||||
var gachaId = 0
|
||||
}
|
||||
class UserCardPrintState(
|
||||
var hasCompleted: Boolean = false,
|
||||
var limitDate: LocalDateTime = LocalDateTime.now(),
|
||||
var placeId: Int = 0,
|
||||
var cardId: Int = 0,
|
||||
var gachaId: Int = 0
|
||||
) : Chu3UserEntity()
|
||||
|
||||
|
|
|
@ -1,49 +0,0 @@
|
|||
package icu.samnyan.aqua.sega.chusan.model.userdata;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Table;
|
||||
import jakarta.persistence.UniqueConstraint;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@Entity(name = "ChusanUserCharacter")
|
||||
@Table(name = "chusan_user_character", uniqueConstraints = {@UniqueConstraint(columnNames = {"user_id", "character_id"})})
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@JsonPropertyOrder({"characterId", "playCount", "level", "friendshipExp", "isValid", "isNewMark", "exMaxLv", "assignIllust", "param1", "param2"})
|
||||
public class UserCharacter extends Chu3UserEntity {
|
||||
@Column(name = "character_id")
|
||||
private int characterId;
|
||||
|
||||
private int playCount = 0;
|
||||
|
||||
private int level = 1;
|
||||
|
||||
private int friendshipExp = 0;
|
||||
|
||||
@JsonProperty("isValid")
|
||||
private boolean isValid = true;
|
||||
|
||||
@JsonProperty("isNewMark")
|
||||
private boolean isNewMark = true;
|
||||
|
||||
private int exMaxLv = 0;
|
||||
|
||||
private int assignIllust = 0;
|
||||
|
||||
private int param1 = 0;
|
||||
|
||||
private int param2 = 0;
|
||||
|
||||
public UserCharacter(Chu3UserData userData) {
|
||||
setUser(userData);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package icu.samnyan.aqua.sega.chusan.model.userdata
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty
|
||||
import jakarta.persistence.Column
|
||||
import jakarta.persistence.Entity
|
||||
import jakarta.persistence.Table
|
||||
import jakarta.persistence.UniqueConstraint
|
||||
|
||||
@Entity(name = "ChusanUserCharacter")
|
||||
@Table(name = "chusan_user_character", uniqueConstraints = [UniqueConstraint(columnNames = ["user_id", "character_id"])])
|
||||
class UserCharacter : Chu3UserEntity() {
|
||||
@Column(name = "character_id")
|
||||
var characterId = 0
|
||||
var playCount = 0
|
||||
var level = 1
|
||||
var friendshipExp = 0
|
||||
@JsonProperty("isValid")
|
||||
var isValid = true
|
||||
@JsonProperty("isNewMark")
|
||||
var isNewMark = true
|
||||
var exMaxLv = 0
|
||||
var assignIllust = 0
|
||||
var param1 = 0
|
||||
var param2 = 0
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
package icu.samnyan.aqua.sega.chusan.model.userdata;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Table;
|
||||
import jakarta.persistence.UniqueConstraint;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@Entity(name = "ChusanUserCharge")
|
||||
@Table(name = "chusan_user_charge", uniqueConstraints = {@UniqueConstraint(columnNames = {"user_id", "charge_id"})})
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@JsonPropertyOrder({"chargeId", "stock", "purchaseDate", "validDate", "param1", "param2", "paramDate"})
|
||||
public class UserCharge extends Chu3UserEntity {
|
||||
@Column(name = "charge_id")
|
||||
private int chargeId;
|
||||
|
||||
private int stock;
|
||||
|
||||
private LocalDateTime purchaseDate;
|
||||
|
||||
private LocalDateTime validDate;
|
||||
|
||||
private int param1;
|
||||
|
||||
private int param2;
|
||||
|
||||
private LocalDateTime paramDate;
|
||||
|
||||
public UserCharge(Chu3UserData user) {
|
||||
setUser(user);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package icu.samnyan.aqua.sega.chusan.model.userdata
|
||||
|
||||
import jakarta.persistence.Entity
|
||||
import jakarta.persistence.Table
|
||||
import jakarta.persistence.UniqueConstraint
|
||||
import java.time.LocalDateTime
|
||||
|
||||
@Entity(name = "ChusanUserCharge")
|
||||
@Table(name = "chusan_user_charge", uniqueConstraints = [UniqueConstraint(columnNames = ["user_id", "charge_id"])])
|
||||
class UserCharge : Chu3UserEntity() {
|
||||
var chargeId = 0
|
||||
var stock = 0
|
||||
var purchaseDate: LocalDateTime? = null
|
||||
var validDate: LocalDateTime? = null
|
||||
var param1 = 0
|
||||
var param2 = 0
|
||||
var paramDate: LocalDateTime? = null
|
||||
}
|
|
@ -1,71 +0,0 @@
|
|||
package icu.samnyan.aqua.sega.chusan.model.userdata;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Table;
|
||||
import jakarta.persistence.UniqueConstraint;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@Entity(name = "ChusanUserCourse")
|
||||
@Table(name = "chusan_user_course", uniqueConstraints = {@UniqueConstraint(columnNames = {"user_id", "course_id"})})
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class UserCourse extends Chu3UserEntity {
|
||||
@Column(name = "course_id")
|
||||
private int courseId;
|
||||
|
||||
private int classId;
|
||||
|
||||
private int playCount;
|
||||
|
||||
private int theoryCount;
|
||||
|
||||
private int scoreMax;
|
||||
|
||||
@JsonProperty("isFullCombo")
|
||||
private boolean isFullCombo;
|
||||
|
||||
@JsonProperty("isAllJustice")
|
||||
private boolean isAllJustice;
|
||||
|
||||
@JsonProperty("isSuccess")
|
||||
private boolean isSuccess;
|
||||
|
||||
private int scoreRank;
|
||||
|
||||
private int eventId;
|
||||
|
||||
private LocalDateTime lastPlayDate;
|
||||
|
||||
private int param1;
|
||||
|
||||
private int param2;
|
||||
|
||||
private int param3;
|
||||
|
||||
private int param4;
|
||||
|
||||
private int orderId;
|
||||
|
||||
private int playerRating;
|
||||
|
||||
@JsonProperty("isClear")
|
||||
private boolean isClear;
|
||||
|
||||
public UserCourse(Chu3UserData userData) {
|
||||
setUser(userData);
|
||||
}
|
||||
|
||||
public UserCourse(int classId) {
|
||||
this.classId = classId;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
package icu.samnyan.aqua.sega.chusan.model.userdata
|
||||
import com.fasterxml.jackson.annotation.JsonProperty
|
||||
import jakarta.persistence.Entity
|
||||
import jakarta.persistence.Table
|
||||
import jakarta.persistence.UniqueConstraint
|
||||
import java.time.LocalDateTime
|
||||
|
||||
@Entity(name = "ChusanUserCourse")
|
||||
@Table(name = "chusan_user_course", uniqueConstraints = [UniqueConstraint(columnNames = ["user_id", "course_id"])])
|
||||
class UserCourse : Chu3UserEntity() {
|
||||
var courseId = 0
|
||||
var classId = 0
|
||||
var playCount = 0
|
||||
var theoryCount = 0
|
||||
var scoreMax = 0
|
||||
@JsonProperty("isFullCombo")
|
||||
var isFullCombo = false
|
||||
@JsonProperty("isAllJustice")
|
||||
var isAllJustice = false
|
||||
@JsonProperty("isSuccess")
|
||||
var isSuccess = false
|
||||
var scoreRank = 0
|
||||
var eventId = 0
|
||||
var lastPlayDate: LocalDateTime? = null
|
||||
var param1 = 0
|
||||
var param2 = 0
|
||||
var param3 = 0
|
||||
var param4 = 0
|
||||
var orderId = 0
|
||||
var playerRating = 0
|
||||
@JsonProperty("isClear")
|
||||
var isClear = false
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
package icu.samnyan.aqua.sega.chusan.model.userdata;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Table;
|
||||
import jakarta.persistence.UniqueConstraint;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@Entity(name = "ChusanUserDuel")
|
||||
@Table(name = "chusan_user_duel", uniqueConstraints = {@UniqueConstraint(columnNames = {"user_id", "duel_id"})})
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class UserDuel extends Chu3UserEntity {
|
||||
@Column(name = "duel_id")
|
||||
private int duelId;
|
||||
|
||||
private int progress;
|
||||
|
||||
private int point;
|
||||
|
||||
@JsonProperty("isClear")
|
||||
private boolean isClear;
|
||||
|
||||
private LocalDateTime lastPlayDate;
|
||||
|
||||
private int param1;
|
||||
|
||||
private int param2;
|
||||
|
||||
private int param3;
|
||||
|
||||
private int param4;
|
||||
|
||||
public UserDuel(Chu3UserData userData) {
|
||||
setUser(userData);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package icu.samnyan.aqua.sega.chusan.model.userdata
|
||||
import com.fasterxml.jackson.annotation.JsonProperty
|
||||
import jakarta.persistence.Column
|
||||
import jakarta.persistence.Entity
|
||||
import jakarta.persistence.Table
|
||||
import jakarta.persistence.UniqueConstraint
|
||||
import java.time.LocalDateTime
|
||||
|
||||
@Entity(name = "ChusanUserDuel")
|
||||
@Table(name = "chusan_user_duel", uniqueConstraints = [UniqueConstraint(columnNames = ["user_id", "duel_id"])])
|
||||
class UserDuel : Chu3UserEntity() {
|
||||
@Column(name = "duel_id")
|
||||
var duelId = 0
|
||||
var progress = 0
|
||||
var point = 0
|
||||
@JsonProperty("isClear")
|
||||
var isClear = false
|
||||
var lastPlayDate: LocalDateTime? = null
|
||||
var param1 = 0
|
||||
var param2 = 0
|
||||
var param3 = 0
|
||||
var param4 = 0
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
package icu.samnyan.aqua.sega.chusan.model.userdata;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Table;
|
||||
import jakarta.persistence.UniqueConstraint;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@Entity(name = "ChusanUserGacha")
|
||||
@Table(name = "chusan_user_gacha", uniqueConstraints = {@UniqueConstraint(columnNames = {"user_id", "gacha_id"})})
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class UserGacha extends Chu3UserEntity {
|
||||
@Column(name = "gacha_id")
|
||||
private int gachaId;
|
||||
|
||||
private int totalGachaCnt;
|
||||
|
||||
private int ceilingGachaCnt;
|
||||
|
||||
private int dailyGachaCnt;
|
||||
|
||||
private int fiveGachaCnt;
|
||||
|
||||
private int elevenGachaCnt;
|
||||
|
||||
private LocalDateTime dailyGachaDate;
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
package icu.samnyan.aqua.sega.chusan.model.userdata
|
||||
|
||||
import jakarta.persistence.Entity
|
||||
import jakarta.persistence.Table
|
||||
import java.time.LocalDateTime
|
||||
|
||||
@Entity(name = "ChusanUserGacha")
|
||||
@Table(name = "chusan_user_gacha")
|
||||
class UserGacha : Chu3UserEntity() {
|
||||
var gachaId = 0
|
||||
var totalGachaCnt = 0
|
||||
var ceilingGachaCnt = 0
|
||||
var dailyGachaCnt = 0
|
||||
var fiveGachaCnt = 0
|
||||
var elevenGachaCnt = 0
|
||||
var dailyGachaDate: LocalDateTime? = null
|
||||
}
|
|
@ -1,175 +0,0 @@
|
|||
package icu.samnyan.aqua.sega.chusan.model.userdata;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Table;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@Entity(name = "ChusanUserGameOption")
|
||||
@Table(name = "chusan_user_game_option")
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@JsonPropertyOrder({
|
||||
"bgInfo",
|
||||
"fieldColor",
|
||||
"guideSound",
|
||||
"soundEffect",
|
||||
"guideLine",
|
||||
"speed",
|
||||
"optionSet",
|
||||
"matching",
|
||||
"judgePos",
|
||||
"rating",
|
||||
"judgeCritical",
|
||||
"judgeJustice",
|
||||
"judgeAttack",
|
||||
"headphone",
|
||||
"playerLevel",
|
||||
"successTap",
|
||||
"successExTap",
|
||||
"successSlideHold",
|
||||
"successAir",
|
||||
"successFlick",
|
||||
"successSkill",
|
||||
"successTapTimbre",
|
||||
"privacy",
|
||||
"mirrorFumen",
|
||||
"selectMusicFilterLv",
|
||||
"sortMusicFilterLv",
|
||||
"sortMusicGenre",
|
||||
"categoryDetail",
|
||||
"judgeTimingOffset",
|
||||
"playTimingOffset",
|
||||
"fieldWallPosition",
|
||||
"resultVoiceShort",
|
||||
"notesThickness",
|
||||
"judgeAppendSe",
|
||||
"trackSkip",
|
||||
"hardJudge",
|
||||
"speed_120",
|
||||
"fieldWallPosition_120",
|
||||
"playTimingOffset_120",
|
||||
"judgeTimingOffset_120",
|
||||
"ext1",
|
||||
"ext2",
|
||||
"ext3",
|
||||
"ext4",
|
||||
"ext5",
|
||||
"ext6",
|
||||
"ext7",
|
||||
"ext8",
|
||||
"ext9",
|
||||
"ext10"
|
||||
})
|
||||
public class UserGameOption extends Chu3UserEntity {
|
||||
|
||||
private int bgInfo;
|
||||
|
||||
private int fieldColor;
|
||||
|
||||
private int guideSound;
|
||||
|
||||
private int soundEffect;
|
||||
|
||||
private int guideLine;
|
||||
|
||||
private int speed;
|
||||
|
||||
private int optionSet;
|
||||
|
||||
private int matching;
|
||||
|
||||
private int judgePos;
|
||||
|
||||
private int rating;
|
||||
|
||||
private int judgeCritical;
|
||||
|
||||
private int judgeJustice;
|
||||
|
||||
private int judgeAttack;
|
||||
|
||||
private int headphone;
|
||||
|
||||
private int playerLevel;
|
||||
|
||||
private int successTap;
|
||||
|
||||
private int successExTap;
|
||||
|
||||
private int successSlideHold;
|
||||
|
||||
private int successAir;
|
||||
|
||||
private int successFlick;
|
||||
|
||||
private int successSkill;
|
||||
|
||||
private int successTapTimbre;
|
||||
|
||||
private int privacy;
|
||||
|
||||
private int mirrorFumen;
|
||||
|
||||
private int selectMusicFilterLv;
|
||||
|
||||
private int sortMusicFilterLv;
|
||||
|
||||
private int sortMusicGenre;
|
||||
|
||||
private int categoryDetail;
|
||||
|
||||
private int judgeTimingOffset;
|
||||
|
||||
private int playTimingOffset;
|
||||
|
||||
private int fieldWallPosition;
|
||||
|
||||
private int resultVoiceShort;
|
||||
|
||||
private int notesThickness;
|
||||
|
||||
private int judgeAppendSe;
|
||||
|
||||
private int trackSkip;
|
||||
|
||||
private int hardJudge;
|
||||
|
||||
private int speed_120;
|
||||
|
||||
private int fieldWallPosition_120;
|
||||
|
||||
private int playTimingOffset_120;
|
||||
|
||||
private int judgeTimingOffset_120;
|
||||
|
||||
private int ext1;
|
||||
|
||||
private int ext2;
|
||||
|
||||
private int ext3;
|
||||
|
||||
private int ext4;
|
||||
|
||||
private int ext5;
|
||||
|
||||
private int ext6;
|
||||
|
||||
private int ext7;
|
||||
|
||||
private int ext8;
|
||||
|
||||
private int ext9;
|
||||
|
||||
private int ext10;
|
||||
|
||||
public UserGameOption(Chu3UserData userData) {
|
||||
setUser(userData);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
package icu.samnyan.aqua.sega.chusan.model.userdata
|
||||
import jakarta.persistence.Entity
|
||||
import jakarta.persistence.Table
|
||||
|
||||
@Entity(name = "ChusanUserGameOption")
|
||||
@Table(name = "chusan_user_game_option")
|
||||
class UserGameOption : Chu3UserEntity() {
|
||||
var bgInfo = 0
|
||||
var fieldColor = 0
|
||||
var guideSound = 0
|
||||
var soundEffect = 0
|
||||
var guideLine = 0
|
||||
var speed = 0
|
||||
var optionSet = 0
|
||||
var matching = 0
|
||||
var judgePos = 0
|
||||
var rating = 0
|
||||
var judgeCritical = 0
|
||||
var judgeJustice = 0
|
||||
var judgeAttack = 0
|
||||
var headphone = 0
|
||||
var playerLevel = 0
|
||||
var successTap = 0
|
||||
var successExTap = 0
|
||||
var successSlideHold = 0
|
||||
var successAir = 0
|
||||
var successFlick = 0
|
||||
var successSkill = 0
|
||||
var successTapTimbre = 0
|
||||
var privacy = 0
|
||||
var mirrorFumen = 0
|
||||
var selectMusicFilterLv = 0
|
||||
var sortMusicFilterLv = 0
|
||||
var sortMusicGenre = 0
|
||||
var categoryDetail = 0
|
||||
var judgeTimingOffset = 0
|
||||
var playTimingOffset = 0
|
||||
var fieldWallPosition = 0
|
||||
var resultVoiceShort = 0
|
||||
var notesThickness = 0
|
||||
var judgeAppendSe = 0
|
||||
var trackSkip = 0
|
||||
var hardJudge = 0
|
||||
var speed_120 = 0
|
||||
var fieldWallPosition_120 = 0
|
||||
var playTimingOffset_120 = 0
|
||||
var judgeTimingOffset_120 = 0
|
||||
var ext1 = 0
|
||||
var ext2 = 0
|
||||
var ext3 = 0
|
||||
var ext4 = 0
|
||||
var ext5 = 0
|
||||
var ext6 = 0
|
||||
var ext7 = 0
|
||||
var ext8 = 0
|
||||
var ext9 = 0
|
||||
var ext10 = 0
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
package icu.samnyan.aqua.sega.chusan.model.userdata;
|
||||
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Table;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* This is for storing the other data that doesn't need to save it in a separate table
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@Entity(name = "ChusanUserGeneralData")
|
||||
@Table(name = "chusan_user_general_data")
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class UserGeneralData extends Chu3UserEntity {
|
||||
private String propertyKey;
|
||||
|
||||
@Column(columnDefinition = "TEXT")
|
||||
private String propertyValue;
|
||||
|
||||
public UserGeneralData(Chu3UserData userData, String key) {
|
||||
setUser(userData);
|
||||
this.propertyKey = key;
|
||||
this.propertyValue = "";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package icu.samnyan.aqua.sega.chusan.model.userdata
|
||||
|
||||
import jakarta.persistence.Column
|
||||
import jakarta.persistence.Entity
|
||||
import jakarta.persistence.Table
|
||||
|
||||
@Entity(name = "ChusanUserGeneralData")
|
||||
@Table(name = "chusan_user_general_data")
|
||||
class UserGeneralData(
|
||||
@Column(columnDefinition = "TEXT")
|
||||
var propertyValue: String = "",
|
||||
var propertyKey: String = "",
|
||||
) : Chu3UserEntity()
|
|
@ -1,38 +0,0 @@
|
|||
package icu.samnyan.aqua.sega.chusan.model.userdata;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Table;
|
||||
import jakarta.persistence.UniqueConstraint;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@Entity(name = "ChusanUserItem")
|
||||
@Table(name = "chusan_user_item", uniqueConstraints = {@UniqueConstraint(columnNames = {"user_id", "item_id", "item_kind"})})
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@JsonPropertyOrder({"itemKind", "itemId", "stock", "isValid"})
|
||||
public class UserItem extends Chu3UserEntity {
|
||||
// Kind ,Type
|
||||
@Column(name = "item_kind")
|
||||
private int itemKind;
|
||||
|
||||
@Column(name = "item_id")
|
||||
private int itemId;
|
||||
|
||||
private int stock = 1;
|
||||
|
||||
@JsonProperty("isValid")
|
||||
private boolean isValid = true;
|
||||
|
||||
public UserItem(Chu3UserData userData) {
|
||||
setUser(userData);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package icu.samnyan.aqua.sega.chusan.model.userdata
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty
|
||||
import jakarta.persistence.Entity
|
||||
import jakarta.persistence.Table
|
||||
import jakarta.persistence.UniqueConstraint
|
||||
|
||||
@Entity(name = "ChusanUserItem")
|
||||
@Table(name = "chusan_user_item", uniqueConstraints = [UniqueConstraint(columnNames = ["user_id", "item_id", "item_kind"])])
|
||||
class UserItem(
|
||||
var itemKind: Int = 0,
|
||||
var itemId: Int = 0,
|
||||
var stock: Int = 1,
|
||||
@JsonProperty("isValid")
|
||||
var isValid: Boolean = true
|
||||
) : Chu3UserEntity()
|
|
@ -1,35 +0,0 @@
|
|||
package icu.samnyan.aqua.sega.chusan.model.userdata;
|
||||
|
||||
import icu.samnyan.aqua.net.games.BaseEntity;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Table;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Entity(name = "ChusanUserLoginBonus")
|
||||
@Table(name = "chusan_user_login_bonus")
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class UserLoginBonus extends BaseEntity {
|
||||
private int version;
|
||||
private int user;
|
||||
private int presetId;
|
||||
private int bonusCount;
|
||||
private LocalDateTime lastUpdateDate;
|
||||
private boolean isWatched;
|
||||
private boolean isFinished;
|
||||
|
||||
public UserLoginBonus(int version, int user, int presetId) {
|
||||
this.version = version;
|
||||
this.user = user;
|
||||
this.presetId = presetId;
|
||||
this.bonusCount = 0;
|
||||
this.lastUpdateDate = LocalDateTime.parse("2018-01-01T00:00:00");
|
||||
this.isWatched = false;
|
||||
this.isFinished = false;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package icu.samnyan.aqua.sega.chusan.model.userdata
|
||||
|
||||
import ext.DATE_2018
|
||||
import icu.samnyan.aqua.net.games.BaseEntity
|
||||
import jakarta.persistence.Entity
|
||||
import jakarta.persistence.Table
|
||||
import java.time.LocalDateTime
|
||||
|
||||
@Entity(name = "ChusanUserLoginBonus")
|
||||
@Table(name = "chusan_user_login_bonus")
|
||||
class UserLoginBonus(
|
||||
var version: Int = 0,
|
||||
// TODO: Fix this (should be User linked)
|
||||
var user: Int = 0,
|
||||
var presetId: Int = 0,
|
||||
var bonusCount: Int = 0,
|
||||
var lastUpdateDate: LocalDateTime = DATE_2018,
|
||||
var isWatched: Boolean = false, // TODO: Check if this should be "watched" or "isWatched" in json
|
||||
var isFinished: Boolean = false,
|
||||
) : BaseEntity()
|
|
@ -1,51 +0,0 @@
|
|||
package icu.samnyan.aqua.sega.chusan.model.userdata;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Table;
|
||||
import jakarta.persistence.UniqueConstraint;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@Entity(name = "ChusanUserMapArea")
|
||||
@Table(name = "chusan_user_map_area", uniqueConstraints = {@UniqueConstraint(columnNames = {"user_id", "map_area_id"})})
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@JsonPropertyOrder({
|
||||
"mapAreaId",
|
||||
"position",
|
||||
"isClear",
|
||||
"rate",
|
||||
"statusCount",
|
||||
"remainGridCount",
|
||||
"isLocked"
|
||||
})
|
||||
public class UserMap extends Chu3UserEntity {
|
||||
@Column(name = "map_area_id")
|
||||
private int mapAreaId;
|
||||
|
||||
private int position;
|
||||
|
||||
@JsonProperty("isClear")
|
||||
private boolean isClear;
|
||||
|
||||
private int rate;
|
||||
|
||||
private int statusCount;
|
||||
|
||||
private int remainGridCount;
|
||||
|
||||
@JsonProperty("isLocked")
|
||||
private boolean isLocked;
|
||||
|
||||
public UserMap(Chu3UserData userData) {
|
||||
setUser(userData);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package icu.samnyan.aqua.sega.chusan.model.userdata
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty
|
||||
import jakarta.persistence.Entity
|
||||
import jakarta.persistence.Table
|
||||
import jakarta.persistence.UniqueConstraint
|
||||
|
||||
@Entity(name = "ChusanUserMapArea")
|
||||
@Table(name = "chusan_user_map_area", uniqueConstraints = [UniqueConstraint(columnNames = ["user_id", "map_area_id"])])
|
||||
class UserMap : Chu3UserEntity() {
|
||||
var mapAreaId = 0
|
||||
var position = 0
|
||||
|
||||
@JsonProperty("isClear")
|
||||
var isClear = false
|
||||
|
||||
var rate = 0
|
||||
var statusCount = 0
|
||||
var remainGridCount = 0
|
||||
|
||||
@JsonProperty("isLocked")
|
||||
var isLocked = false
|
||||
}
|
|
@ -1,79 +0,0 @@
|
|||
package icu.samnyan.aqua.sega.chusan.model.userdata;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||
import icu.samnyan.aqua.sega.util.jackson.BooleanToIntegerDeserializer;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Table;
|
||||
import jakarta.persistence.UniqueConstraint;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@Entity(name = "ChusanUserMusicDetail")
|
||||
@Table(name = "chusan_user_music_detail", uniqueConstraints = {@UniqueConstraint(columnNames = {"user_id", "music_id", "level"})})
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@JsonPropertyOrder({
|
||||
"musicId",
|
||||
"level",
|
||||
"playCount",
|
||||
"scoreMax",
|
||||
"missCount",
|
||||
"maxComboCount",
|
||||
"isFullCombo",
|
||||
"isAllJustice",
|
||||
"isSuccess",
|
||||
"fullChain",
|
||||
"maxChain",
|
||||
"isLock",
|
||||
"theoryCount",
|
||||
"ext1"
|
||||
})
|
||||
public class UserMusicDetail extends Chu3UserEntity {
|
||||
@Column(name = "music_id")
|
||||
private int musicId;
|
||||
|
||||
private int level;
|
||||
|
||||
private int playCount;
|
||||
|
||||
private int scoreMax;
|
||||
|
||||
private int missCount;
|
||||
|
||||
private int maxComboCount;
|
||||
|
||||
@JsonProperty("isFullCombo")
|
||||
private boolean isFullCombo;
|
||||
|
||||
@JsonProperty("isAllJustice")
|
||||
private boolean isAllJustice;
|
||||
|
||||
@JsonDeserialize(using = BooleanToIntegerDeserializer.class)
|
||||
@JsonProperty("isSuccess")
|
||||
private int isSuccess;
|
||||
|
||||
private int fullChain;
|
||||
|
||||
private int maxChain;
|
||||
|
||||
private int scoreRank;
|
||||
|
||||
@JsonProperty("isLock")
|
||||
private boolean isLock;
|
||||
|
||||
private int theoryCount;
|
||||
|
||||
private int ext1;
|
||||
|
||||
public UserMusicDetail(Chu3UserData userData) {
|
||||
setUser(userData);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
package icu.samnyan.aqua.sega.chusan.model.userdata
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty
|
||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize
|
||||
import icu.samnyan.aqua.sega.util.jackson.BooleanToIntegerDeserializer
|
||||
import jakarta.persistence.Entity
|
||||
import jakarta.persistence.Table
|
||||
import jakarta.persistence.UniqueConstraint
|
||||
|
||||
/**
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@Entity(name = "ChusanUserMusicDetail")
|
||||
@Table(
|
||||
name = "chusan_user_music_detail",
|
||||
uniqueConstraints = [UniqueConstraint(columnNames = ["user_id", "music_id", "level"])]
|
||||
)
|
||||
class UserMusicDetail : Chu3UserEntity() {
|
||||
var musicId = 0
|
||||
var level = 0
|
||||
var playCount = 0
|
||||
var scoreMax = 0
|
||||
var missCount = 0
|
||||
var maxComboCount = 0
|
||||
|
||||
@JsonProperty("isFullCombo")
|
||||
var isFullCombo = false
|
||||
|
||||
@JsonProperty("isAllJustice")
|
||||
var isAllJustice = false
|
||||
|
||||
@JsonDeserialize(using = BooleanToIntegerDeserializer::class)
|
||||
@JsonProperty("isSuccess")
|
||||
var isSuccess = 0
|
||||
|
||||
var fullChain = 0
|
||||
var maxChain = 0
|
||||
var scoreRank = 0
|
||||
|
||||
@JsonProperty("isLock")
|
||||
var isLock = false
|
||||
|
||||
var theoryCount = 0
|
||||
var ext1 = 0
|
||||
}
|
|
@ -1,167 +0,0 @@
|
|||
package icu.samnyan.aqua.sega.chusan.model.userdata;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import icu.samnyan.aqua.net.games.IGenericGamePlaylog;
|
||||
import jakarta.persistence.Column;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.Table;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@Entity(name = "ChusanUserPlaylog")
|
||||
@Table(name = "chusan_user_playlog")
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class UserPlaylog extends Chu3UserEntity implements IGenericGamePlaylog {
|
||||
private String romVersion;
|
||||
|
||||
private int orderId;
|
||||
|
||||
private int sortNumber;
|
||||
|
||||
private int placeId;
|
||||
|
||||
private LocalDateTime playDate;
|
||||
|
||||
private LocalDateTime userPlayDate;
|
||||
|
||||
private int musicId;
|
||||
|
||||
private int level;
|
||||
|
||||
private int customId;
|
||||
|
||||
private long playedUserId1;
|
||||
|
||||
private long playedUserId2;
|
||||
|
||||
private long playedUserId3;
|
||||
|
||||
private String playedUserName1;
|
||||
|
||||
private String playedUserName2;
|
||||
|
||||
private String playedUserName3;
|
||||
|
||||
private int playedMusicLevel1;
|
||||
|
||||
private int playedMusicLevel2;
|
||||
|
||||
private int playedMusicLevel3;
|
||||
|
||||
private int playedCustom1;
|
||||
|
||||
private int playedCustom2;
|
||||
|
||||
private int playedCustom3;
|
||||
|
||||
private int track;
|
||||
|
||||
private int score;
|
||||
|
||||
@Column(name = "\"rank\"")
|
||||
private int rank;
|
||||
|
||||
private int maxCombo;
|
||||
|
||||
private int maxChain;
|
||||
|
||||
private int rateTap;
|
||||
|
||||
private int rateHold;
|
||||
|
||||
private int rateSlide;
|
||||
|
||||
private int rateAir;
|
||||
|
||||
private int rateFlick;
|
||||
|
||||
private int judgeGuilty;
|
||||
|
||||
private int judgeAttack;
|
||||
|
||||
private int judgeJustice;
|
||||
|
||||
private int judgeCritical;
|
||||
|
||||
private int judgeHeaven;
|
||||
|
||||
private int eventId;
|
||||
|
||||
private int playerRating;
|
||||
|
||||
@JsonProperty("isNewRecord")
|
||||
private boolean isNewRecord;
|
||||
|
||||
@JsonProperty("isFullCombo")
|
||||
private boolean isFullCombo;
|
||||
|
||||
private int fullChainKind;
|
||||
|
||||
@JsonProperty("isAllJustice")
|
||||
private boolean isAllJustice;
|
||||
|
||||
@JsonProperty("isContinue")
|
||||
private boolean isContinue;
|
||||
|
||||
@JsonProperty("isFreeToPlay")
|
||||
private boolean isFreeToPlay;
|
||||
|
||||
private int characterId;
|
||||
|
||||
private int charaIllustId;
|
||||
|
||||
private int skillId;
|
||||
|
||||
private int playKind;
|
||||
|
||||
@JsonProperty("isClear")
|
||||
private boolean isClear;
|
||||
|
||||
private int skillLevel;
|
||||
|
||||
private int skillEffect;
|
||||
|
||||
private String placeName;
|
||||
|
||||
private int commonId;
|
||||
|
||||
// SUN
|
||||
private int regionId;
|
||||
|
||||
private int machineType;
|
||||
|
||||
// SUN PLUS
|
||||
private int ticketId;
|
||||
|
||||
public UserPlaylog(Chu3UserData userData) {
|
||||
setUser(userData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAchievement() {
|
||||
return score;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getAfterRating() {
|
||||
return playerRating;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBeforeRating() {
|
||||
return playerRating; // TODO: Get before rating
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAllPerfect() {
|
||||
return isAllJustice;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
package icu.samnyan.aqua.sega.chusan.model.userdata
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty
|
||||
import icu.samnyan.aqua.net.games.IGenericGamePlaylog
|
||||
import jakarta.persistence.Column
|
||||
import jakarta.persistence.Entity
|
||||
import jakarta.persistence.Table
|
||||
import java.time.LocalDateTime
|
||||
|
||||
@Entity(name = "ChusanUserPlaylog")
|
||||
@Table(name = "chusan_user_playlog")
|
||||
class UserPlaylog : Chu3UserEntity(), IGenericGamePlaylog {
|
||||
var romVersion: String? = null
|
||||
var orderId = 0
|
||||
var sortNumber = 0
|
||||
var placeId = 0
|
||||
var playDate: LocalDateTime? = null
|
||||
override var userPlayDate: LocalDateTime = LocalDateTime.now()
|
||||
override var musicId: Int = 0
|
||||
override var level: Int = 0
|
||||
var customId = 0
|
||||
var playedUserId1: Long = 0
|
||||
var playedUserId2: Long = 0
|
||||
var playedUserId3: Long = 0
|
||||
var playedUserName1: String? = null
|
||||
var playedUserName2: String? = null
|
||||
var playedUserName3: String? = null
|
||||
var playedMusicLevel1 = 0
|
||||
var playedMusicLevel2 = 0
|
||||
var playedMusicLevel3 = 0
|
||||
var playedCustom1 = 0
|
||||
var playedCustom2 = 0
|
||||
var playedCustom3 = 0
|
||||
var track = 0
|
||||
var score = 0
|
||||
@Column(name = "\"rank\"")
|
||||
var rank = 0
|
||||
override var maxCombo: Int = 0
|
||||
var maxChain = 0
|
||||
var rateTap = 0
|
||||
var rateHold = 0
|
||||
var rateSlide = 0
|
||||
var rateAir = 0
|
||||
var rateFlick = 0
|
||||
var judgeGuilty = 0
|
||||
var judgeAttack = 0
|
||||
var judgeJustice = 0
|
||||
var judgeCritical = 0
|
||||
var judgeHeaven = 0
|
||||
var eventId = 0
|
||||
var playerRating = 0
|
||||
@JsonProperty("isNewRecord")
|
||||
var isNewRecord = false
|
||||
@JsonProperty("isFullCombo")
|
||||
override var isFullCombo: Boolean = false
|
||||
var fullChainKind = 0
|
||||
@JsonProperty("isAllJustice")
|
||||
var isAllJustice = false
|
||||
@JsonProperty("isContinue")
|
||||
var isContinue = false
|
||||
@JsonProperty("isFreeToPlay")
|
||||
var isFreeToPlay = false
|
||||
var characterId = 0
|
||||
var charaIllustId = 0
|
||||
var skillId = 0
|
||||
var playKind = 0
|
||||
@JsonProperty("isClear")
|
||||
var isClear = false
|
||||
var skillLevel = 0
|
||||
var skillEffect = 0
|
||||
var placeName: String? = null
|
||||
var commonId = 0
|
||||
var regionId = 0
|
||||
var machineType = 0
|
||||
var ticketId = 0
|
||||
|
||||
override val achievement: Int get() = score
|
||||
override val afterRating: Int get() = playerRating
|
||||
override val beforeRating: Int get() = playerRating // TODO: Implement this
|
||||
override val isAllPerfect: Boolean get() = isAllJustice
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
package icu.samnyan.aqua.sega.chusan.service;
|
||||
|
||||
import icu.samnyan.aqua.sega.chusan.model.Chu3GameLoginBonusPresetsRepo;
|
||||
import icu.samnyan.aqua.sega.chusan.model.gamedata.GameLoginBonusPreset;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Service("ChusanGameLoginBonusPresetService")
|
||||
public class GameLoginBonusPresetService {
|
||||
private final Chu3GameLoginBonusPresetsRepo gameLoginBonusPresetsRepository;
|
||||
|
||||
@Autowired
|
||||
public GameLoginBonusPresetService(Chu3GameLoginBonusPresetsRepo gameLoginBonusPresetsRepository){
|
||||
this.gameLoginBonusPresetsRepository = gameLoginBonusPresetsRepository;
|
||||
}
|
||||
|
||||
public List<GameLoginBonusPreset> getGameLoginBonusPresets(int version){
|
||||
return this.gameLoginBonusPresetsRepository.findLoginBonusPresets(version, 1);
|
||||
}
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
package icu.samnyan.aqua.sega.chusan.service;
|
||||
|
||||
|
||||
import icu.samnyan.aqua.sega.chusan.model.Chu3GameLoginBonusRepo;
|
||||
import icu.samnyan.aqua.sega.chusan.model.gamedata.GameLoginBonus;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
@Service("ChusanGameLoginBonusService")
|
||||
public class GameLoginBonusService {
|
||||
private final Chu3GameLoginBonusRepo gameLoginBonusRepository;
|
||||
|
||||
@Autowired
|
||||
public GameLoginBonusService(Chu3GameLoginBonusRepo gameLoginBonusRepository){
|
||||
this.gameLoginBonusRepository = gameLoginBonusRepository;
|
||||
}
|
||||
|
||||
public List<GameLoginBonus> getAllGameLoginBonus(int presetId){
|
||||
return this.gameLoginBonusRepository.findGameLoginBonus(1, presetId);
|
||||
}
|
||||
|
||||
public Optional<GameLoginBonus> getGameLoginBonusByDay(int presetId, int day){
|
||||
return this.gameLoginBonusRepository.findByRequiredDays(1, presetId, day);
|
||||
}
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
package icu.samnyan.aqua.sega.chusan.service;
|
||||
|
||||
import icu.samnyan.aqua.sega.chusan.model.Chu3UserActivityRepo;
|
||||
import icu.samnyan.aqua.sega.chusan.model.userdata.UserActivity;
|
||||
import icu.samnyan.aqua.sega.chusan.model.userdata.Chu3UserData;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@Service("ChusanUserActivityService")
|
||||
public class UserActivityService {
|
||||
|
||||
private final Chu3UserActivityRepo userActivityRepository;
|
||||
|
||||
@Autowired
|
||||
public UserActivityService(Chu3UserActivityRepo userActivityRepository) {
|
||||
this.userActivityRepository = userActivityRepository;
|
||||
}
|
||||
|
||||
public List<UserActivity> getByUserId(String userId) {
|
||||
return userActivityRepository.findByUser_Card_ExtId(Long.parseLong(userId));
|
||||
}
|
||||
}
|
|
@ -1,49 +0,0 @@
|
|||
package icu.samnyan.aqua.sega.chusan.service;
|
||||
|
||||
import icu.samnyan.aqua.sega.chusan.model.Chu3UserCharacterRepo;
|
||||
import icu.samnyan.aqua.sega.chusan.model.userdata.UserCharacter;
|
||||
import icu.samnyan.aqua.sega.chusan.model.userdata.Chu3UserData;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@Service("ChusanUserCharacterService")
|
||||
public class UserCharacterService {
|
||||
|
||||
private final Chu3UserCharacterRepo userCharacterRepository;
|
||||
|
||||
@Autowired
|
||||
public UserCharacterService(Chu3UserCharacterRepo userCharacterRepository) {
|
||||
this.userCharacterRepository = userCharacterRepository;
|
||||
}
|
||||
|
||||
public UserCharacter save(UserCharacter userCharacter) {
|
||||
return userCharacterRepository.save(userCharacter);
|
||||
}
|
||||
|
||||
public List<UserCharacter> saveAll(Iterable<UserCharacter> userCharacter) {
|
||||
return userCharacterRepository.saveAll(userCharacter);
|
||||
}
|
||||
|
||||
public List<UserCharacter> getByUserId(String userId) {
|
||||
return userCharacterRepository.findByUser_Card_ExtId(Long.parseLong(userId));
|
||||
}
|
||||
|
||||
public Page<UserCharacter> getByUserId(String userId, int pageNumber, int maxCount) {
|
||||
Pageable pageable = PageRequest.of(pageNumber, maxCount);
|
||||
return userCharacterRepository.findByUser_Card_ExtId(Long.parseLong(userId), pageable);
|
||||
}
|
||||
|
||||
public Optional<UserCharacter> getByUserAndCharacterId(Chu3UserData user, int characterId) {
|
||||
return userCharacterRepository.findTopByUserAndCharacterIdOrderByIdDesc(user, characterId);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
package icu.samnyan.aqua.sega.chusan.service;
|
||||
|
||||
import icu.samnyan.aqua.sega.chusan.model.Chu3UserChargeRepo;
|
||||
import icu.samnyan.aqua.sega.chusan.model.userdata.UserCharge;
|
||||
import icu.samnyan.aqua.sega.chusan.model.userdata.Chu3UserData;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@Service("ChusanUserChargeService")
|
||||
public class UserChargeService {
|
||||
|
||||
private final Chu3UserChargeRepo userChargeRepository;
|
||||
|
||||
public UserChargeService(Chu3UserChargeRepo userChargeRepository) {
|
||||
this.userChargeRepository = userChargeRepository;
|
||||
}
|
||||
|
||||
public UserCharge save(UserCharge userCharge) {
|
||||
return userChargeRepository.save(userCharge);
|
||||
}
|
||||
|
||||
public List<UserCharge> saveAll(List<UserCharge> newUserChargeList) {
|
||||
return userChargeRepository.saveAll(newUserChargeList);
|
||||
}
|
||||
|
||||
public List<UserCharge> getByUserId(String userId) {
|
||||
return userChargeRepository.findByUser_Card_ExtId(Long.parseLong(userId));
|
||||
}
|
||||
|
||||
public Optional<UserCharge> getByUserAndChargeId(Chu3UserData user, int chargeId) {
|
||||
return userChargeRepository.findByUserAndChargeId(user, chargeId);
|
||||
}
|
||||
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue