mirror of
https://github.com/MewoLab/AquaDX.git
synced 2025-12-14 11:56:15 +08:00
Compare commits
17 Commits
491044d37a
...
v1-dev
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
aeafa6a396 | ||
|
|
448426a96d | ||
|
|
dfa6176689 | ||
|
|
d996fba291 | ||
|
|
0cb2a95ff3 | ||
|
|
be5220fd51 | ||
|
|
f23c0d6fe1 | ||
|
|
5aca650602 | ||
|
|
7c72348016 | ||
|
|
5eee6505f9 | ||
|
|
43b7ea65a5 | ||
|
|
85149dcd03 | ||
|
|
a767c8949c | ||
|
|
bbeb476a62 | ||
|
|
c444350cef | ||
|
|
13a318d519 | ||
|
|
e744d96c96 |
@@ -1,7 +1,6 @@
|
||||
<script>
|
||||
import { fade } from "svelte/transition";
|
||||
import { FADE_IN, FADE_OUT } from "../../libs/config";
|
||||
import GameSettingFields from "./GameSettingFields.svelte";
|
||||
import { t, ts } from "../../libs/i18n";
|
||||
import useLocalStorage from "../../libs/hooks/useLocalStorage.svelte";
|
||||
import RegionSelector from "./RegionSelector.svelte";
|
||||
@@ -13,7 +12,6 @@
|
||||
<blockquote>
|
||||
{ts("settings.gameNotice")}
|
||||
</blockquote>
|
||||
<GameSettingFields game="general"/>
|
||||
<div class="field">
|
||||
<div class="bool">
|
||||
<input id="rounding" type="checkbox" bind:checked={rounding.value}/>
|
||||
|
||||
@@ -149,18 +149,30 @@ export const EN_REF_SETTINGS = {
|
||||
'settings.tabs.mai2': 'Mai',
|
||||
'settings.tabs.ongeki': 'Ongeki',
|
||||
'settings.tabs.wacca': 'Wacca',
|
||||
'settings.fields.unlockMusic.name': 'Unlock All Music',
|
||||
'settings.fields.unlockMusic.desc': 'Unlock all music and master difficulty in game.',
|
||||
'settings.fields.unlockChara.name': 'Unlock All Characters',
|
||||
'settings.fields.unlockChara.desc': 'Unlock all characters, voices, and partners in game.',
|
||||
'settings.fields.unlockCollectables.name': 'Unlock All Collectables',
|
||||
'settings.fields.unlockCollectables.desc': 'Unlock all collectables (nameplate, title, icon, frame) in game.',
|
||||
'settings.fields.unlockTickets.name': 'Unlock All Tickets',
|
||||
'settings.fields.unlockTickets.desc': 'Infinite map/ex tickets (Note: maimai still limits which tickets can be used).',
|
||||
'settings.fields.waccaInfiniteWp.name': 'Wacca: Infinite WP',
|
||||
'settings.fields.waccaInfiniteWp.desc': 'Set WP to 999999',
|
||||
'settings.fields.waccaAlwaysVip.name': 'Wacca: Always VIP',
|
||||
'settings.fields.waccaAlwaysVip.desc': 'Set VIP expiration date to 2077-01-01',
|
||||
'settings.fields.mai2UnlockMusic.name': 'Unlock All Music',
|
||||
'settings.fields.mai2UnlockMusic.desc': 'Unlock all music and master difficulty.',
|
||||
'settings.fields.mai2UnlockChara.name': 'Unlock All Characters',
|
||||
'settings.fields.mai2UnlockChara.desc': 'Unlock all characters (new characters start at level 1).',
|
||||
'settings.fields.mai2UnlockCharaMaxLevel.name': 'Max Character Level',
|
||||
'settings.fields.mai2UnlockCharaMaxLevel.desc': 'Set all characters to max level.',
|
||||
'settings.fields.mai2UnlockPartners.name': 'Unlock All Partners',
|
||||
'settings.fields.mai2UnlockPartners.desc': 'Unlock all partners.',
|
||||
'settings.fields.mai2UnlockCollectables.name': 'Unlock All Collectables',
|
||||
'settings.fields.mai2UnlockCollectables.desc': 'Unlock all collectables (nameplate, title, icon, frame).',
|
||||
'settings.fields.mai2UnlockTickets.name': 'Unlock All Tickets',
|
||||
'settings.fields.mai2UnlockTickets.desc': 'Infinite tickets (Note: client still limits which tickets can be used).',
|
||||
'settings.fields.waccaUnlockMusic.name': 'Unlock All Music',
|
||||
'settings.fields.waccaUnlockMusic.desc': 'Unlock all music.',
|
||||
'settings.fields.waccaUnlockPlates.name': 'Unlock All Plates',
|
||||
'settings.fields.waccaUnlockPlates.desc': 'Unlock all plates.',
|
||||
'settings.fields.waccaUnlockCollectables.name': 'Unlock All Collectables',
|
||||
'settings.fields.waccaUnlockCollectables.desc': 'Unlock all collectables (icon, trophy).',
|
||||
'settings.fields.waccaUnlockTickets.name': 'Infinite Tickets',
|
||||
'settings.fields.waccaUnlockTickets.desc': 'Infinite tickets.',
|
||||
'settings.fields.waccaInfiniteWp.name': 'Infinite WP',
|
||||
'settings.fields.waccaInfiniteWp.desc': 'Set WP to 999999.',
|
||||
'settings.fields.waccaAlwaysVip.name': 'Always VIP',
|
||||
'settings.fields.waccaAlwaysVip.desc': 'Set VIP expiration date to 2077-01-01.',
|
||||
'settings.fields.chusanTeamName.name': 'Team Name',
|
||||
'settings.fields.chusanTeamName.desc': 'Customize the text displayed on the top of your profile.',
|
||||
'settings.fields.chusanInfinitePenguins.name': 'Infinite Penguins',
|
||||
|
||||
@@ -161,18 +161,30 @@ const zhSettings: typeof EN_REF_SETTINGS = {
|
||||
'settings.tabs.mai2': '舞萌',
|
||||
'settings.tabs.ongeki': '音击',
|
||||
'settings.tabs.wacca': '华卡',
|
||||
'settings.fields.unlockMusic.name': '解锁谱面',
|
||||
'settings.fields.unlockMusic.desc': '在游戏中解锁所有曲目和大师难度谱面。',
|
||||
'settings.fields.unlockChara.name': '解锁角色',
|
||||
'settings.fields.unlockChara.desc': '在游戏中解锁所有角色、语音和伙伴。',
|
||||
'settings.fields.unlockCollectables.name': '解锁收藏品',
|
||||
'settings.fields.unlockCollectables.desc': '在游戏中解锁所有收藏品(名牌、称号、图标、背景图)。',
|
||||
'settings.fields.unlockTickets.name': '解锁游戏券',
|
||||
'settings.fields.unlockTickets.desc': '无限跑图券/解锁券(注:maimai 客户端仍限制一些券不能使用)。',
|
||||
'settings.fields.waccaInfiniteWp.name': '华卡:无限 WP',
|
||||
'settings.fields.waccaInfiniteWp.desc': '将 WP 设置为 999999',
|
||||
'settings.fields.waccaAlwaysVip.name': '华卡:永久会员',
|
||||
'settings.fields.waccaAlwaysVip.desc': '将 VIP 到期时间设置为 2077-01-01',
|
||||
'settings.fields.mai2UnlockMusic.name': '解锁谱面',
|
||||
'settings.fields.mai2UnlockMusic.desc': '解锁所有曲目和大师难度谱面。',
|
||||
'settings.fields.mai2UnlockChara.name': '解锁角色',
|
||||
'settings.fields.mai2UnlockChara.desc': '解锁所有角色(新角色从 1 级开始)。',
|
||||
'settings.fields.mai2UnlockCharaMaxLevel.name': '角色满级',
|
||||
'settings.fields.mai2UnlockCharaMaxLevel.desc': '将所有角色设置为满级。',
|
||||
'settings.fields.mai2UnlockPartners.name': '解锁搭档',
|
||||
'settings.fields.mai2UnlockPartners.desc': '解锁所有搭档。',
|
||||
'settings.fields.mai2UnlockCollectables.name': '解锁收藏品',
|
||||
'settings.fields.mai2UnlockCollectables.desc': '解锁所有收藏品(姓名框、称号、头像、背景)。',
|
||||
'settings.fields.mai2UnlockTickets.name': '解锁功能票',
|
||||
'settings.fields.mai2UnlockTickets.desc': '无限功能票(注:客户端仍限制一些功能票不能使用)。',
|
||||
'settings.fields.waccaUnlockMusic.name': '解锁谱面',
|
||||
'settings.fields.waccaUnlockMusic.desc': '解锁所有曲目。',
|
||||
'settings.fields.waccaUnlockPlates.name': '解锁铭牌',
|
||||
'settings.fields.waccaUnlockPlates.desc': '解锁所有铭牌。',
|
||||
'settings.fields.waccaUnlockCollectables.name': '解锁收藏品',
|
||||
'settings.fields.waccaUnlockCollectables.desc': '解锁所有收藏品。',
|
||||
'settings.fields.waccaUnlockTickets.name': '无限解锁券',
|
||||
'settings.fields.waccaUnlockTickets.desc': '无限解锁券。',
|
||||
'settings.fields.waccaInfiniteWp.name': '无限 WP',
|
||||
'settings.fields.waccaInfiniteWp.desc': '将 WP 设置为 999999。',
|
||||
'settings.fields.waccaAlwaysVip.name': '永久会员',
|
||||
'settings.fields.waccaAlwaysVip.desc': '将 VIP 到期时间设置为 2077-01-01。',
|
||||
'settings.fields.chusanTeamName.name': '队伍名称',
|
||||
'settings.fields.chusanTeamName.desc': '自定义显示在个人资料顶部的文本。',
|
||||
'settings.fields.chusanInfinitePenguins.name': '我是桐谷遥',
|
||||
|
||||
@@ -99,9 +99,6 @@
|
||||
state = 'verify'
|
||||
verifyMsg = t("welcome.verify-state-2")
|
||||
}
|
||||
else if (e.message === 'Login not allowed: Card has been migrated to Minato.') {
|
||||
location.href = `https://portal.mumur.net/login?username=${encodeURIComponent(email)}`
|
||||
}
|
||||
else {
|
||||
error = e.message
|
||||
submitting = false // unnecessary? see line 113, same for both reset functions
|
||||
|
||||
@@ -15,6 +15,7 @@ import kotlinx.coroutines.withContext
|
||||
import org.apache.tika.Tika
|
||||
import org.apache.tika.mime.MimeTypes
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.context.ApplicationContext
|
||||
import org.springframework.http.HttpHeaders
|
||||
import org.springframework.http.HttpStatus
|
||||
import org.springframework.http.ResponseEntity.BodyBuilder
|
||||
@@ -34,8 +35,10 @@ import java.util.concurrent.locks.Lock
|
||||
import kotlin.reflect.KCallable
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.reflect.KMutableProperty1
|
||||
import kotlin.reflect.full.declaredMemberProperties
|
||||
import kotlin.reflect.full.isSubclassOf
|
||||
import kotlin.reflect.full.memberProperties
|
||||
import kotlin.reflect.jvm.javaField
|
||||
import kotlin.reflect.jvm.jvmErasure
|
||||
|
||||
typealias RP = RequestParam
|
||||
@@ -80,7 +83,9 @@ annotation class SettingField(
|
||||
|
||||
// Reflection
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun <T : Any> KClass<T>.vars() = memberProperties.mapNotNull { it as? Var<T, Any> }
|
||||
fun <T : Any> KClass<T>.ownVars() = declaredMemberProperties.sortedBy { it.javaField?.declaringClass?.declaredFields?.indexOf(it.javaField) ?: Int.MAX_VALUE }.mapNotNull { it as? Var<T, Any> }
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun <T : Any> KClass<T>.vars(): List<Var<T, Any>> = supertypes.mapNotNull { it.classifier as? KClass<*> }.filter { !it.java.isInterface }.flatMap{ it.vars() as List<Var<T, Any>> } + ownVars()
|
||||
fun <T : Any> KClass<T>.varsMap() = vars().associateBy { it.name }
|
||||
fun <T : Any> KClass<T>.getters() = java.methods.filter { it.name.startsWith("get") }
|
||||
fun <T : Any> KClass<T>.gettersMap() = getters().associateBy { it.name.removePrefix("get").firstCharLower() }
|
||||
@@ -264,3 +269,6 @@ val <S> Pair<*, S>.r get() = component2()
|
||||
val Query.exec get() = resultList.map { (it as Array<*>).toList() }
|
||||
fun List<List<Any?>>.numCsv(vararg head: Str) = head.joinToString(",") + "\n" +
|
||||
joinToString("\n") { it.joinToString(",") }
|
||||
|
||||
// DI
|
||||
inline fun <reified T> ApplicationContext.lazy() = lazy { getBean(T::class.java) }
|
||||
|
||||
@@ -21,15 +21,15 @@ val JSON_FUZZY_BOOLEAN = SimpleModule().addDeserializer(Boolean::class.java, obj
|
||||
else -> 400 - "Invalid boolean value ${parser.text}"
|
||||
}
|
||||
})
|
||||
val JSON_DATETIME = SimpleModule().addDeserializer(java.time.LocalDateTime::class.java, object : JsonDeserializer<java.time.LocalDateTime>() {
|
||||
val JSON_DATETIME = SimpleModule().addDeserializer(java.time.LocalDateTime::class.java, object : JsonDeserializer<LocalDateTime>() {
|
||||
override fun deserialize(parser: JsonParser, context: DeserializationContext) =
|
||||
// First try standard formats via asDateTime() method
|
||||
parser.text.asDateTime() ?: try {
|
||||
parser.text.takeIf { it.isNotEmpty() }?.run { asDateTime() ?: try {
|
||||
// Try maimai2 format (yyyy-MM-dd HH:mm:ss.0)
|
||||
LocalDateTime.parse(parser.text, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.0"))
|
||||
} catch (e: Exception) {
|
||||
400 - "Invalid date time value ${parser.text}"
|
||||
}
|
||||
} }
|
||||
})
|
||||
val JACKSON = jacksonObjectMapper().apply {
|
||||
setSerializationInclusion(JsonInclude.Include.NON_NULL)
|
||||
|
||||
@@ -101,8 +101,7 @@ class CardController(
|
||||
val games = migrate.split(',')
|
||||
cardGameService.migrate(card, games)
|
||||
|
||||
fedy.onCardLinked(card.luid, oldExtId = card.extId, ghostExtId = u.ghostCard.extId,
|
||||
games.map { Fedy.getGameName(it) }.filterNotNull())
|
||||
fedy.onCardLinked(card.luid, oldExtId = card.extId, ghostExtId = u.ghostCard.extId, games)
|
||||
|
||||
log.info("Net /card/link : Linked card ${card.id} to user ${u.username} and migrated data to ${games.joinToString()}")
|
||||
|
||||
@@ -207,7 +206,8 @@ class CardGameService(
|
||||
val diva: icu.samnyan.aqua.sega.diva.dao.userdata.PlayerProfileRepository,
|
||||
val safety: AquaNetSafetyService,
|
||||
val cardRepo: CardRepository,
|
||||
val em: EntityManager
|
||||
val em: EntityManager,
|
||||
val cardService: CardService
|
||||
) {
|
||||
companion object {
|
||||
val log = logger()
|
||||
@@ -225,7 +225,9 @@ class CardGameService(
|
||||
val remainingGames = dataRepos.keys.toMutableSet()
|
||||
games.forEach { game ->
|
||||
val dataRepo = dataRepos[game] ?: return@forEach
|
||||
migrateCard(game, dataRepo, cardRepo, crd)
|
||||
if (migrateCard(game, dataRepo, cardRepo, crd))
|
||||
// Update timestamp for the ghost card (data migrated in)
|
||||
cardService.updateCardTimestamp(crd.aquaUser!!.ghostCard, game, resetCreatedAt = true)
|
||||
remainingGames.remove(game)
|
||||
}
|
||||
// For remaining games, orphan the data by assigning them to a dummy card
|
||||
|
||||
@@ -8,6 +8,7 @@ import org.springframework.web.bind.annotation.RestController
|
||||
import java.security.MessageDigest
|
||||
import icu.samnyan.aqua.net.utils.SUCCESS
|
||||
import icu.samnyan.aqua.net.components.JWT
|
||||
import icu.samnyan.aqua.net.db.AquaGameOptions
|
||||
import icu.samnyan.aqua.net.db.AquaNetUser
|
||||
import icu.samnyan.aqua.net.db.AquaUserServices
|
||||
import icu.samnyan.aqua.net.games.mai2.Mai2Import
|
||||
@@ -27,7 +28,9 @@ import icu.samnyan.aqua.sega.general.model.Card
|
||||
import icu.samnyan.aqua.sega.general.service.CardService
|
||||
import icu.samnyan.aqua.sega.ongeki.OgkUserDataRepo
|
||||
import icu.samnyan.aqua.sega.wacca.model.db.WcUserRepo
|
||||
import org.springframework.context.ApplicationContext
|
||||
import org.springframework.web.multipart.MultipartFile
|
||||
import java.time.Instant
|
||||
import java.util.concurrent.CompletableFuture
|
||||
import kotlin.io.path.getLastModifiedTime
|
||||
import kotlin.io.path.isRegularFile
|
||||
@@ -41,11 +44,11 @@ class FedyProps {
|
||||
var remote: String = ""
|
||||
}
|
||||
|
||||
data class UserProfilePicture(val url: Str, val lastUpdatedMs: Long)
|
||||
data class UserProfilePicture(val url: Str, val updatedAtMs: Long)
|
||||
data class UserBasicInfo(
|
||||
val auId: Long, val ghostExtId: Long, val registrationTimeMs: Long,
|
||||
val username: Str, val displayName: Str, val email: Str, val passwordHash: Str, val profileBio: Str,
|
||||
val profilePicture: UserProfilePicture?,
|
||||
val profilePicture: UserProfilePicture?, val gameOptions: Map<Str, Any?>?,
|
||||
)
|
||||
|
||||
private data class UserUpdatedEvent(val user: UserBasicInfo, val isNewlyCreated: Bool)
|
||||
@@ -66,21 +69,23 @@ private data class FedyEvent(
|
||||
@API("/api/v2/fedy", consumes = ["multipart/form-data"])
|
||||
class Fedy(
|
||||
val jwt: JWT,
|
||||
val us: AquaUserServices,
|
||||
val emailProps: EmailProperties,
|
||||
val cardRepo: CardRepository,
|
||||
val cardService: CardService,
|
||||
val mai2Import: Mai2Import,
|
||||
val mai2UserDataRepo: Mai2UserDataRepo,
|
||||
val mai2UploadUserPlaylog: Mai2UploadUserPlaylogHandler,
|
||||
val mai2UpsertUserAll: Mai2UpsertUserAllHandler,
|
||||
val chu3UserDataRepo: Chu3UserDataRepo,
|
||||
val ongekiUserDataRepo: OgkUserDataRepo,
|
||||
val waccaUserDataRepo: WcUserRepo,
|
||||
val props: FedyProps,
|
||||
val paths: PathProps,
|
||||
val transactionManager: PlatformTransactionManager
|
||||
val transactionManager: PlatformTransactionManager,
|
||||
ctx: ApplicationContext
|
||||
) {
|
||||
val us by ctx.lazy<AquaUserServices>()
|
||||
val cardService by ctx.lazy<CardService>()
|
||||
val mai2Import by ctx.lazy<Mai2Import>()
|
||||
val mai2UploadUserPlaylog by ctx.lazy<Mai2UploadUserPlaylogHandler>()
|
||||
val mai2UpsertUserAll by ctx.lazy<Mai2UpsertUserAllHandler>()
|
||||
|
||||
val transaction by lazy { TransactionTemplate(transactionManager) }
|
||||
|
||||
private fun Str.checkKey() {
|
||||
@@ -127,7 +132,7 @@ class Fedy(
|
||||
} caught { UserRegisterRes(error = it) }
|
||||
}
|
||||
|
||||
data class UserUpdateReq(val auId: Long, val fields: Map<Str, Str?>?)
|
||||
data class UserUpdateReq(val auId: Long, val fields: Map<Str, Str?>?, val gameOptions: Map<Str, Any?>?)
|
||||
data class UserUpdateRes(val error: FedyErr? = null, val user: UserBasicInfo? = null)
|
||||
@API("/user/update")
|
||||
fun handleUserUpdate(@RH(KEY_HEADER) key: Str, @RT(REQ_PART) req: UserUpdateReq, @RT(PFP_PART) pfpFile: MultipartFile?): UserUpdateRes = handleFedy(key) {
|
||||
@@ -138,12 +143,16 @@ class Fedy(
|
||||
if (k == "email") { ru.email = us.validateEmail(v) }
|
||||
else us.update(ru, k, v)
|
||||
}
|
||||
pfpFile?.run {
|
||||
pfpFile?.apply {
|
||||
val mime = TIKA.detect(pfpFile.bytes).takeIf { it.startsWith("image/") } ?: (400 - "Invalid file type")
|
||||
val name = "${ru.auId}${MIMES.forName(mime)?.extension ?: ".jpg"}"
|
||||
(paths.aquaNetPortrait.path() / name).writeBytes(bytes)
|
||||
ru.profilePicture = name
|
||||
}
|
||||
req.gameOptions?.apply {
|
||||
val options = ru.gameOptions ?: AquaGameOptions().also { ru.gameOptions = it }
|
||||
forEach { (k, v) -> v?.let { GAME_OPTIONS_FIELDS[k]?.set(options, it) } }
|
||||
}
|
||||
us.userRepo.save(ru)
|
||||
if (fields.containsKey("pwHash") ?: false) { us.clearAllSessions(ru) }
|
||||
UserUpdateRes(user = ru.fedyBasicInfo())
|
||||
@@ -157,25 +166,31 @@ class Fedy(
|
||||
?.let { paths.aquaNetPortrait.path() / it }?.takeIf { it.isRegularFile() }
|
||||
?.let { UserProfilePicture(
|
||||
url = "/uploads/net/portrait/${profilePicture}",
|
||||
lastUpdatedMs = it.getLastModifiedTime().toMillis()
|
||||
) }
|
||||
updatedAtMs = it.getLastModifiedTime().toMillis()
|
||||
) },
|
||||
gameOptions?.let { o -> GAME_OPTIONS_FIELDS.mapValues { it.value.get(o) } }
|
||||
)
|
||||
|
||||
data class DataPullReq(val extId: Long, val game: Str, val exportOptions: ExportOptions)
|
||||
data class DataPullRes(val error: FedyErr? = null, val result: Any? = null)
|
||||
data class DataPullReq(val extId: Long, val game: Str, val createdAtMs: Long, val updatedAtMs: Long, val exportOptions: ExportOptions)
|
||||
data class DataPullResult(val data: Any?, val createdAtMs: Long, val updatedAtMs: Long, val isRebased: Bool)
|
||||
data class DataPullRes(val error: FedyErr? = null, val result: DataPullResult? = null)
|
||||
@API("/data/pull")
|
||||
fun handleDataPull(@RH(KEY_HEADER) key: Str, @RT(REQ_PART) req: DataPullReq): DataPullRes = handleFedy(key) {
|
||||
val card = cardRepo.findByExtId(req.extId).orElse(null)
|
||||
?: (404 - "Card with extId ${req.extId} not found")
|
||||
val cardTimestamp = cardService.getCardTimestamp(card, req.game)
|
||||
if (cardTimestamp.updatedAt.toEpochMilli() == req.updatedAtMs) return@handleFedy DataPullRes(error = null, result = null) // No changes
|
||||
val isRebased = req.createdAtMs > 0 && cardTimestamp.createdAt.toEpochMilli() > req.createdAtMs
|
||||
val exportOptions = if (!isRebased) { req.exportOptions } else { req.exportOptions.copy(playlogAfter = null) }
|
||||
{
|
||||
DataPullRes(result = when (req.game) {
|
||||
"mai2" -> mai2Import.export(card, req.exportOptions)
|
||||
DataPullRes(result = DataPullResult(data = when (req.game) {
|
||||
"mai2" -> mai2Import.export(card, exportOptions)
|
||||
else -> 406 - "Unsupported game"
|
||||
})
|
||||
}, createdAtMs = cardTimestamp.createdAt.toEpochMilli(), updatedAtMs = cardTimestamp.updatedAt.toEpochMilli(), isRebased = isRebased))
|
||||
} caught { DataPullRes(error = it) }
|
||||
}
|
||||
|
||||
data class DataPushReq(val extId: Long, val game: Str, val data: JDict, val removeOldData: Bool)
|
||||
data class DataPushReq(val extId: Long, val game: Str, val data: JDict, val removeOldData: Bool, val updatedAtMs: Long)
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
@API("/data/push")
|
||||
fun handleDataPush(@RH(KEY_HEADER) key: Str, @RT(REQ_PART) req: DataPushReq): Any = handleFedy(key) {
|
||||
@@ -188,6 +203,7 @@ class Fedy(
|
||||
repo.flush()
|
||||
}
|
||||
}
|
||||
val card = cardRepo.findByExtId(extId).orElse(null) ?: (404 - "Card not found")
|
||||
transaction.execute { when (req.game) {
|
||||
"mai2" -> {
|
||||
if (req.removeOldData) { removeOldData(mai2UserDataRepo) }
|
||||
@@ -198,7 +214,7 @@ class Fedy(
|
||||
}
|
||||
else -> 406 - "Unsupported game"
|
||||
} }
|
||||
|
||||
cardService.updateCardTimestamp(card, req.game, now = Instant.ofEpochMilli(req.updatedAtMs), resetCreatedAt = req.removeOldData)
|
||||
SUCCESS
|
||||
}
|
||||
|
||||
@@ -221,9 +237,9 @@ class Fedy(
|
||||
var pairedCard = cardService.tryLookup(req.pairedLuid)?.maybeGhost()
|
||||
if (pairedCard?.extId != card?.extId) {
|
||||
var isGhost = pairedCard?.isGhost == true
|
||||
var isFresh = pairedCard != null && isCardFresh(pairedCard)
|
||||
if (isGhost && isFresh) isPairedLuidDiverged = true
|
||||
else if (!isGhost && card?.isGhost == true) {
|
||||
var isNonFresh = pairedCard != null && !isCardFresh(pairedCard)
|
||||
if (isGhost || isNonFresh) isPairedLuidDiverged = true
|
||||
else if (card?.isGhost == true) {
|
||||
// Ensure paired card is linked, if the main card is linked
|
||||
// If the main card is not linked, there's nothing Fedy can do. It's Fedy's best effort.
|
||||
if (pairedCard == null) { pairedCard = cardService.registerByAccessCode(req.pairedLuid, card.aquaUser) }
|
||||
@@ -276,17 +292,16 @@ class Fedy(
|
||||
log.info("Fedy /card/unlink : Unlinked card ${card.id} (${card.luid}) from user ${cu.auId} (${cu.username})")
|
||||
}
|
||||
|
||||
fun onUserUpdated(u: AquaNetUser, isNew: Bool = false) = maybeNotifyAsync(FedyEvent(userUpdated = UserUpdatedEvent(u.fedyBasicInfo(), isNew)))
|
||||
fun onCardCreated(luid: Str, extId: Long) = maybeNotifyAsync(FedyEvent(cardCreated = CardCreatedEvent(luid, extId)))
|
||||
fun onCardLinked(luid: Str, oldExtId: Long?, ghostExtId: Long, migratedGames: List<Str>) = maybeNotifyAsync(FedyEvent(cardLinked = CardLinkedEvent(luid, oldExtId, ghostExtId, migratedGames)))
|
||||
fun onCardUnlinked(luid: Str) = maybeNotifyAsync(FedyEvent(cardUnlinked = CardUnlinkedEvent(luid)))
|
||||
fun onDataUpdated(extId: Long, game: Str, removeOldData: Bool) = maybeNotifyAsync({
|
||||
fun onUserUpdated(u: AquaNetUser, isNew: Bool = false) = maybeNotifyAsync { FedyEvent(userUpdated = UserUpdatedEvent(u.fedyBasicInfo(), isNew)) }
|
||||
fun onCardCreated(luid: Str, extId: Long) = maybeNotifyAsync { FedyEvent(cardCreated = CardCreatedEvent(luid, extId)) }
|
||||
fun onCardLinked(luid: Str, oldExtId: Long?, ghostExtId: Long, migratedGames: List<Str>) = maybeNotifyAsync { FedyEvent(cardLinked = CardLinkedEvent(luid, oldExtId, ghostExtId, migratedGames)) }
|
||||
fun onCardUnlinked(luid: Str) = maybeNotifyAsync { FedyEvent(cardUnlinked = CardUnlinkedEvent(luid)) }
|
||||
fun onDataUpdated(extId: Long, game: Str, removeOldData: Bool) = maybeNotifyAsync {
|
||||
val card = cardRepo.findByExtId(extId).orElse(null) ?: return@maybeNotifyAsync null // Card not found, nothing to do
|
||||
FedyEvent(dataUpdated = DataUpdatedEvent(extId, card.isGhost, game, removeOldData))
|
||||
})
|
||||
}
|
||||
|
||||
private fun maybeNotifyAsync(event: FedyEvent) = maybeNotifyAsync({ event })
|
||||
private fun maybeNotifyAsync(getEvent: () -> FedyEvent?) = if (!props.enabled && !suppressEvents.get()) {} else CompletableFuture.runAsync {
|
||||
private fun maybeNotifyAsync(getEvent: () -> FedyEvent?) = if (!props.enabled || suppressEvents.get()) {} else CompletableFuture.runAsync {
|
||||
var event: FedyEvent? = null
|
||||
try {
|
||||
event = getEvent()
|
||||
@@ -326,7 +341,7 @@ class Fedy(
|
||||
|
||||
// Apparently existing cards could possibly be fresh and never used in any game. Treat them as new cards.
|
||||
private fun isCardFresh(c: Card): Bool {
|
||||
fun <T : IUserData> checkForGame(repo: GenericUserDataRepo<T>, card: Card): Bool = repo.findByCard(card) == null
|
||||
fun <T : IUserData> checkForGame(repo: GenericUserDataRepo<T>, card: Card): Bool = repo.findByCard(card) != null
|
||||
return when {
|
||||
checkForGame(mai2UserDataRepo, c) -> false
|
||||
checkForGame(chu3UserDataRepo, c) -> false
|
||||
@@ -345,18 +360,12 @@ class Fedy(
|
||||
const val KEY_HEADER = "X-Fedy-Key"
|
||||
const val REQ_PART = "request"
|
||||
const val PFP_PART = "profilePicture"
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val GAME_OPTIONS_FIELDS = listOf(
|
||||
O::mai2UnlockMusic, O::mai2UnlockChara, O::mai2UnlockCharaMaxLevel, O::mai2UnlockPartners, O::mai2UnlockCollectables, O::mai2UnlockTickets
|
||||
).map { it as Var<O, Any?> }.associateBy { it.name }
|
||||
val log = logger()
|
||||
|
||||
fun getGameName(gameId: Str) = when (gameId) {
|
||||
"mai2" -> "mai2"
|
||||
"SDEZ" -> "mai2"
|
||||
"chu3" -> "chu3"
|
||||
"SDHD" -> "chu3"
|
||||
"ongeki" -> "mu3"
|
||||
"SDDT" -> "mu3"
|
||||
"wacca" -> "wacca"
|
||||
"SDFE" -> "wacca"
|
||||
else -> null // Not supported
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
typealias O = AquaGameOptions
|
||||
|
||||
@@ -14,7 +14,8 @@ import kotlin.reflect.jvm.jvmErasure
|
||||
class SettingsApi(
|
||||
val us: AquaUserServices,
|
||||
val userRepo: AquaNetUserRepo,
|
||||
val goRepo: AquaGameOptionsRepo
|
||||
val goRepo: AquaGameOptionsRepo,
|
||||
val fedy: Fedy
|
||||
) {
|
||||
// Get all params with SettingField annotation
|
||||
val fields = AquaGameOptions::class.vars()
|
||||
@@ -41,6 +42,6 @@ class SettingsApi(
|
||||
}
|
||||
// Check field type
|
||||
field.setCast(options, value)
|
||||
goRepo.save(options)
|
||||
goRepo.save(options).also { fedy.onUserUpdated(u) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,22 +3,15 @@ package icu.samnyan.aqua.net
|
||||
import ext.*
|
||||
import icu.samnyan.aqua.net.components.*
|
||||
import icu.samnyan.aqua.net.db.*
|
||||
import icu.samnyan.aqua.net.db.AquaUserServices.Companion.SETTING_FIELDS
|
||||
import icu.samnyan.aqua.net.utils.PathProps
|
||||
import icu.samnyan.aqua.net.utils.SUCCESS
|
||||
import icu.samnyan.aqua.sega.general.dao.CardRepository
|
||||
import icu.samnyan.aqua.sega.general.model.Card
|
||||
import icu.samnyan.aqua.sega.general.model.CardStatus
|
||||
import icu.samnyan.aqua.sega.general.service.CardService
|
||||
import jakarta.servlet.http.HttpServletRequest
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.context.annotation.Lazy
|
||||
import org.springframework.security.crypto.password.PasswordEncoder
|
||||
import org.springframework.web.bind.annotation.RestController
|
||||
import org.springframework.web.multipart.MultipartFile
|
||||
import java.time.Instant
|
||||
import java.time.LocalDateTime
|
||||
import kotlin.io.path.writeBytes
|
||||
|
||||
@RestController
|
||||
@@ -28,6 +21,7 @@ class UserRegistrar(
|
||||
val hasher: PasswordEncoder,
|
||||
val turnstileService: TurnstileService,
|
||||
val emailService: EmailService,
|
||||
val fedy: Fedy,
|
||||
val geoIP: GeoIP,
|
||||
val jwt: JWT,
|
||||
val confirmationRepo: EmailConfirmationRepo,
|
||||
@@ -37,7 +31,6 @@ class UserRegistrar(
|
||||
val emailProps: EmailProperties,
|
||||
final val paths: PathProps
|
||||
) {
|
||||
@Autowired @Lazy lateinit var fedy: Fedy
|
||||
val portraitPath = paths.aquaNetPortrait.path()
|
||||
|
||||
companion object {
|
||||
@@ -93,8 +86,6 @@ class UserRegistrar(
|
||||
?: (400 - "User not found")
|
||||
if (!hasher.matches(password, user.pwHash)) 400 - "Invalid password"
|
||||
|
||||
if (user.ghostCard.status == CardStatus.MIGRATED_TO_MINATO) 400 - "Login not allowed: Card has been migrated to Minato."
|
||||
|
||||
// Check if email is verified
|
||||
if (!user.emailConfirmed && emailProps.enable) {
|
||||
// Check if last confirmation email was sent within a minute
|
||||
|
||||
@@ -2,10 +2,7 @@ package icu.samnyan.aqua.net.db
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore
|
||||
import ext.SettingField
|
||||
import jakarta.persistence.Entity
|
||||
import jakarta.persistence.GeneratedValue
|
||||
import jakarta.persistence.GenerationType
|
||||
import jakarta.persistence.Id
|
||||
import jakarta.persistence.*
|
||||
import org.springframework.data.jpa.repository.JpaRepository
|
||||
|
||||
@Entity
|
||||
@@ -14,21 +11,29 @@ class AquaGameOptions(
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
var id: Long = 0,
|
||||
|
||||
@SettingField("general")
|
||||
var unlockMusic: Boolean = false,
|
||||
|
||||
@SettingField("general")
|
||||
var unlockChara: Boolean = false,
|
||||
|
||||
@SettingField("general")
|
||||
var unlockCollectables: Boolean = false,
|
||||
|
||||
@SettingField("general")
|
||||
var unlockTickets: Boolean = false,
|
||||
@SettingField("mai2") @Column(name = "mai2_unlock_music")
|
||||
var mai2UnlockMusic: Boolean = false,
|
||||
@SettingField("mai2") @Column(name = "mai2_unlock_chara")
|
||||
var mai2UnlockChara: Boolean = false,
|
||||
@SettingField("mai2") @Column(name = "mai2_unlock_chara_max_level")
|
||||
var mai2UnlockCharaMaxLevel: Boolean = false,
|
||||
@SettingField("mai2") @Column(name = "mai2_unlock_partners")
|
||||
var mai2UnlockPartners: Boolean = false,
|
||||
@SettingField("mai2") @Column(name = "mai2_unlock_collectables")
|
||||
var mai2UnlockCollectables: Boolean = false,
|
||||
@SettingField("mai2") @Column(name = "mai2_unlock_tickets")
|
||||
var mai2UnlockTickets: Boolean = false,
|
||||
|
||||
@SettingField("wacca")
|
||||
var waccaUnlockMusic: Boolean = false,
|
||||
@SettingField("wacca")
|
||||
var waccaUnlockPlates: Boolean = false,
|
||||
@SettingField("wacca")
|
||||
var waccaUnlockCollectables: Boolean = false,
|
||||
@SettingField("wacca")
|
||||
var waccaUnlockTickets: Boolean = false,
|
||||
@SettingField("wacca")
|
||||
var waccaInfiniteWp: Boolean = false,
|
||||
|
||||
@SettingField("wacca")
|
||||
var waccaAlwaysVip: Boolean = false,
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import icu.samnyan.aqua.net.BotProps
|
||||
import icu.samnyan.aqua.net.db.AquaUserServices
|
||||
import icu.samnyan.aqua.net.utils.SUCCESS
|
||||
import icu.samnyan.aqua.sega.general.model.Card
|
||||
import icu.samnyan.aqua.sega.general.model.CardStatus
|
||||
import icu.samnyan.aqua.sega.general.service.CardService
|
||||
import jakarta.annotation.PostConstruct
|
||||
import org.slf4j.LoggerFactory
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
@@ -30,6 +30,8 @@ abstract class GameApiController<T : IUserData>(val name: String, userDataClass:
|
||||
abstract val settableFields: Map<String, (T, String) -> Unit>
|
||||
open val gettableFields: Set<String> = setOf()
|
||||
|
||||
@Autowired lateinit var cardService: CardService
|
||||
|
||||
@API("trend")
|
||||
abstract suspend fun trend(@RP username: String): List<TrendOut>
|
||||
@API("user-summary")
|
||||
@@ -56,7 +58,7 @@ abstract class GameApiController<T : IUserData>(val name: String, userDataClass:
|
||||
|
||||
val reqUser = token?.let { us.jwt.auth(it) }?.let { u ->
|
||||
// Optimization: If the user is not banned, we don't need to process user information
|
||||
if (!u.ghostCard.rankingBanned && !u.cards.any { it.rankingBanned } && u.ghostCard.status == CardStatus.NORMAL) null
|
||||
if (!u.ghostCard.rankingBanned && !u.cards.any { it.rankingBanned } && u.ghostCard.status.isNormal) null
|
||||
else u
|
||||
}
|
||||
|
||||
@@ -139,6 +141,7 @@ abstract class GameApiController<T : IUserData>(val name: String, userDataClass:
|
||||
val user = async { userDataRepo.findByCard(u.ghostCard) } ?: (404 - "User not found")
|
||||
prop(user, value)
|
||||
async { userDataRepo.save(user) }
|
||||
cardService.updateCardTimestamp(u.ghostCard, name)
|
||||
SUCCESS
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import icu.samnyan.aqua.net.Fedy
|
||||
import icu.samnyan.aqua.net.utils.AquaNetProps
|
||||
import icu.samnyan.aqua.net.utils.SUCCESS
|
||||
import icu.samnyan.aqua.sega.general.model.Card
|
||||
import icu.samnyan.aqua.sega.general.service.CardService
|
||||
import org.springframework.beans.factory.annotation.Autowired
|
||||
import org.springframework.data.jpa.repository.JpaRepository
|
||||
import org.springframework.data.repository.NoRepositoryBean
|
||||
@@ -17,7 +18,6 @@ import java.util.*
|
||||
import kotlin.io.path.Path
|
||||
import kotlin.io.path.writeText
|
||||
import kotlin.reflect.KClass
|
||||
import org.springframework.context.annotation.Lazy
|
||||
|
||||
data class ExportOptions(
|
||||
val playlogAfter: String? = null
|
||||
@@ -50,6 +50,7 @@ interface IUserRepo<UserModel, ThisModel>: JpaRepository<ThisModel, Long> {
|
||||
* Import controller for a game
|
||||
*
|
||||
* @param game: 4-letter Game ID
|
||||
* @param gameName: mai2/chu3/ongeki
|
||||
* @param exportFields: Mapping of type names to variables in the export model
|
||||
* (e.g. "Mai2UserCharacter" -> Mai2DataExport::userCharacterList)
|
||||
* @param exportRepos: Mapping of variables to repositories that can be used to find the data
|
||||
@@ -57,6 +58,7 @@ interface IUserRepo<UserModel, ThisModel>: JpaRepository<ThisModel, Long> {
|
||||
*/
|
||||
abstract class ImportController<ExportModel: IExportClass<UserModel>, UserModel: IUserData>(
|
||||
val game: String,
|
||||
val gameName: String,
|
||||
val exportClass: KClass<ExportModel>,
|
||||
val exportFields: Map<String, Var<ExportModel, Any>>,
|
||||
val exportRepos: Map<Var<ExportModel, Any>, IUserRepo<UserModel, *>>,
|
||||
@@ -71,7 +73,7 @@ abstract class ImportController<ExportModel: IExportClass<UserModel>, UserModel:
|
||||
@Autowired lateinit var netProps: AquaNetProps
|
||||
@Autowired lateinit var transManager: PlatformTransactionManager
|
||||
val trans by lazy { TransactionTemplate(transManager) }
|
||||
@Autowired @Lazy lateinit var fedy: Fedy
|
||||
@Autowired lateinit var cardService: CardService
|
||||
|
||||
init {
|
||||
artemisRenames.values.forEach {
|
||||
@@ -148,7 +150,7 @@ abstract class ImportController<ExportModel: IExportClass<UserModel>, UserModel:
|
||||
}
|
||||
}
|
||||
|
||||
Fedy.getGameName(game)?.let { fedy.onDataUpdated(u.ghostCard.extId, it, true) }
|
||||
cardService.updateCardTimestamp(u.ghostCard, gameName, resetCreatedAt = true)
|
||||
|
||||
SUCCESS
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ import kotlin.reflect.full.declaredMembers
|
||||
class Chu3Import(
|
||||
val repos: Chu3Repos,
|
||||
) : ImportController<Chu3DataExport, Chu3UserData>(
|
||||
"SDHD", Chu3DataExport::class,
|
||||
"SDHD", "chu3", Chu3DataExport::class,
|
||||
exportFields = Chu3DataExport::class.vars().associateBy {
|
||||
it.name.replace("List", "").lowercase()
|
||||
},
|
||||
|
||||
@@ -19,7 +19,7 @@ import kotlin.reflect.full.declaredMembers
|
||||
class Mai2Import(
|
||||
val repos: Mai2Repos,
|
||||
) : ImportController<Maimai2DataExport, Mai2UserDetail>(
|
||||
"SDEZ", Maimai2DataExport::class,
|
||||
"SDEZ", "mai2", Maimai2DataExport::class,
|
||||
exportFields = Maimai2DataExport::class.vars().associateBy {
|
||||
it.name.replace("List", "").lowercase()
|
||||
},
|
||||
|
||||
@@ -3,6 +3,7 @@ package icu.samnyan.aqua.net.games.mai2
|
||||
import ext.*
|
||||
import icu.samnyan.aqua.net.db.AquaUserServices
|
||||
import icu.samnyan.aqua.net.utils.SUCCESS
|
||||
import icu.samnyan.aqua.sega.general.service.CardService
|
||||
import icu.samnyan.aqua.sega.maimai2.model.Mai2Repos
|
||||
import icu.samnyan.aqua.sega.maimai2.model.userdata.Mai2UserMusicDetail
|
||||
import org.springframework.web.bind.annotation.PostMapping
|
||||
@@ -13,6 +14,7 @@ import org.springframework.web.bind.annotation.RestController
|
||||
class Mai2MusicDetailImport(
|
||||
val us: AquaUserServices,
|
||||
val repos: Mai2Repos,
|
||||
val cardService: CardService,
|
||||
) {
|
||||
@PostMapping("import-music-detail")
|
||||
suspend fun importMusicDetail(@RP token: String, @RB data: List<Mai2UserMusicDetail>) = us.jwt.auth(token) { u ->
|
||||
@@ -39,6 +41,7 @@ class Mai2MusicDetailImport(
|
||||
}
|
||||
}
|
||||
repos.userMusicDetail.saveAll(data)
|
||||
cardService.updateCardTimestamp(card, "mai2")
|
||||
SUCCESS
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,6 +110,7 @@ class Maimai2(
|
||||
val user = userDataRepo.findByCard(card) ?: (404 - "User not found")
|
||||
user.userName = newNameFull
|
||||
userDataRepo.save(user)
|
||||
cardService.updateCardTimestamp(card, "mai2")
|
||||
}
|
||||
mapOf("newName" to newNameFull)
|
||||
}
|
||||
@@ -139,6 +140,7 @@ class Maimai2(
|
||||
loginBonus.add(newBonus)
|
||||
}
|
||||
repos.userLoginBonus.saveAll(loginBonus)
|
||||
cardService.updateCardTimestamp(card, "mai2")
|
||||
}
|
||||
SUCCESS
|
||||
}
|
||||
@@ -172,6 +174,7 @@ class Maimai2(
|
||||
|
||||
myRival.propertyValue = myRivalList.joinToString(",")
|
||||
repos.userGeneralData.save(myRival)
|
||||
cardService.updateCardTimestamp(myCard, "mai2")
|
||||
}
|
||||
SUCCESS
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import icu.samnyan.aqua.sega.chusan.model.Chu3Repos
|
||||
import icu.samnyan.aqua.sega.general.GameMusicPopularity
|
||||
import icu.samnyan.aqua.sega.general.MeowApi
|
||||
import icu.samnyan.aqua.sega.general.RequestContext
|
||||
import icu.samnyan.aqua.sega.general.service.CardService
|
||||
import icu.samnyan.aqua.sega.util.jackson.BasicMapper
|
||||
import icu.samnyan.aqua.sega.util.jackson.StringMapper
|
||||
import icu.samnyan.aqua.spring.Metrics
|
||||
@@ -29,6 +30,7 @@ class ChusanController(
|
||||
val cmMapper: BasicMapper,
|
||||
val db: Chu3Repos,
|
||||
val us: AquaUserServices,
|
||||
val cardService: CardService,
|
||||
val versionHelper: ChusanVersionHelper,
|
||||
val props: ChusanProps,
|
||||
val pop: GameMusicPopularity,
|
||||
|
||||
@@ -236,9 +236,7 @@ fun ChusanController.chusanInit() {
|
||||
) + userDict
|
||||
|
||||
if (user.card?.status == CardStatus.MIGRATED_TO_MINATO) {
|
||||
res["userName"] = "JiaQQqun / ChangeDNS"
|
||||
res["rating"] = 0
|
||||
res["playerLevel"] = 0
|
||||
res["userName"] = "${res["userName"]}@AquaDX"
|
||||
}
|
||||
|
||||
res
|
||||
@@ -394,13 +392,6 @@ fun ChusanController.chusanInit() {
|
||||
// }
|
||||
// process()
|
||||
|
||||
val user = db.userData.findByCard_ExtId(uid)()
|
||||
|
||||
if (user?.card?.status == CardStatus.MIGRATED_TO_MINATO) {
|
||||
"""{"returnCode":"0"}"""
|
||||
}
|
||||
else {
|
||||
"""{"returnCode":"1"}"""
|
||||
}
|
||||
"""{"returnCode":"1"}"""
|
||||
}
|
||||
}
|
||||
@@ -75,6 +75,8 @@ fun ChusanController.cmApiInit() {
|
||||
)
|
||||
}
|
||||
|
||||
u.card?.let { cardService.updateCardTimestamp(it, "chu3") }
|
||||
|
||||
mapOf(
|
||||
"returnCode" to 1,
|
||||
"apiName" to "CMUpsertUserGachaApi",
|
||||
@@ -85,13 +87,15 @@ fun ChusanController.cmApiInit() {
|
||||
"CMUpsertUserPrintCancel" {
|
||||
val orderIdList: List<Long> = cmMapper.convert<List<Long>>(parsing { data["orderIdList"]!! })
|
||||
|
||||
db.userCardPrintState.saveAll(orderIdList.mapNotNull {
|
||||
val states = 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
|
||||
}
|
||||
})
|
||||
|
||||
states.firstOrNull()?.user?.card?.let { cardService.updateCardTimestamp(it, "chu3") }
|
||||
|
||||
mapOf("returnCode" to 1, "apiName" to "CMUpsertUserPrintCancelApi")
|
||||
}
|
||||
|
||||
@@ -114,6 +118,8 @@ fun ChusanController.cmApiInit() {
|
||||
db.userCardPrintState.save(this)
|
||||
}
|
||||
|
||||
u.card?.let { cardService.updateCardTimestamp(it, "chu3") }
|
||||
|
||||
mapOf("returnCode" to 1, "apiName" to "CMUpsertUserPrintSubtractApi")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import ext.*
|
||||
import icu.samnyan.aqua.sega.chusan.ChusanController
|
||||
import icu.samnyan.aqua.sega.chusan.model.request.Chu3UserAll
|
||||
import icu.samnyan.aqua.sega.chusan.model.userdata.*
|
||||
import icu.samnyan.aqua.sega.general.model.CardStatus
|
||||
import icu.samnyan.aqua.sega.general.model.response.UserRecentRating
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
@@ -13,6 +14,7 @@ fun ChusanController.upsertApiInit() {
|
||||
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)
|
||||
charge.user.card?.let { cardService.updateCardTimestamp(it, "chu3") }
|
||||
"""{"returnCode":"1"}"""
|
||||
}
|
||||
|
||||
@@ -36,6 +38,12 @@ fun ChusanController.upsertApiInit() {
|
||||
userNameEx = ""
|
||||
}.also { db.userData.saveAndFlush(it) }
|
||||
|
||||
// If the user was previously migrated to Minato, saving would mark them "migrated and then cleared".
|
||||
if (u.card?.status == CardStatus.MIGRATED_TO_MINATO) {
|
||||
u.card?.status = CardStatus.NORMAL_MIGRATED_TO_MINATO_AND_THEN_CLEARED
|
||||
us.cardRepo.save(u.card!!)
|
||||
}
|
||||
|
||||
// Only save if it is a valid region and the user has played at least a song
|
||||
req.userPlaylogList?.firstOrNull()?.regionId?.let { rid ->
|
||||
val region = db.userRegions.findByUserAndRegionId(u, rid)?.apply {
|
||||
@@ -185,8 +193,10 @@ fun ChusanController.upsertApiInit() {
|
||||
}.also { db.userCMissionProgress.save(it) }
|
||||
}
|
||||
}
|
||||
|
||||
u.card?.let { cardService.updateCardTimestamp(it, "chu3") }
|
||||
}
|
||||
|
||||
"""{"returnCode":1}"""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ enum class CardStatus {
|
||||
NORMAL,
|
||||
|
||||
// Reserved for future use
|
||||
NORMAL_RESERVED_1,
|
||||
NORMAL_MIGRATED_TO_MINATO_AND_THEN_CLEARED,
|
||||
NORMAL_RESERVED_2,
|
||||
NORMAL_RESERVED_3,
|
||||
NORMAL_RESERVED_4,
|
||||
@@ -22,7 +22,12 @@ enum class CardStatus {
|
||||
// Deleted statuses
|
||||
OVERWRITTEN,
|
||||
DELETED,
|
||||
MIGRATED_TO_MINATO,
|
||||
MIGRATED_TO_MINATO;
|
||||
|
||||
/**
|
||||
* Returns true if card status is in any NORMAL state
|
||||
*/
|
||||
val isNormal get() = this.ordinal in NORMAL.ordinal..NORMAL_RESERVED_9.ordinal
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
package icu.samnyan.aqua.sega.general.model
|
||||
|
||||
import ext.Str
|
||||
import jakarta.persistence.*
|
||||
import org.springframework.data.jpa.repository.JpaRepository
|
||||
import org.springframework.stereotype.Repository
|
||||
import java.time.Instant
|
||||
|
||||
@Entity(name = "SegaCardTimestamp")
|
||||
@Table(name = "sega_card_timestamp")
|
||||
class CardTimestamp(
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
var id: Long = 0,
|
||||
|
||||
@Column(nullable = false)
|
||||
var createdAt: Instant = Instant.now(),
|
||||
|
||||
@Column(nullable = false)
|
||||
var updatedAt: Instant = Instant.now(),
|
||||
|
||||
var game: Str,
|
||||
|
||||
@ManyToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "card_id")
|
||||
var card: Card? = null,
|
||||
)
|
||||
|
||||
@Repository
|
||||
interface CardTimestampRepo : JpaRepository<CardTimestamp, Long> {
|
||||
fun findByCardIdAndGame(cardId: Long, game: Str): CardTimestamp?
|
||||
}
|
||||
@@ -1,10 +1,16 @@
|
||||
package icu.samnyan.aqua.sega.general.service
|
||||
|
||||
import ext.Bool
|
||||
import ext.Str
|
||||
import ext.minus
|
||||
import icu.samnyan.aqua.net.Fedy
|
||||
import icu.samnyan.aqua.net.db.AquaNetUser
|
||||
import icu.samnyan.aqua.sega.general.dao.CardRepository
|
||||
import icu.samnyan.aqua.sega.general.model.Card
|
||||
import icu.samnyan.aqua.sega.general.model.CardTimestamp
|
||||
import icu.samnyan.aqua.sega.general.model.CardTimestampRepo
|
||||
import org.springframework.stereotype.Service
|
||||
import java.time.Instant
|
||||
import java.time.LocalDateTime
|
||||
import java.util.*
|
||||
import java.util.concurrent.ThreadLocalRandom
|
||||
@@ -14,7 +20,7 @@ import kotlin.jvm.optionals.getOrNull
|
||||
* @author samnyan (privateamusement@protonmail.com)
|
||||
*/
|
||||
@Service
|
||||
class CardService(val cardRepo: CardRepository)
|
||||
class CardService(val cardRepo: CardRepository, val cardTimestampRepo: CardTimestampRepo, val fedy: Fedy)
|
||||
{
|
||||
/**
|
||||
* Find a card by External ID
|
||||
@@ -106,4 +112,13 @@ class CardService(val cardRepo: CardRepository)
|
||||
}
|
||||
return eid
|
||||
}
|
||||
|
||||
fun getCardTimestamp(card: Card, game: Str, now: Instant = Instant.now()) =
|
||||
cardTimestampRepo.findByCardIdAndGame(card.id, game) ?: CardTimestamp(game = game, card = card, createdAt = now, updatedAt = now);
|
||||
|
||||
fun updateCardTimestamp(card: Card, game: Str, now: Instant = Instant.now(), resetCreatedAt: Bool = false) {
|
||||
cardTimestampRepo.save(getCardTimestamp(card, game, now).apply { updatedAt = now }
|
||||
.apply { if (resetCreatedAt) createdAt = now });
|
||||
fedy.onDataUpdated(card.extId, game, resetCreatedAt)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,10 +115,7 @@ fun Maimai2ServletController.initApis() {
|
||||
)
|
||||
|
||||
if (d.card?.status == CardStatus.MIGRATED_TO_MINATO) {
|
||||
res["userName"] = "JiaQQqun / ChangeDNS"
|
||||
res["dispRate"] = 1
|
||||
res["playerRating"] = 66564
|
||||
res["totalAwake"] = 7114
|
||||
res["userName"] = "${res["userName"]}@AquaDX"
|
||||
}
|
||||
|
||||
res
|
||||
@@ -134,10 +131,6 @@ fun Maimai2ServletController.initApis() {
|
||||
"Bearer" to "meow", "bearer" to "meow"
|
||||
)
|
||||
|
||||
if (d?.card?.status == CardStatus.MIGRATED_TO_MINATO) {
|
||||
res["returnCode"] = 0
|
||||
}
|
||||
|
||||
// Get regionId from request
|
||||
val region = data["regionId"] as? Int
|
||||
|
||||
@@ -150,6 +143,7 @@ fun Maimai2ServletController.initApis() {
|
||||
regionId = region
|
||||
}
|
||||
db.userRegions.save(region)
|
||||
// d.card?.let { cardService.updateCardTimestamp(it, "mai2") } // TODO: why save regions on login?
|
||||
}
|
||||
|
||||
res
|
||||
@@ -231,12 +225,16 @@ fun Maimai2ServletController.initApis() {
|
||||
// Kaleidoscope, added on 1.50
|
||||
// [{gateId, phaseId}]
|
||||
"GetGameKaleidxScope" { mapOf("gameKaleidxScopeList" to ls(
|
||||
mapOf("gateId" to 1, "phaseId" to findPhase(LocalDate.of(2025, 1, 18))),
|
||||
mapOf("gateId" to 2, "phaseId" to 2),
|
||||
mapOf("gateId" to 3, "phaseId" to 2),
|
||||
mapOf("gateId" to 4, "phaseId" to findPhase(LocalDate.of(2025, 2, 25))),
|
||||
mapOf("gateId" to 5, "phaseId" to 2),
|
||||
mapOf("gateId" to 6, "phaseId" to 2),
|
||||
mapOf("gateId" to 1, "phaseId" to 6),
|
||||
mapOf("gateId" to 2, "phaseId" to 6),
|
||||
mapOf("gateId" to 3, "phaseId" to 6),
|
||||
mapOf("gateId" to 4, "phaseId" to 6),
|
||||
mapOf("gateId" to 5, "phaseId" to 6),
|
||||
mapOf("gateId" to 6, "phaseId" to 6),
|
||||
mapOf("gateId" to 7, "phaseId" to 6),
|
||||
mapOf("gateId" to 8, "phaseId" to 6),
|
||||
mapOf("gateId" to 9, "phaseId" to 6),
|
||||
mapOf("gateId" to 10, "phaseId" to 13),
|
||||
)) }
|
||||
// Request: {userId}
|
||||
// Response: {userId, userKaleidxScopeList}
|
||||
|
||||
@@ -40,9 +40,6 @@ class Maimai2ServletController(
|
||||
val db: Mai2Repos,
|
||||
val net: Maimai2,
|
||||
): MeowApi(serialize = { _, resp -> if (resp is String) resp else resp.toJson() }) {
|
||||
|
||||
@Autowired @Lazy lateinit var fedy: Fedy
|
||||
|
||||
companion object {
|
||||
private val log = logger()
|
||||
private val empty = listOf<Any>()
|
||||
@@ -95,7 +92,6 @@ class Maimai2ServletController(
|
||||
val ctx = RequestContext(req, data.mut)
|
||||
serialize(api, handlers[api]!!(ctx) ?: noop).also {
|
||||
log.info("$token : $api > ${it.truncate(500)}")
|
||||
if (api == "UpsertUserAllApi") { data["userId"]?.long?.let { fedy.onDataUpdated(it, "mai2", false) } }
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
package icu.samnyan.aqua.sega.maimai2.handler
|
||||
|
||||
import ext.int
|
||||
import ext.logger
|
||||
import ext.mapApply
|
||||
import icu.samnyan.aqua.net.games.mai2.Maimai2
|
||||
import icu.samnyan.aqua.sega.general.BaseHandler
|
||||
import icu.samnyan.aqua.sega.general.dao.CardRepository
|
||||
import icu.samnyan.aqua.sega.maimai2.model.Mai2Repos
|
||||
import icu.samnyan.aqua.sega.maimai2.model.userdata.Mai2ItemKind
|
||||
import icu.samnyan.aqua.sega.maimai2.model.userdata.Mai2UserCharacter
|
||||
import org.springframework.stereotype.Component
|
||||
import kotlin.jvm.optionals.getOrNull
|
||||
|
||||
@@ -15,34 +18,25 @@ class GetUserCharacterHandler(
|
||||
val maimai2: Maimai2,
|
||||
val cardRepo: CardRepository,
|
||||
) : BaseHandler {
|
||||
val itemUnlock = maimai2.itemMapping[Mai2ItemKind.chara.name]?.map { mapOf(
|
||||
"characterId" to it.key,
|
||||
"level" to 9999,
|
||||
"awakening" to 1,
|
||||
"useCount" to 0
|
||||
) }
|
||||
val charaIds = maimai2.itemMapping[Mai2ItemKind.chara.name]?.map { it.key.int() } ?: emptyList()
|
||||
|
||||
init {
|
||||
if (itemUnlock.isNullOrEmpty()) logger.warn("Mai2 item info is empty")
|
||||
if (charaIds.isEmpty()) logger.warn("Mai2 item info is empty")
|
||||
}
|
||||
|
||||
override fun handle(request: Map<String, Any>): Any {
|
||||
val userId = (request["userId"] as Number).toLong()
|
||||
|
||||
// Aqua Net game unlock feature
|
||||
cardRepo.findByExtId(userId).getOrNull()?.aquaUser?.gameOptions?.let { opt ->
|
||||
if (!opt.unlockChara or itemUnlock.isNullOrEmpty()) return@let
|
||||
|
||||
logger.info("Response: ${itemUnlock!!.size} Characters - All unlock")
|
||||
return mapOf(
|
||||
"userId" to userId,
|
||||
"userCharacterList" to itemUnlock
|
||||
)
|
||||
}
|
||||
val gameOptions = cardRepo.findByExtId(userId).getOrNull()?.aquaUser?.gameOptions
|
||||
val userCharacterList = repos.userCharacter.findByUser_Card_ExtId(userId)
|
||||
.let { if (gameOptions?.mai2UnlockChara != true) it else (
|
||||
charaIds.associateWith { Mai2UserCharacter().apply { characterId = it; level = 1 } } +
|
||||
it.associateBy { it.characterId }
|
||||
).values }
|
||||
.let { if (gameOptions?.mai2UnlockCharaMaxLevel != true) it else it.mapApply { level = 9999 } }
|
||||
|
||||
return mapOf(
|
||||
"userId" to userId,
|
||||
"userCharacterList" to repos.userCharacter.findByUser_Card_ExtId(userId)
|
||||
"userCharacterList" to userCharacterList
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -50,10 +50,11 @@ class GetUserItemHandler(
|
||||
// Aqua Net game unlock feature
|
||||
cardRepo.findByExtId(userId).getOrNull()?.aquaUser?.gameOptions?.let { opt ->
|
||||
val items = when {
|
||||
(kind in 5..8) && opt.unlockMusic -> musicUnlock.getValue(kind)
|
||||
(kind in 1..3 || kind == 11) && opt.unlockCollectables -> itemUnlock[kind]
|
||||
(kind == 12) && opt.unlockTickets -> itemUnlock[kind]
|
||||
(kind in 9..10) && opt.unlockChara -> itemUnlock[kind]
|
||||
(kind in 5..8) && opt.mai2UnlockMusic -> musicUnlock.getValue(kind)
|
||||
(kind in 1..3 || kind == 11) && opt.mai2UnlockCollectables -> itemUnlock[kind]
|
||||
(kind == 12) && opt.mai2UnlockTickets -> itemUnlock[kind]
|
||||
(kind == 9) && opt.mai2UnlockChara -> itemUnlock[kind]
|
||||
(kind == 10) && opt.mai2UnlockPartners -> itemUnlock[kind]
|
||||
else -> emptyList()
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ import ext.millis
|
||||
import ext.parsing
|
||||
import icu.samnyan.aqua.sega.allnet.TokenChecker
|
||||
import icu.samnyan.aqua.sega.general.BaseHandler
|
||||
import icu.samnyan.aqua.sega.general.service.CardService
|
||||
import icu.samnyan.aqua.sega.maimai2.model.Mai2UserDataRepo
|
||||
import icu.samnyan.aqua.sega.maimai2.model.Mai2UserPlaylogRepo
|
||||
import icu.samnyan.aqua.sega.maimai2.model.userdata.Mai2UserPlaylog
|
||||
@@ -22,7 +23,8 @@ import kotlin.jvm.optionals.getOrNull
|
||||
class UploadUserPlaylogHandler(
|
||||
private val userDataRepository: Mai2UserDataRepo,
|
||||
private val playlogRepo: Mai2UserPlaylogRepo,
|
||||
private val mapper: BasicMapper
|
||||
private val mapper: BasicMapper,
|
||||
private val cardService: CardService
|
||||
) : BaseHandler {
|
||||
data class BacklogEntry(val time: Long, val playlog: Mai2UserPlaylog)
|
||||
companion object {
|
||||
@@ -60,7 +62,10 @@ class UploadUserPlaylogHandler(
|
||||
|
||||
// Save if the user is registered
|
||||
val u = userDataRepository.findByCardExtId(uid).getOrNull()
|
||||
if (u != null) playlogRepo.save(playlog.apply { user = u })
|
||||
if (u != null) {
|
||||
playlogRepo.save(playlog.apply { user = u })
|
||||
// u.card?.let { cardService.updateCardTimestamp(it, "mai2") } // No need: always followed by an UpsertUserAll
|
||||
}
|
||||
|
||||
// If the user hasn't registered (first play), save the playlog to a backlog
|
||||
else {
|
||||
|
||||
@@ -5,11 +5,14 @@ import ext.invoke
|
||||
import ext.mapApply
|
||||
import ext.unique
|
||||
import icu.samnyan.aqua.sega.general.BaseHandler
|
||||
import icu.samnyan.aqua.sega.general.model.CardStatus
|
||||
import icu.samnyan.aqua.sega.general.service.CardService
|
||||
import icu.samnyan.aqua.sega.maimai2.handler.UploadUserPlaylogHandler.Companion.playBacklog
|
||||
import icu.samnyan.aqua.sega.maimai2.model.*
|
||||
import icu.samnyan.aqua.sega.maimai2.model.Mai2Repos
|
||||
import icu.samnyan.aqua.sega.maimai2.model.request.Mai2UpsertUserAll
|
||||
import icu.samnyan.aqua.sega.maimai2.model.userdata.*
|
||||
import icu.samnyan.aqua.sega.maimai2.model.userdata.Mai2UserDetail
|
||||
import icu.samnyan.aqua.sega.maimai2.model.userdata.Mai2UserGeneralData
|
||||
import icu.samnyan.aqua.sega.maimai2.model.userdata.Mai2UserRate
|
||||
import icu.samnyan.aqua.sega.util.jackson.BasicMapper
|
||||
import lombok.AllArgsConstructor
|
||||
import org.slf4j.LoggerFactory
|
||||
@@ -25,7 +28,6 @@ class UpsertUserAllHandler(
|
||||
val cardService: CardService,
|
||||
val repos: Mai2Repos
|
||||
) : BaseHandler {
|
||||
|
||||
fun String.isValidUsername() = isNotBlank() && length <= 8
|
||||
|
||||
@Throws(JsonProcessingException::class)
|
||||
@@ -59,6 +61,12 @@ class UpsertUserAllHandler(
|
||||
}
|
||||
})
|
||||
|
||||
// If the user was previously migrated to Minato, saving would mark them "migrated and then cleared".
|
||||
if (u.card?.status == CardStatus.MIGRATED_TO_MINATO) {
|
||||
u.card?.status = CardStatus.NORMAL_MIGRATED_TO_MINATO_AND_THEN_CLEARED
|
||||
cardService.cardRepo.save(u.card!!)
|
||||
}
|
||||
|
||||
// Check playlog backlog
|
||||
if (playBacklog.containsKey(userId)) playBacklog.remove(userId)?.forEach {
|
||||
repos.userPlaylog.save(it.playlog.apply { user = u })
|
||||
@@ -163,6 +171,8 @@ class UpsertUserAllHandler(
|
||||
})
|
||||
}
|
||||
|
||||
u.card?.let { cardService.updateCardTimestamp(it, "mai2") }
|
||||
|
||||
return SUCCESS
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import ext.logger
|
||||
import ext.long
|
||||
import ext.parsing
|
||||
import icu.samnyan.aqua.sega.general.BaseHandler
|
||||
import icu.samnyan.aqua.sega.general.service.CardService
|
||||
import icu.samnyan.aqua.sega.maimai2.model.Mai2Repos
|
||||
import icu.samnyan.aqua.sega.maimai2.model.userdata.Mai2UserPrintDetail
|
||||
import icu.samnyan.aqua.sega.util.jackson.BasicMapper
|
||||
@@ -18,6 +19,7 @@ import java.util.concurrent.ThreadLocalRandom
|
||||
class UpsertUserPrintHandler(
|
||||
val mapper: BasicMapper,
|
||||
val db: Mai2Repos,
|
||||
val cardService: CardService,
|
||||
@param:Value("\${game.cardmaker.card.expiration:15}") val expirationTime: Long,
|
||||
) : BaseHandler {
|
||||
val log = logger()
|
||||
@@ -43,6 +45,8 @@ class UpsertUserPrintHandler(
|
||||
}
|
||||
db.userPrintDetail.save(userPrint)
|
||||
|
||||
userData.card?.let { cardService.updateCardTimestamp(it, "mai2") }
|
||||
|
||||
return mapOf(
|
||||
"returnCode" to 1,
|
||||
"orderId" to 0,
|
||||
|
||||
@@ -197,6 +197,8 @@ fun OngekiController.cmApiInit() {
|
||||
}
|
||||
}
|
||||
|
||||
u.card?.let { cardService.updateCardTimestamp(it, "ongeki") }
|
||||
|
||||
null
|
||||
}
|
||||
|
||||
@@ -250,6 +252,8 @@ fun OngekiController.cmApiInit() {
|
||||
}
|
||||
}
|
||||
|
||||
u.card?.let { cardService.updateCardTimestamp(it, "ongeki") }
|
||||
|
||||
null
|
||||
}
|
||||
|
||||
@@ -313,6 +317,8 @@ fun OngekiController.cmApiInit() {
|
||||
}
|
||||
}
|
||||
|
||||
u.card?.let { cardService.updateCardTimestamp(it, "ongeki") }
|
||||
|
||||
null
|
||||
}
|
||||
|
||||
@@ -342,4 +348,4 @@ fun OngekiController.cmApiInit() {
|
||||
|
||||
mapOf("length" to 0, "gameTheaterList" to emptyList<Any>(), "registIdList" to emptyList<Any>())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import icu.samnyan.aqua.sega.allnet.TokenChecker
|
||||
import icu.samnyan.aqua.sega.general.GameMusicPopularity
|
||||
import icu.samnyan.aqua.sega.general.MeowApi
|
||||
import icu.samnyan.aqua.sega.general.RequestContext
|
||||
import icu.samnyan.aqua.sega.general.service.CardService
|
||||
import icu.samnyan.aqua.sega.util.jackson.BasicMapper
|
||||
import icu.samnyan.aqua.spring.Metrics
|
||||
import jakarta.servlet.http.HttpServletRequest
|
||||
@@ -22,6 +23,7 @@ class OngekiController(
|
||||
val gdb: OngekiGameRepos,
|
||||
val us: AquaUserServices,
|
||||
val pop: GameMusicPopularity,
|
||||
val cardService: CardService,
|
||||
): MeowApi({ _, resp -> if (resp is String) resp else mapper.write(resp) }) {
|
||||
|
||||
val log = logger()
|
||||
|
||||
@@ -4,6 +4,7 @@ import ext.int
|
||||
import ext.invoke
|
||||
import ext.mapApply
|
||||
import ext.minus
|
||||
import icu.samnyan.aqua.sega.general.model.CardStatus
|
||||
import icu.samnyan.aqua.sega.ongeki.model.OngekiUpsertUserAll
|
||||
import icu.samnyan.aqua.sega.ongeki.model.UserData
|
||||
import icu.samnyan.aqua.sega.ongeki.model.UserGeneralData
|
||||
@@ -49,6 +50,12 @@ fun OngekiController.initUpsertAll() {
|
||||
db.regions.save(region)
|
||||
}
|
||||
|
||||
// If the user was previously migrated to Minato, saving would mark them "migrated and then cleared".
|
||||
if (u.card?.status == CardStatus.MIGRATED_TO_MINATO) {
|
||||
u.card?.status = CardStatus.NORMAL_MIGRATED_TO_MINATO_AND_THEN_CLEARED
|
||||
us.cardRepo.save(u.card!!)
|
||||
}
|
||||
|
||||
all.run {
|
||||
// Set users
|
||||
listOfNotNull(
|
||||
@@ -202,6 +209,8 @@ fun OngekiController.initUpsertAll() {
|
||||
id = db.kop.findByUserAndKopIdAndAreaId(u, kopId, areaId)()?.id ?: 0 }) }
|
||||
}
|
||||
|
||||
u.card?.let { cardService.updateCardTimestamp(it, "ongeki") }
|
||||
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -162,26 +162,13 @@ fun OngekiController.initUser() {
|
||||
)
|
||||
|
||||
if (u.card?.status == CardStatus.MIGRATED_TO_MINATO) {
|
||||
res["userName"] = "JiaQQqun / ChangeDNS"
|
||||
res["level"] = 0
|
||||
res["exp"] = 0
|
||||
res["playerRating"] = 0
|
||||
res["newPlayerRating"] = 0
|
||||
res["userName"] = "${res["userName"]}@AquaDX"
|
||||
}
|
||||
|
||||
res
|
||||
}
|
||||
|
||||
"GameLogin" {
|
||||
val user = db.data.findByCard_ExtId(uid)()
|
||||
|
||||
if (user?.card?.status == CardStatus.MIGRATED_TO_MINATO) {
|
||||
"""{"returnCode":"0"}"""
|
||||
}
|
||||
else {
|
||||
"""{"returnCode":"1"}"""
|
||||
}
|
||||
}
|
||||
"GameLogin" { """{"returnCode":"1"}""" }
|
||||
|
||||
"GetUserRecentRating".unpaged {
|
||||
db.generalData.findByUser_Card_ExtIdAndPropertyKey(uid, "recent_rating_list")()?.let { recent ->
|
||||
|
||||
@@ -205,28 +205,28 @@ fun WaccaServer.init() {
|
||||
val go = u.card?.aquaUser?.gameOptions ?: AquaGameOptions()
|
||||
|
||||
// All unlock
|
||||
if (go.unlockMusic && wacca.musicMapping.isNotEmpty()) {
|
||||
if (go.waccaUnlockMusic && wacca.musicMapping.isNotEmpty()) {
|
||||
items[MUSIC_UNLOCK()] = wacca.musicMapping.map { (id, v) -> MUSIC_UNLOCK(u, id, p1 = v.notes.size.long() - 1) }
|
||||
}
|
||||
if (go.unlockTickets) {
|
||||
if (go.waccaUnlockTickets) {
|
||||
var i = 0
|
||||
items[TICKET()] = enabledTickets.flatMap { (1..5).map { TICKET(u, it).apply { id = (i++).toLong() } } }
|
||||
}
|
||||
if (go.unlockChara) {
|
||||
if (go.waccaUnlockPlates) {
|
||||
wacca.itemMapping["plates"]?.let { items[USER_PLATE()] = it.map { (k, _) -> USER_PLATE(u, k.int()) } }
|
||||
}
|
||||
if (go.unlockCollectables) {
|
||||
if (go.waccaUnlockCollectables) {
|
||||
// TODO: Add titles
|
||||
mapOf("icon" to ICON, "plates" to USER_PLATE, "trophy" to TROPHY).map { (name, type) ->
|
||||
mapOf("icon" to ICON, "trophy" to TROPHY).map { (name, type) ->
|
||||
wacca.itemMapping[name]?.let { items[type()] = it.map { (k, _) -> type(u, k.int()) } }
|
||||
}
|
||||
}
|
||||
|
||||
val status = u.lStatus().toMutableList()
|
||||
|
||||
if (u.card?.status == CardStatus.MIGRATED_TO_MINATO) {
|
||||
status[1] = "JiaQQqun / ChangeDNS"
|
||||
}
|
||||
// if (u.card?.status == CardStatus.MIGRATED_TO_MINATO) {
|
||||
// status[1] = "${status[1]}@AquaDX"
|
||||
// }
|
||||
|
||||
u.run { ls(
|
||||
"0 status" - status,
|
||||
|
||||
@@ -0,0 +1,289 @@
|
||||
INSERT IGNORE INTO `ongeki_game_music` (id, artist_name, boss_card_id, boss_level, genre, level0, level1, level2, level3, level4, name, sort_name) VALUES
|
||||
(337, 'LOVE☆MAXガールズ「ゴシックは魔法乙女」', '100816', 15, 'POPS&ANIME', '4', '6', '9', 12, 0, 'わたしたち魔法乙女です☆', 'ワタシタチマホウオトメテス'),
|
||||
(591, 'TJ.hangneil', '101557', 80, 'オンゲキ', '6', '10', '13', 15, 0, 'Apollo', 'APOLLO'),
|
||||
(945, '柊かえ(CV:立花芽恵夢)「Re:ステージ!プリズムステップ」', '100915', 40, 'POPS&ANIME', '4', '8', '12', 14, 0, 'ガジェットはプリンセス', 'カシエツトハフリンセス'),
|
||||
(946, 'テトラルキア「Re:ステージ!プリズムステップ」', '100915', 15, 'POPS&ANIME', '2', '7', '11', 14, 0, 'ユニゾンモノローグ', 'ユニソンモノロク'),
|
||||
(1000, 'あべにゅうぷろじぇくと feat.エンジェルオールスターズ(めぐる・すみれ・遥・葵・クルミ・テスラ・ナイン)', '102185', 7, 'POPS&ANIME', '3', '7', '10', 12, 0, 'えんじぇる♡ピタゴリ☆ほーみたい!', 'エンシエルヒタコリホミタイ'),
|
||||
(1001, '周防パトラ', '102217', 10, 'POPS&ANIME', '4', '8', '11', 13, 0, '偉大なる悪魔は実は大天使パトラちゃん様なのだ!', 'イタイナルアクマハシツハタイテンシハトラチヤンサマナノタ'),
|
||||
(1002, '周防パトラ', '102217', 8, 'POPS&ANIME', '3', '6', '9', 12, 0, 'ハートサーモグラフィー', 'ハトサモクラフイ'),
|
||||
(1061, 'ARForest', '100765', 35, 'オンゲキ', '5', '9', '11', 14, 0, 'Flow Into You', 'FLOWINTOYOU'),
|
||||
(1074, '曲:Feryquitous/歌:高瀬 梨緒(CV:久保 ユリカ)', '101872', 24, 'オンゲキ', '3', '8', '12', 13, 0, 'Ai Me', 'AIME'),
|
||||
(1075, '曲:KENSUKE/歌:結城 莉玖(CV:朝日奈 丸佳)', '101873', 25, 'オンゲキ', '4', '8', '12', 13, 0, 'がおっと!!最強☆ぱーりーないと', 'カオツトサイキヨウハリナイト'),
|
||||
(1076, '曲:テラ(少女理論観測所)/歌:藍原 椿(CV:橋本 ちなみ)', '101874', 26, 'オンゲキ', '3', '7', '11', 13, 0, '耐冬花麗', 'ツハキウルワシ'),
|
||||
(1077, '提供', '100070', 15, 'オンゲキ', '4', '8', '12', 14, 0, 'Never Ending Adventure', 'NEVERENDINGADVENTURE'),
|
||||
(1078, 'brz1128', '100762', 40, 'オンゲキ', '4', '9', '12', 14, 0, 'ALLNIGHT_DANCER', 'ALLNIGHTDANCER'),
|
||||
(1079, '7mai', '101571', 63, 'オンゲキ', '6', '9', '12', 14, 0, 'Nýx', 'NYX'),
|
||||
(1080, 'Aoi', '100785', 80, 'オンゲキ', '7', '10', '13', 15, 0, 'Sargasso', 'SARGASSO'),
|
||||
(1083, 'Artifact vs. Dualcast', '100001', 43, 'チュウマイ', '4', '9', '12', 14, 0, 'Energizing Flame', 'ENERGIZINGFLAME'),
|
||||
(1084, 'owl*tree feat.nie*tree', '100064', 44, 'チュウマイ', '4', '9', '12', 14, 0, 'QuiQ', 'QUIQ'),
|
||||
(1085, '歌:長瀬有花/曲:いよわ', '102586', 5, 'POPS&ANIME', '2', '6', '10', 13, 0, 'オレンジスケール', 'オレンシスケル'),
|
||||
(1086, '歌:長瀬有花/曲:いよわ', '102586', 15, 'POPS&ANIME', '4', '8', '11', 13, 0, 'ほんの感想', 'ホンノカンソウ'),
|
||||
(1087, 'ジョー・力一', '101600', 11, 'POPS&ANIME', '2', '7', '10', 13, 0, 'レイテストショーマン', 'レイテストシヨマン'),
|
||||
(1088, '名取さな', '101842', 37, 'POPS&ANIME', '2', '7', '10', 13, 0, 'いっかい書いてさようなら', 'イツカイカイテサヨウナラ'),
|
||||
(1089, 'K-forest「Phigros」', '100209', 15, 'VARIETY', '3', '9', '12', 14, 0, 'Break Over', 'BREAKOVER'),
|
||||
(1090, 'Halv「Phigros」', '100029', 25, 'VARIETY', '3', '9', '12', 14, 0, 'Concvssion', 'CONCVSSION'),
|
||||
(1091, 'Sakuzyo「Phigros」', '100074', 65, 'VARIETY', '6', '10', '13', 15, 0, 'Distorted Fate', 'DISTORTEDFATE'),
|
||||
(1092, 'Blacklolita', '102300', 60, 'オンゲキ', '3', '9', '13', 14, 0, '[HALO]', 'HALO'),
|
||||
(1093, '矢鴇つかさ feat. kalon.', '100443', 26, 'チュウマイ', '2', '8', '11', 13, 0, 'SPILL OVER COLORS', 'SPILLOVERCOLORS'),
|
||||
(1094, '原口沙輔 feat.重音テト', '102503', 10, 'niconico', '2', '8', '10', 13, 0, '人マニア', 'ヒトマニア'),
|
||||
(1095, 'マサラダ', '102503', 15, 'niconico', '3', '7', '10', 13, 0, 'ライアーダンサー', 'ライアタンサ'),
|
||||
(1096, '柊マグネタイト', '100420', 28, 'niconico', '2', '7', '10', 13, 0, 'リアライズ', 'リアライス'),
|
||||
(1097, 'かめりあ', '100048', 71, 'チュウマイ', '6', '9', '13', 15, 0, 'Λzure Vixen', 'AZUREVIXEN'),
|
||||
(1098, '曲:脇眞富/歌:オンゲキシューターズ', '102711', 7, 'オンゲキ', '3', '7', '10', 13, 0, 'パピプペ Popping! Talk!', 'ハヒフヘPOPPINGTALK'),
|
||||
(1099, 'パソコン音楽クラブ', '100248', 33, 'チュウマイ', '3', '9', '13', 14, 0, 'Ignition', 'IGNITION'),
|
||||
(1100, 'kamome sano', '100022', 39, 'チュウマイ', '5', '8', '12', 14, 0, 'crazy (about you)', 'CRAZYABOUTYOU'),
|
||||
(1101, '天川はの', '100211', 5, 'POPS&ANIME', '2', '6', '10', 12, 0, 'Honeycomb', 'HONEYCOMB'),
|
||||
(1102, 'DÉ DÉ MOUSE & WaMi', '100061', 9, 'VARIETY', '2', '7', '11', 13, 0, 'As You Feel', 'ASYOUFEEL'),
|
||||
(1103, '歌:櫻川めぐ/曲:堀江晶太', '102571', 1, 'POPS&ANIME', '2', '5', '10', 13, 0, '一冊のアロー', 'イツサツノアロ'),
|
||||
(1104, '歌:松下/曲:堀江晶太', '100427', 10, 'POPS&ANIME', '2', '6', '10', 13, 0, 'Hey Darling!', 'HEYDARLING'),
|
||||
(1105, 'Mitsukiyo「ブルーアーカイブ -Blue Archive-」', '102598', 5, 'VARIETY', '3', '9', '12', 14, 0, 'Unwelcome School', 'UNWELCOMESCHOOL'),
|
||||
(1106, 'SUGAR RUSH「ブルーアーカイブ -Blue Archive-」', '102598', 10, 'VARIETY', '3', '6', '11', 13, 0, '彩りキャンバス', 'イロトリキヤンハス'),
|
||||
(1107, 'KARUT「ブルーアーカイブ -Blue Archive-」', '102603', 20, 'VARIETY', '3', '8', '11', 13, 0, 'Glitch Street', 'GLITCHSTREET'),
|
||||
(1108, 'Nor「ブルーアーカイブ -Blue Archive-」', '102598', 15, 'VARIETY', '3', '7', '10', 13, 0, 'Usagi Flap', 'USAGIFLAP'),
|
||||
(1109, 'Nor「ブルーアーカイブ -Blue Archive-」', '102603', 25, 'VARIETY', '3', '7', '10', 13, 0, 'RE Aoharu', 'REAOHARU'),
|
||||
(1113, 'B小町 ルビー(CV:伊駒ゆりえ)、有馬かな(CV:潘めぐみ)、MEMちょ(CV:大久保瑠美)', '100250', 2, 'POPS&ANIME', '3', '7', '10', 13, 0, 'POP IN 2', 'POPIN2'),
|
||||
(7077, '曲:穴山大輔, 水野健治/歌:藤沢 柚子(CV:久保田 梨沙)', '100769', 40, 'オンゲキ', '1', '5', '8', 12, 0, '夏色花火 -藤沢 柚子ソロver.-', 'ナツイロハナヒフシサワユスソロVER'),
|
||||
(7078, '曲:穴山大輔, 水野健治/歌:早乙女 彩華(CV:中島 唯)', '100770', 40, 'オンゲキ', '1', '5', '8', 12, 0, '夏色花火 -早乙女 彩華ソロver.-', 'ナツイロハナヒサオトメアヤカソロVER'),
|
||||
(7079, '曲:Powerless/歌:柏木 咲姫(CV:石見 舞菜香)', '100755', 40, 'オンゲキ', '3', '6', '11', 13, 0, 'Iudicium “Apocalypsis Mix” -柏木 咲姫ソロver.-', 'IUDICIUMAPOCALYPSISMIXカシワキサキソロVER'),
|
||||
(7080, '曲:Powerless/歌:柏木 美亜(CV:和氣 あず未)', '100756', 40, 'オンゲキ', '3', '6', '11', 13, 0, 'Iudicium “Apocalypsis Mix” -柏木 美亜ソロver.-', 'IUDICIUMAPOCALYPSISMIXカシワキミアソロVER'),
|
||||
(7152, '曲:アオワイファイ/歌:星咲 あかり(CV:赤尾 ひかる)', '100001', 40, 'オンゲキ', '2', '5', '10', 12, 0, 'WakeUP MakeUP FEVER! -星咲 あかりソロver.-', 'WAKEUPMAKEUPFEVERホシサキアカリソロVER'),
|
||||
(7153, '曲:アオワイファイ/歌:高瀬 梨緒(CV:久保 ユリカ)', '100028', 40, 'オンゲキ', '2', '5', '10', 12, 0, 'WakeUP MakeUP FEVER! -高瀬 梨緒ソロver.-', 'WAKEUPMAKEUPFEVERタカセリオソロVER'),
|
||||
(7154, '曲:アオワイファイ/歌:藍原 椿(CV:橋本 ちなみ)', '100042', 40, 'オンゲキ', '2', '5', '10', 12, 0, 'WakeUP MakeUP FEVER! -藍原 椿ソロver.-', 'WAKEUPMAKEUPFEVERアイハラツハキソロVER'),
|
||||
(7155, '曲:アオワイファイ/歌:桜井 春菜(CV:近藤 玲奈)', '100049', 40, 'オンゲキ', '2', '5', '10', 12, 0, 'WakeUP MakeUP FEVER! -桜井 春菜ソロver.-', 'WAKEUPMAKEUPFEVERサクライハルナソロVER'),
|
||||
(7156, '曲:アオワイファイ/歌:東雲 つむぎ(CV:和泉 風花)', '100452', 40, 'オンゲキ', '2', '5', '10', 12, 0, 'WakeUP MakeUP FEVER! -東雲 つむぎソロver.-', 'WAKEUPMAKEUPFEVERシノノメツムキソロVER'),
|
||||
(8060, 'LeaF', '101320', 56, 'チュウマイ', '0', '0', '0', 0, 14, 'macrocosmos', 'MACROCOSMOS'),
|
||||
(8177, 'オルタンシア「Re:ステージ!プリズムステップ」', '100915', 50, 'POPS&ANIME', '0', '0', '0', 0, 14, '君とインフィニティ -2021-', 'キミトインフイニテイ2021'),
|
||||
(8178, 'aran', '3', 40, 'オンゲキ', '0', '0', '0', 0, 0, 'Random Access Emotions', 'RANDOMACCESSEMOTIONS'),
|
||||
(8185, 'Tanchiky', '100476', 41, 'VARIETY', '0', '0', '0', 0, 0, 'ENERGY SYNERGY MATRIX', 'ENERGYSYNERGYMATRIX'),
|
||||
(8186, 'HiTECH NINJA', '100031', 10, 'オンゲキ', '0', '0', '0', 0, 14, 'Dolphika', 'DOLPHIKA'),
|
||||
(8187, '曲:アオワイファイ/歌:オンゲキシューターズ', '100236', 50, 'オンゲキ', '0', '0', '0', 0, 14, 'WakeUP MakeUP FEVER!', 'WAKEUPMAKEUPFEVER'),
|
||||
(8188, 'LOVE☆MAXガールズ「ゴシックは魔法乙女」', '100816', 55, 'POPS&ANIME', '0', '0', '0', 0, 14, 'わたしたち魔法乙女です☆', 'ワタシタチマホウオトメテス');
|
||||
INSERT IGNORE INTO `ongeki_game_event` (`id`) VALUES
|
||||
('1500430101'),
|
||||
('1500431601'),
|
||||
('1500432001'),
|
||||
('1500450101'),
|
||||
('1500450301'),
|
||||
('1500450302'),
|
||||
('1500451601'),
|
||||
('1500451701'),
|
||||
('1500451902'),
|
||||
('1500520101'),
|
||||
('1500520102'),
|
||||
('1500520301'),
|
||||
('1500520302'),
|
||||
('1500521301'),
|
||||
('1500540101'),
|
||||
('1500540102'),
|
||||
('1500540103'),
|
||||
('1500540301'),
|
||||
('1500540302'),
|
||||
('1500540303'),
|
||||
('1500540304'),
|
||||
('1500540305'),
|
||||
('1500540501'),
|
||||
('1500540502'),
|
||||
('1500540601'),
|
||||
('1500541501'),
|
||||
('1500541502'),
|
||||
('1500541503'),
|
||||
('1500541601'),
|
||||
('1500541602'),
|
||||
('1500541701'),
|
||||
('1500610101'),
|
||||
('1500610102'),
|
||||
('1500610301'),
|
||||
('1500610302'),
|
||||
('1500610303'),
|
||||
('1500610701'),
|
||||
('1500611301'),
|
||||
('1500630101'),
|
||||
('1500630102'),
|
||||
('1500630301'),
|
||||
('1500630501'),
|
||||
('1500630601'),
|
||||
('1500630801'),
|
||||
('1500631501'),
|
||||
('1500631601'),
|
||||
('1500631701'),
|
||||
('1500631801'),
|
||||
('1500710101'),
|
||||
('1500710102'),
|
||||
('1500710103'),
|
||||
('1500710301'),
|
||||
('1500710302'),
|
||||
('1500710303'),
|
||||
('1500710304'),
|
||||
('1500710305'),
|
||||
('1500710501'),
|
||||
('1500710701'),
|
||||
('1500711301'),
|
||||
('1500720101'),
|
||||
('1500720102'),
|
||||
('1500720103'),
|
||||
('1500720301'),
|
||||
('1500720302'),
|
||||
('1500720303'),
|
||||
('1500720304'),
|
||||
('1500720305'),
|
||||
('1500720501'),
|
||||
('1500720502'),
|
||||
('1500721501'),
|
||||
('1500721502'),
|
||||
('1500721601'),
|
||||
('1500721602'),
|
||||
('1500721701'),
|
||||
('1500721802'),
|
||||
('1500730101'),
|
||||
('1500730301'),
|
||||
('1500730801'),
|
||||
('1500760101'),
|
||||
('1500760501'),
|
||||
('1500760601'),
|
||||
('1500761401'),
|
||||
('1500761501'),
|
||||
('1500761601'),
|
||||
('1500761701'),
|
||||
('1500761801'),
|
||||
('1500810101'),
|
||||
('1500810102'),
|
||||
('1500810103'),
|
||||
('1500810301'),
|
||||
('1500810302'),
|
||||
('1500810303'),
|
||||
('1500810701'),
|
||||
('1500811301'),
|
||||
('1500811401'),
|
||||
('1500811501'),
|
||||
('1500811502'),
|
||||
('1500811503'),
|
||||
('1500811601'),
|
||||
('1500811701'),
|
||||
('1500811902'),
|
||||
('1500821801'),
|
||||
('1500830101'),
|
||||
('1500830102'),
|
||||
('1500830301'),
|
||||
('1500830302'),
|
||||
('1500830303'),
|
||||
('1500830304'),
|
||||
('1500830305'),
|
||||
('1500830306'),
|
||||
('1500830501'),
|
||||
('1500830601'),
|
||||
('1500831501'),
|
||||
('1500831502'),
|
||||
('1500831601'),
|
||||
('1500831701'),
|
||||
('1500910701'),
|
||||
('1500931801'),
|
||||
('1501051801'),
|
||||
('1501051802');
|
||||
INSERT IGNORE INTO `ongeki_game_card` (id, name, nick_name, attribute, chara_id, school, gakunen, rarity, level_param, skill_id, cho_kaika_skill_id, card_number, version) VALUES
|
||||
(100048, '【SSR】藍原 椿[サディスティック・スマイル]', 'サディスティック・スマイル', 'Leaf', 1005, '奏坂学園', '高校1年生', 'SSR', '60,257,280,295,307,317,0,0,0,322', 100106, 100107, '[O.N.G.E.K.I.]1.00-0057', '1.00'),
|
||||
(102036, '【SSR】三角 葵[夏宵スターマイン]', '夏宵スターマイン', 'Aqua', 1002, 'プロモーション', '高校2年生', 'SSR', '60,257,280,295,307,317,0,0,0,322', 105020, 105021, '[O.N.G.E.K.I.]Special Card', '1.45'),
|
||||
(102037, '【SSR】藍原 椿[夏宵スターマイン]', '夏宵スターマイン', 'Leaf', 1005, 'プロモーション', '高校1年生', 'SSR', '60,257,280,295,307,317,0,0,0,322', 105020, 105021, '[O.N.G.E.K.I.]Special Card', '1.45'),
|
||||
(102049, '【SSR】結城 莉玖[I got a gig tonight!]', 'I got a gig tonight!', 'Fire', 1004, '奏坂学園', '高校1年生', 'SSR', '66,277,297,309,316,327,0,0,0,332', 150013, 150014, '[O.N.G.E.K.I.]1.50-0027', '1.50'),
|
||||
(102050, '【SSR】逢坂 茜[Rule the World!!]', 'Rule the World!!', 'Fire', 1011, '奏坂学園', '高校3年生', 'SSR', '66,277,297,309,316,327,0,0,0,332', 150015, 150016, '[O.N.G.E.K.I.]1.50-0028', '1.50'),
|
||||
(102297, '【SSR】柏木 美亜[Primera Fes. ~Bridal Stage~]', 'Primera Fes. ~Bridal Stage~', 'Fire', 1013, '奏坂学園', '中学2年生', 'SSR', '70,300,313,323,330,335,0,0,0,340', 115134, 115135, '[O.N.G.E.K.I.]1.50-0046', '1.50'),
|
||||
(102298, '【SSR】珠洲島 有栖[Primera Fes. ~Bridal Stage~]', 'Primera Fes. ~Bridal Stage~', 'Aqua', 1012, '奏坂学園', '高校1年生', 'SSR', '60,257,280,295,307,317,0,0,0,322', 120006, 120007, '[O.N.G.E.K.I.]1.50-0047', '1.50'),
|
||||
(102299, '【SSR】三角 葵[Primera Fes. ~Bridal Stage~]', 'Primera Fes. ~Bridal Stage~', 'Aqua', 1002, '奏坂学園', '高校2年生', 'SSR', '60,257,280,295,307,317,0,0,0,322', 115122, 115123, '[O.N.G.E.K.I.]1.50-0048', '1.50'),
|
||||
(102300, '【SSR】柏木 美亜[Primera Fes. ~Bridal Stage~(集合Ver.)対戦相手専用]', 'Primera Fes. ~Bridal Stage~(集合Ver.)対戦相手専用', 'Fire', 1013, '奏坂学園', '中学2年生', 'SSR', '60,257,280,295,307,317,0,0,0,322', 100000, 100041, '[O.N.G.E.K.I.]1.50-', '1.50'),
|
||||
(102510, '【SR】重音テト[お ま え]', 'お ま え', 'Fire', 46194, '重音テト', '-', 'SR', '50,222,237,252,267,282,0,0,0,282', 100033, 100074, '[O.N.G.E.K.I.]1.50-E-0024', '1.50'),
|
||||
(102511, '【SR】重音テト[踊れ 踊れ 嘘に踊れ]', '踊れ 踊れ 嘘に踊れ', 'Fire', 46194, '重音テト', '-', 'SR', '50,222,237,252,267,282,0,0,0,282', 105042, 105043, '[O.N.G.E.K.I.]1.50-E-0025', '1.50'),
|
||||
(102512, '【SR】重音テト[踊ったもん勝ち]', '踊ったもん勝ち', 'Fire', 46194, '重音テト', '-', 'SR', '50,222,237,252,267,282,0,0,0,282', 120088, 120089, '[O.N.G.E.K.I.]1.50-E-0026', '1.50'),
|
||||
(102515, '【SSR】重音テト[人マニア]', '人マニア', 'Fire', 46194, '重音テト', '-', 'SSR', '60,257,280,295,307,317,0,0,0,322', 100138, 100139, '[O.N.G.E.K.I.]1.50-E-0029', '1.50'),
|
||||
(102516, '【SSR】重音テト[ライアーダンサー]', 'ライアーダンサー', 'Fire', 46194, '重音テト', '-', 'SSR', '60,257,280,295,307,317,0,0,0,322', 100031, 100072, '[O.N.G.E.K.I.]1.50-E-0030', '1.50'),
|
||||
(102571, '【R】和泉 妃愛[生徒会副会長]', '生徒会副会長', 'Fire', 46203, 'ハミダシクリエイティブ', '-', 'R', '50,197,212,227,242,257,0,0,0,257', 100005, 100046, '[O.N.G.E.K.I.]1.50-E-0039', '1.50'),
|
||||
(102572, '【R】常磐 華乃[生徒会広報]', '生徒会広報', 'Fire', 46204, 'ハミダシクリエイティブ', '-', 'R', '50,197,212,227,242,257,0,0,0,257', 110092, 110093, '[O.N.G.E.K.I.]1.50-E-0040', '1.50'),
|
||||
(102573, '【R】錦 あすみ[生徒会書記]', '生徒会書記', 'Fire', 46205, 'ハミダシクリエイティブ', '-', 'R', '50,197,212,227,242,257,0,0,0,257', 110148, 110149, '[O.N.G.E.K.I.]1.50-E-0041', '1.50'),
|
||||
(102574, '【R】鎌倉 詩桜[前生徒会長]', '前生徒会長', 'Fire', 46206, 'ハミダシクリエイティブ', '-', 'R', '50,197,212,227,242,257,0,0,0,257', 130006, 130007, '[O.N.G.E.K.I.]1.50-E-0042', '1.50'),
|
||||
(102575, '【R】竜閑 天梨[生徒会お手伝い]', '生徒会お手伝い', 'Fire', 46207, 'ハミダシクリエイティブ', '-', 'R', '50,197,212,227,242,257,0,0,0,257', 110142, 110143, '[O.N.G.E.K.I.]1.50-E-0043', '1.50'),
|
||||
(102576, '【SR】和泉 妃愛[ダメ兄を甘やかすことに喜びを感じる人気声優]', 'ダメ兄を甘やかすことに喜びを感じる人気声優', 'Fire', 46203, 'ハミダシクリエイティブ', '-', 'SR', '50,222,237,252,267,282,0,0,0,282', 125012, 125013, '[O.N.G.E.K.I.]1.50-E-0044', '1.50'),
|
||||
(102577, '【SR】常磐 華乃[黒歴史を抱える売れっ子イラストレーター]', '黒歴史を抱える売れっ子イラストレーター', 'Fire', 46204, 'ハミダシクリエイティブ', '-', 'SR', '50,222,237,252,267,282,0,0,0,282', 100025, 100066, '[O.N.G.E.K.I.]1.50-E-0045', '1.50'),
|
||||
(102578, '【SR】錦 あすみ[電脳世界「から」受肉した天使]', '電脳世界「から」受肉した天使', 'Fire', 46205, 'ハミダシクリエイティブ', '-', 'SR', '50,222,237,252,267,282,0,0,0,282', 100016, 100057, '[O.N.G.E.K.I.]1.50-E-0046', '1.50'),
|
||||
(102579, '【SR】鎌倉 詩桜[前会長にして元凶の気まぐれ小説家]', '前会長にして元凶の気まぐれ小説家', 'Fire', 46206, 'ハミダシクリエイティブ', '-', 'SR', '50,222,237,252,267,282,0,0,0,282', 100033, 100074, '[O.N.G.E.K.I.]1.50-E-0047', '1.50'),
|
||||
(102580, '【SR】竜閑 天梨[今をときめく人気読モ]', '今をときめく人気読モ', 'Fire', 46207, 'ハミダシクリエイティブ', '-', 'SR', '50,222,237,252,267,282,0,0,0,282', 115036, 115037, '[O.N.G.E.K.I.]1.50-E-0048', '1.50'),
|
||||
(102581, '【SSR】和泉 妃愛[妃愛&あすみ]', '妃愛&あすみ', 'Fire', 46203, 'ハミダシクリエイティブ', '-', 'SSR', '60,257,280,295,307,317,0,0,0,322', 130062, 130063, '[O.N.G.E.K.I.]1.50-E-0049', '1.50'),
|
||||
(102582, '【SSR】和泉 妃愛[ハミダシクリエイティブ]', 'ハミダシクリエイティブ', 'Fire', 46203, 'ハミダシクリエイティブ', '-', 'SSR', '60,257,280,295,307,317,0,0,0,322', 125046, 125047, '[O.N.G.E.K.I.]1.50-E-0050', '1.50'),
|
||||
(102586, '【R】長瀬有花[RIOT MUSIC]', 'RIOT MUSIC', 'Aqua', 46208, '長瀬有花', '-', 'R', '50,197,212,227,242,257,0,0,0,257', 100005, 100046, '[O.N.G.E.K.I.]1.50-E-0051', '1.50'),
|
||||
(102588, '【SR】長瀬有花[長瀬有花の日常①]', '長瀬有花の日常①', 'Aqua', 46208, '長瀬有花', '-', 'SR', '50,222,237,252,267,282,0,0,0,282', 100025, 100066, '[O.N.G.E.K.I.]1.50-E-0052', '1.50'),
|
||||
(102589, '【SR】長瀬有花[長瀬有花の日常②]', '長瀬有花の日常②', 'Aqua', 46208, '長瀬有花', '-', 'SR', '50,222,237,252,267,282,0,0,0,282', 100033, 100074, '[O.N.G.E.K.I.]1.50-E-0053', '1.50'),
|
||||
(102590, '【SR】長瀬有花[長瀬有花の日常③]', '長瀬有花の日常③', 'Aqua', 46208, '長瀬有花', '-', 'SR', '50,222,237,252,267,282,0,0,0,282', 100018, 100059, '[O.N.G.E.K.I.]1.50-E-0054', '1.50'),
|
||||
(102591, '【SR】長瀬有花[長瀬有花の日常④]', '長瀬有花の日常④', 'Aqua', 46208, '長瀬有花', '-', 'SR', '50,222,237,252,267,282,0,0,0,282', 110086, 110087, '[O.N.G.E.K.I.]1.50-E-0055', '1.50'),
|
||||
(102592, '【SR】長瀬有花[長瀬有花の日常⑤]', '長瀬有花の日常⑤', 'Aqua', 46208, '長瀬有花', '-', 'SR', '50,222,237,252,267,282,0,0,0,282', 110094, 110095, '[O.N.G.E.K.I.]1.50-E-0056', '1.50'),
|
||||
(102593, '【SR】長瀬有花[長瀬有花の日常⑥]', '長瀬有花の日常⑥', 'Aqua', 46208, '長瀬有花', '-', 'SR', '50,222,237,252,267,282,0,0,0,282', 125022, 125023, '[O.N.G.E.K.I.]1.50-E-0057', '1.50'),
|
||||
(102595, '【SSR】長瀬有花[Eureka]', 'Eureka', 'Aqua', 46208, '長瀬有花', '-', 'SSR', '60,257,280,295,307,317,0,0,0,322', 110070, 110071, '[O.N.G.E.K.I.]1.50-E-0058', '1.50'),
|
||||
(102596, '【SSR】長瀬有花[だつりょく系アーティスト]', 'だつりょく系アーティスト', 'Aqua', 46208, '長瀬有花', '-', 'SSR', '60,257,280,295,307,317,0,0,0,322', 105020, 105021, '[O.N.G.E.K.I.]1.50-E-0059', '1.50'),
|
||||
(102598, '【R】陸八魔 アル[便利屋68]', '便利屋68', 'Fire', 46209, 'ブルーアーカイブ', '-', 'R', '50,197,212,227,242,257,0,0,0,257', 100005, 100046, '[O.N.G.E.K.I.]1.50-E-0067', '1.50'),
|
||||
(102599, '【R】鬼方 カヨコ[便利屋68]', '便利屋68', 'Fire', 46210, 'ブルーアーカイブ', '-', 'R', '50,197,212,227,242,257,0,0,0,257', 110092, 110093, '[O.N.G.E.K.I.]1.50-E-0068', '1.50'),
|
||||
(102600, '【R】浅黄 ムツキ[便利屋68]', '便利屋68', 'Fire', 46211, 'ブルーアーカイブ', '-', 'R', '50,197,212,227,242,257,0,0,0,257', 110142, 110143, '[O.N.G.E.K.I.]1.50-E-0069', '1.50'),
|
||||
(102601, '【R】伊草 ハルカ[便利屋68]', '便利屋68', 'Fire', 46212, 'ブルーアーカイブ', '-', 'R', '50,197,212,227,242,257,0,0,0,257', 110108, 110109, '[O.N.G.E.K.I.]1.50-E-0070', '1.50'),
|
||||
(102602, '【R】桐藤 ナギサ[ティーパーティー]', 'ティーパーティー', 'Aqua', 46213, 'ブルーアーカイブ', '-', 'R', '50,197,212,227,242,257,0,0,0,257', 125050, 125051, '[O.N.G.E.K.I.]1.50-E-0096', '1.50'),
|
||||
(102603, '【R】聖園 ミカ[ティーパーティー]', 'ティーパーティー', 'Aqua', 46214, 'ブルーアーカイブ', '-', 'R', '50,197,212,227,242,257,0,0,0,257', 100005, 100046, '[O.N.G.E.K.I.]1.50-E-0097', '1.50'),
|
||||
(102604, '【R】百合園 セイア[ティーパーティー]', 'ティーパーティー', 'Aqua', 46215, 'ブルーアーカイブ', '-', 'R', '50,197,212,227,242,257,0,0,0,257', 100004, 100045, '[O.N.G.E.K.I.]1.50-E-0098', '1.50'),
|
||||
(102605, '【R】阿慈谷 ヒフミ[補習授業部]', '補習授業部', 'Aqua', 46216, 'ブルーアーカイブ', '-', 'R', '50,197,212,227,242,257,0,0,0,257', 100004, 100045, '[O.N.G.E.K.I.]1.50-E-0099', '1.50'),
|
||||
(102606, '【R】白洲 アズサ[補習授業部]', '補習授業部', 'Aqua', 46217, 'ブルーアーカイブ', '-', 'R', '50,197,212,227,242,257,0,0,0,257', 110092, 110093, '[O.N.G.E.K.I.]1.50-E-0100', '1.50'),
|
||||
(102607, '【R】下江 コハル[補習授業部]', '補習授業部', 'Aqua', 46218, 'ブルーアーカイブ', '-', 'R', '50,197,212,227,242,257,0,0,0,257', 100003, 100044, '[O.N.G.E.K.I.]1.50-E-0101', '1.50'),
|
||||
(102608, '【R】浦和 ハナコ[補習授業部]', '補習授業部', 'Aqua', 46219, 'ブルーアーカイブ', '-', 'R', '50,197,212,227,242,257,0,0,0,257', 125006, 125007, '[O.N.G.E.K.I.]1.50-E-0102', '1.50'),
|
||||
(102609, '【R】柚鳥 ナツ[放課後スイーツ部]', '放課後スイーツ部', 'Leaf', 46220, 'ブルーアーカイブ', '-', 'R', '50,197,212,227,242,257,0,0,0,257', 110084, 110085, '[O.N.G.E.K.I.]1.50-E-0071', '1.50'),
|
||||
(102610, '【R】杏山 カズサ[放課後スイーツ部]', '放課後スイーツ部', 'Leaf', 46221, 'ブルーアーカイブ', '-', 'R', '50,197,212,227,242,257,0,0,0,257', 100005, 100046, '[O.N.G.E.K.I.]1.50-E-0072', '1.50'),
|
||||
(102611, '【R】栗村 アイリ[放課後スイーツ部]', '放課後スイーツ部', 'Leaf', 46222, 'ブルーアーカイブ', '-', 'R', '50,197,212,227,242,257,0,0,0,257', 105004, 105005, '[O.N.G.E.K.I.]1.50-E-0073', '1.50'),
|
||||
(102612, '【R】伊原木 ヨシミ[放課後スイーツ部]', '放課後スイーツ部', 'Leaf', 46223, 'ブルーアーカイブ', '-', 'R', '50,197,212,227,242,257,0,0,0,257', 110092, 110093, '[O.N.G.E.K.I.]1.50-E-0074', '1.50'),
|
||||
(102613, '【R】美甘 ネル[Cleaning&Clearing]', 'Cleaning&Clearing', 'Fire', 46224, 'ブルーアーカイブ', '-', 'R', '50,197,212,227,242,257,0,0,0,257', 110092, 110093, '[O.N.G.E.K.I.]1.50-E-0075', '1.50'),
|
||||
(102614, '【R】一之瀬 アスナ[Cleaning&Clearing]', 'Cleaning&Clearing', 'Fire', 46225, 'ブルーアーカイブ', '-', 'R', '50,197,212,227,242,257,0,0,0,257', 100004, 100045, '[O.N.G.E.K.I.]1.50-E-0076', '1.50'),
|
||||
(102615, '【R】角楯 カリン[Cleaning&Clearing]', 'Cleaning&Clearing', 'Fire', 46226, 'ブルーアーカイブ', '-', 'R', '50,197,212,227,242,257,0,0,0,257', 100005, 100046, '[O.N.G.E.K.I.]1.50-E-0077', '1.50'),
|
||||
(102616, '【R】室笠 アカネ[Cleaning&Clearing]', 'Cleaning&Clearing', 'Fire', 46227, 'ブルーアーカイブ', '-', 'R', '50,197,212,227,242,257,0,0,0,257', 105112, 105113, '[O.N.G.E.K.I.]1.50-E-0078', '1.50'),
|
||||
(102617, '【R】飛鳥馬 トキ[Cleaning&Clearing]', 'Cleaning&Clearing', 'Fire', 46228, 'ブルーアーカイブ', '-', 'R', '50,197,212,227,242,257,0,0,0,257', 110092, 110093, '[O.N.G.E.K.I.]1.50-E-0079', '1.50'),
|
||||
(102628, '【SR】陸八魔 アル[外部経営顧問としての入社提案]', '外部経営顧問としての入社提案', 'Fire', 46209, 'ブルーアーカイブ', '-', 'SR', '50,222,237,252,267,282,0,0,0,282', 120018, 120019, '[O.N.G.E.K.I.]1.50-E-0080', '1.50'),
|
||||
(102629, '【SR】鬼方 カヨコ[雨の降る日の路地裏]', '雨の降る日の路地裏', 'Fire', 46210, 'ブルーアーカイブ', '-', 'SR', '50,222,237,252,267,282,0,0,0,282', 100025, 100066, '[O.N.G.E.K.I.]1.50-E-0081', '1.50'),
|
||||
(102630, '【SR】浅黄 ムツキ[誰かからの特別な依頼]', '誰かからの特別な依頼', 'Fire', 46211, 'ブルーアーカイブ', '-', 'SR', '50,222,237,252,267,282,0,0,0,282', 100016, 100057, '[O.N.G.E.K.I.]1.50-E-0082', '1.50'),
|
||||
(102631, '【SR】伊草 ハルカ[間違えて]', '間違えて', 'Fire', 46212, 'ブルーアーカイブ', '-', 'SR', '50,222,237,252,267,282,0,0,0,282', 115008, 115009, '[O.N.G.E.K.I.]1.50-E-0083', '1.50'),
|
||||
(102632, '【SR】桐藤 ナギサ[紅茶とコク]', '紅茶とコク', 'Aqua', 46213, 'ブルーアーカイブ', '-', 'SR', '50,222,237,252,267,282,0,0,0,282', 110066, 110067, '[O.N.G.E.K.I.]1.50-E-0103', '1.50'),
|
||||
(102633, '【SR】聖園 ミカ[屋根裏部屋のお姫様]', '屋根裏部屋のお姫様', 'Aqua', 46214, 'ブルーアーカイブ', '-', 'SR', '50,222,237,252,267,282,0,0,0,282', 105042, 105043, '[O.N.G.E.K.I.]1.50-E-0104', '1.50'),
|
||||
(102634, '【SR】百合園 セイア[眠り姫からの誘い]', '眠り姫からの誘い', 'Aqua', 46215, 'ブルーアーカイブ', '-', 'SR', '50,222,237,252,267,282,0,0,0,282', 110086, 110087, '[O.N.G.E.K.I.]1.50-E-0105', '1.50'),
|
||||
(102635, '【SR】阿慈谷 ヒフミ[偶然のお出かけ]', '偶然のお出かけ', 'Aqua', 46216, 'ブルーアーカイブ', '-', 'SR', '50,222,237,252,267,282,0,0,0,282', 105052, 105053, '[O.N.G.E.K.I.]1.50-E-0106', '1.50'),
|
||||
(102636, '【SR】白洲 アズサ[計画]', '計画', 'Aqua', 46217, 'ブルーアーカイブ', '-', 'SR', '50,222,237,252,267,282,0,0,0,282', 100025, 100066, '[O.N.G.E.K.I.]1.50-E-0107', '1.50'),
|
||||
(102637, '【SR】下江 コハル[何するつもり?]', '何するつもり?', 'Aqua', 46218, 'ブルーアーカイブ', '-', 'SR', '50,222,237,252,267,282,0,0,0,282', 115052, 115053, '[O.N.G.E.K.I.]1.50-E-0108', '1.50'),
|
||||
(102638, '【SR】浦和 ハナコ[少し変わった女の子]', '少し変わった女の子', 'Aqua', 46219, 'ブルーアーカイブ', '-', 'SR', '50,222,237,252,267,282,0,0,0,282', 100018, 100059, '[O.N.G.E.K.I.]1.50-E-0109', '1.50'),
|
||||
(102639, '【SR】柚鳥 ナツ[3時間目「実習:発掘」]', '3時間目「実習:発掘」', 'Leaf', 46220, 'ブルーアーカイブ', '-', 'SR', '50,222,237,252,267,282,0,0,0,282', 100017, 100058, '[O.N.G.E.K.I.]1.50-E-0084', '1.50'),
|
||||
(102640, '【SR】杏山 カズサ[バッドタイミング]', 'バッドタイミング', 'Leaf', 46221, 'ブルーアーカイブ', '-', 'SR', '50,222,237,252,267,282,0,0,0,282', 110094, 110095, '[O.N.G.E.K.I.]1.50-E-0085', '1.50'),
|
||||
(102641, '【SR】栗村 アイリ[ちょっとしたデート]', 'ちょっとしたデート', 'Leaf', 46222, 'ブルーアーカイブ', '-', 'SR', '50,222,237,252,267,282,0,0,0,282', 105000, 105001, '[O.N.G.E.K.I.]1.50-E-0086', '1.50'),
|
||||
(102642, '【SR】伊原木 ヨシミ[その輝きの、すぐそばに]', 'その輝きの、すぐそばに', 'Leaf', 46223, 'ブルーアーカイブ', '-', 'SR', '50,222,237,252,267,282,0,0,0,282', 100033, 100074, '[O.N.G.E.K.I.]1.50-E-0087', '1.50'),
|
||||
(102643, '【SR】美甘 ネル[輝く夜に]', '輝く夜に', 'Fire', 46224, 'ブルーアーカイブ', '-', 'SR', '50,222,237,252,267,282,0,0,0,282', 120018, 120019, '[O.N.G.E.K.I.]1.50-E-0088', '1.50'),
|
||||
(102644, '【SR】一之瀬 アスナ[壊れたアスナ]', '壊れたアスナ', 'Fire', 46225, 'ブルーアーカイブ', '-', 'SR', '50,222,237,252,267,282,0,0,0,282', 110136, 110137, '[O.N.G.E.K.I.]1.50-E-0089', '1.50'),
|
||||
(102645, '【SR】角楯 カリン[メイドカフェ!]', 'メイドカフェ!', 'Fire', 46226, 'ブルーアーカイブ', '-', 'SR', '50,222,237,252,267,282,0,0,0,282', 120074, 120075, '[O.N.G.E.K.I.]1.50-E-0090', '1.50'),
|
||||
(102646, '【SR】室笠 アカネ[輝く午後を迎えて]', '輝く午後を迎えて', 'Fire', 46227, 'ブルーアーカイブ', '-', 'SR', '50,222,237,252,267,282,0,0,0,282', 130000, 130001, '[O.N.G.E.K.I.]1.50-E-0091', '1.50'),
|
||||
(102647, '【SR】飛鳥馬 トキ[メイドの中のメイド]', 'メイドの中のメイド', 'Fire', 46228, 'ブルーアーカイブ', '-', 'SR', '50,222,237,252,267,282,0,0,0,282', 110094, 110095, '[O.N.G.E.K.I.]1.50-E-0092', '1.50'),
|
||||
(102658, '【SSR】聖園 ミカ[聖園ミカ、ついに登場~☆ って感じかな?]', '聖園ミカ、ついに登場~☆ って感じかな?', 'Aqua', 46214, 'ブルーアーカイブ', '-', 'SSR', '67,287,307,319,326,337,0,0,0,342', 115134, 115135, '[O.N.G.E.K.I.]1.50-E-0110', '1.50'),
|
||||
(102659, '【SSR】美甘 ネル[コールサイン・ダブルオー]', 'コールサイン・ダブルオー', 'Fire', 46224, 'ブルーアーカイブ', '-', 'SSR', '60,257,280,295,307,317,0,0,0,322', 120006, 120007, '[O.N.G.E.K.I.]1.50-E-0093', '1.50'),
|
||||
(102660, '【SSR】阿慈谷 ヒフミ[私たちの、青春の物語を!!]', '私たちの、青春の物語を!!', 'Aqua', 46216, 'ブルーアーカイブ', '-', 'SSR', '60,257,280,295,307,317,0,0,0,322', 110098, 110099, '[O.N.G.E.K.I.]1.50-E-0111', '1.50'),
|
||||
(102661, '【SSR】栗村 アイリ[-ive aLIVE!]', '-ive aLIVE!', 'Leaf', 46222, 'ブルーアーカイブ', '-', 'SSR', '60,257,280,295,307,317,0,0,0,322', 110068, 110069, '[O.N.G.E.K.I.]1.50-E-0094', '1.50'),
|
||||
(102662, '【SSR】白洲 アズサ[Et Omnia Vanitas]', 'Et Omnia Vanitas', 'Aqua', 46217, 'ブルーアーカイブ', '-', 'SSR', '60,257,280,295,307,317,0,0,0,322', 100144, 100145, '[O.N.G.E.K.I.]1.50-E-0112', '1.50'),
|
||||
(102663, '【SSR】陸八魔 アル[あっはは!これくらい簡単よ!]', 'あっはは!これくらい簡単よ!', 'Fire', 46209, 'ブルーアーカイブ', '-', 'SSR', '60,257,280,295,307,317,0,0,0,322', 110070, 110071, '[O.N.G.E.K.I.]1.50-E-0095', '1.50'),
|
||||
(102664, '【SSR】桐藤 ナギサ[いつでも余裕をもって、優雅に]', 'いつでも余裕をもって、優雅に', 'Aqua', 46213, 'ブルーアーカイブ', '-', 'SSR', '60,257,280,295,307,317,0,0,0,322', 105020, 105021, '[O.N.G.E.K.I.]1.50-301', '1.50'),
|
||||
(102665, '【SSR】飛鳥馬 トキ[命令を遂行します。]', '命令を遂行します。', 'Fire', 46228, 'ブルーアーカイブ', '-', 'SSR', '60,257,280,295,307,317,0,0,0,322', 125046, 125047, '[O.N.G.E.K.I.]1.50-302', '1.50'),
|
||||
(102688, '【SSR】星咲 あかり[ハーバリウム・フェアリーズ]', 'ハーバリウム・フェアリーズ', 'Fire', 1000, '奏坂学園', '高校2年生', 'SSR', '67,290,310,322,332,340,0,0,0,345', 150001, 150002, '[O.N.G.E.K.I.]1.50-0029', '1.50'),
|
||||
(102689, '【SSR】藤沢 柚子[ハーバリウム・フェアリーズ]', 'ハーバリウム・フェアリーズ', 'Leaf', 1001, '奏坂学園', '高校2年生', 'SSR', '67,290,310,322,332,340,0,0,0,345', 150005, 150006, '[O.N.G.E.K.I.]1.50-0030', '1.50'),
|
||||
(102690, '【SSR】三角 葵[ハーバリウム・フェアリーズ]', 'ハーバリウム・フェアリーズ', 'Aqua', 1002, '奏坂学園', '高校2年生', 'SSR', '67,290,310,322,332,340,0,0,0,345', 150003, 150004, '[O.N.G.E.K.I.]1.50-0031', '1.50'),
|
||||
(102691, '【SSR】高瀬 梨緒[ハーバリウム・フェアリーズ]', 'ハーバリウム・フェアリーズ', 'Aqua', 1003, '奏坂学園', '高校2年生', 'SSR', '67,290,310,322,332,340,0,0,0,345', 150003, 150004, '[O.N.G.E.K.I.]1.50-0032', '1.50'),
|
||||
(102692, '【SSR】結城 莉玖[ハーバリウム・フェアリーズ]', 'ハーバリウム・フェアリーズ', 'Fire', 1004, '奏坂学園', '高校1年生', 'SSR', '67,290,310,322,332,340,0,0,0,345', 150001, 150002, '[O.N.G.E.K.I.]1.50-0033', '1.50'),
|
||||
(102693, '【SSR】藍原 椿[ハーバリウム・フェアリーズ]', 'ハーバリウム・フェアリーズ', 'Leaf', 1005, '奏坂学園', '高校1年生', 'SSR', '67,290,310,322,332,340,0,0,0,345', 150005, 150006, '[O.N.G.E.K.I.]1.50-0034', '1.50'),
|
||||
(102696, '【SSR】九條 楓[ハーバリウム・フェアリーズ]', 'ハーバリウム・フェアリーズ', 'Leaf', 1008, '奏坂学園', '高校3年生', 'SSR', '67,290,310,322,332,340,0,0,0,345', 150005, 150006, '[O.N.G.E.K.I.]1.50-0037', '1.50'),
|
||||
(102699, '【SSR】逢坂 茜[ハーバリウム・フェアリーズ]', 'ハーバリウム・フェアリーズ', 'Fire', 1011, '奏坂学園', '高校3年生', 'SSR', '67,290,310,322,332,340,0,0,0,345', 150001, 150002, '[O.N.G.E.K.I.]1.50-0040', '1.50'),
|
||||
(102700, '【SSR】珠洲島 有栖[ハーバリウム・フェアリーズ]', 'ハーバリウム・フェアリーズ', 'Aqua', 1012, '奏坂学園', '高校1年生', 'SSR', '67,290,310,322,332,340,0,0,0,345', 150003, 150004, '[O.N.G.E.K.I.]1.50-0041', '1.50'),
|
||||
(102706, '【SSR】西館 ハク[アイシング・ドリーム]', 'アイシング・ドリーム', 'Fire', 32001, 'Re:ステージ!プリズムステップ', '-', 'SSR', '60,257,280,295,307,317,0,0,0,322', 130002, 130003, '[O.N.G.E.K.I.]1.50-0019', '1.50'),
|
||||
(102707, '【SSR】結城 莉玖[O.N.G.E.K.I. 7th Anniversary]', 'O.N.G.E.K.I. 7th Anniversary', 'Fire', 1004, '奏坂学園', '高校1年生', 'SSR', '65,275,295,307,314,325,0,0,0,330', 100034, 100075, '[O.N.G.E.K.I.]1.50-0049', '1.50'),
|
||||
(102708, '【SSR】桜井 春菜[O.N.G.E.K.I. 7th Anniversary]', 'O.N.G.E.K.I. 7th Anniversary', 'Fire', 1007, '奏坂学園', '高校2年生', 'SSR', '66,280,300,312,319,330,0,0,0,335', 135038, 135039, '[O.N.G.E.K.I.]1.50-0050', '1.50'),
|
||||
(102709, '【SSR】井之原 小星[O.N.G.E.K.I. 7th Anniversary]', 'O.N.G.E.K.I. 7th Anniversary', 'Leaf', 1010, '奏坂学園', '高校1年生', 'SSR', '65,275,295,307,314,325,0,0,0,330', 135074, 135075, '[O.N.G.E.K.I.]1.50-0051', '1.50'),
|
||||
(102710, '【SSR】逢坂 茜[O.N.G.E.K.I. 7th Anniversary]', 'O.N.G.E.K.I. 7th Anniversary', 'Fire', 1011, '奏坂学園', '高校3年生', 'SSR', '65,275,295,307,314,325,0,0,0,330', 105020, 105021, '[O.N.G.E.K.I.]1.50-0052', '1.50'),
|
||||
(102711, '【SSR】柏木 美亜[O.N.G.E.K.I. 7th Anniversary]', 'O.N.G.E.K.I. 7th Anniversary', 'Fire', 1013, '奏坂学園', '中学2年生', 'SSR', '66,280,300,312,319,330,0,0,0,335', 115120, 115121, '[O.N.G.E.K.I.]1.50-0053', '1.50'),
|
||||
(102721, '【SR】西郷・R・いろり[もちもちダウナー有能]', 'もちもちダウナー有能', 'Fire', 46019, '名取さな', '-', 'SR', '50,222,237,252,267,282,0,0,0,282', 120068, 120069, '[O.N.G.E.K.I.]1.50-E-0060', '1.50'),
|
||||
(102722, '【SR】名取さな[名取探偵事務所所長]', '名取探偵事務所所長', 'Fire', 46019, '名取さな', '-', 'SR', '50,222,237,252,267,282,0,0,0,282', 120018, 120019, '[O.N.G.E.K.I.]1.50-E-0061', '1.50'),
|
||||
(102723, '【SR】名取さな[みんなで踊ろうおしりぷり音頭]', 'みんなで踊ろうおしりぷり音頭', 'Fire', 46019, '名取さな', '-', 'SR', '50,222,237,252,267,282,0,0,0,282', 115068, 115069, '[O.N.G.E.K.I.]1.50-E-0062', '1.50'),
|
||||
(102724, '【SSR】名取さな[名取探偵事務所開店!!]', '名取探偵事務所開店!!', 'Fire', 46019, '名取さな', '-', 'SSR', '65,270,291,304,314,322,0,0,0,327', 115132, 115133, '[O.N.G.E.K.I.]1.50-E-0063', '1.50'),
|
||||
(102725, '【SSR】名取さな[さなちゃんねる夏祭り]', 'さなちゃんねる夏祭り', 'Fire', 46019, '名取さな', '-', 'SSR', '65,270,291,304,314,322,0,0,0,327', 110004, 110005, '[O.N.G.E.K.I.]1.50-E-0064', '1.50'),
|
||||
(102726, '【SSR】名取さな[ハロー・マイ・バースデイ]', 'ハロー・マイ・バースデイ', 'Fire', 46019, '名取さな', '-', 'SSR', '65,270,291,304,314,322,0,0,0,327', 130086, 130087, '[O.N.G.E.K.I.]1.50-E-0065', '1.50'),
|
||||
(102727, '【SSR】名取さな[王国からの招待状]', '王国からの招待状', 'Fire', 46019, '名取さな', '-', 'SSR', '65,270,291,304,314,322,0,0,0,327', 120006, 120007, '[O.N.G.E.K.I.]1.50-E-0066', '1.50'),
|
||||
(102734, '【SSR】旭 日向[Earthly Light(集合Ver.)]', 'Earthly Light(集合Ver.)', 'Leaf', 32001, 'Re:ステージ!プリズムステップ', '-', 'SSR', '60,257,280,295,307,317,0,0,0,322', 100000, 100041, '[O.N.G.E.K.I.]1.50-371', '1.50'),
|
||||
(102738, '【SR+】珠洲島 有栖[Nexture 05「SIRIUS」]', 'Nexture 05「SIRIUS」', 'Aqua', 1012, '奏坂学園', '高校1年生', 'SRPlus', '53,240,263,278,290,300,0,0,0,300', 120072, 120073, '[O.N.G.E.K.I.]Special Card', '1.50');
|
||||
11
src/main/resources/db/80/V1000_62__sega_card_timestamp.sql
Normal file
11
src/main/resources/db/80/V1000_62__sega_card_timestamp.sql
Normal file
@@ -0,0 +1,11 @@
|
||||
CREATE TABLE sega_card_timestamp
|
||||
(
|
||||
id BIGINT AUTO_INCREMENT NOT NULL,
|
||||
created_at datetime(3) NOT NULL,
|
||||
updated_at datetime(3) NOT NULL,
|
||||
game VARCHAR(255) NOT NULL,
|
||||
card_id BIGINT NOT NULL,
|
||||
PRIMARY KEY (id),
|
||||
CONSTRAINT fk_sega_card_timestamp_on_sega_card FOREIGN KEY (card_id) REFERENCES sega_card (id) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
CONSTRAINT unq_sega_card_timestamp_on_game_card UNIQUE (game, card_id)
|
||||
);
|
||||
@@ -0,0 +1,30 @@
|
||||
-- Add new unlock columns
|
||||
ALTER TABLE aqua_game_options ADD COLUMN mai2_unlock_music BIT NOT NULL DEFAULT 0;
|
||||
ALTER TABLE aqua_game_options ADD COLUMN mai2_unlock_chara BIT NOT NULL DEFAULT 0;
|
||||
ALTER TABLE aqua_game_options ADD COLUMN mai2_unlock_chara_max_level BIT NOT NULL DEFAULT 0;
|
||||
ALTER TABLE aqua_game_options ADD COLUMN mai2_unlock_partners BIT NOT NULL DEFAULT 0;
|
||||
ALTER TABLE aqua_game_options ADD COLUMN mai2_unlock_collectables BIT NOT NULL DEFAULT 0;
|
||||
ALTER TABLE aqua_game_options ADD COLUMN mai2_unlock_tickets BIT NOT NULL DEFAULT 0;
|
||||
ALTER TABLE aqua_game_options ADD COLUMN wacca_unlock_music BIT NOT NULL DEFAULT 0;
|
||||
ALTER TABLE aqua_game_options ADD COLUMN wacca_unlock_plates BIT NOT NULL DEFAULT 0;
|
||||
ALTER TABLE aqua_game_options ADD COLUMN wacca_unlock_collectables BIT NOT NULL DEFAULT 0;
|
||||
ALTER TABLE aqua_game_options ADD COLUMN wacca_unlock_tickets BIT NOT NULL DEFAULT 0;
|
||||
|
||||
-- Migrate data
|
||||
UPDATE aqua_game_options SET
|
||||
mai2_unlock_music = unlock_music,
|
||||
mai2_unlock_chara = unlock_chara,
|
||||
mai2_unlock_chara_max_level = unlock_chara,
|
||||
mai2_unlock_partners = unlock_chara,
|
||||
mai2_unlock_collectables = unlock_collectables,
|
||||
mai2_unlock_tickets = unlock_tickets,
|
||||
wacca_unlock_music = unlock_music,
|
||||
wacca_unlock_plates = unlock_chara | unlock_collectables,
|
||||
wacca_unlock_collectables = unlock_collectables,
|
||||
wacca_unlock_tickets = unlock_tickets;
|
||||
|
||||
-- Drop old columns
|
||||
ALTER TABLE aqua_game_options DROP COLUMN unlock_music;
|
||||
ALTER TABLE aqua_game_options DROP COLUMN unlock_chara;
|
||||
ALTER TABLE aqua_game_options DROP COLUMN unlock_collectables;
|
||||
ALTER TABLE aqua_game_options DROP COLUMN unlock_tickets;
|
||||
@@ -0,0 +1,112 @@
|
||||
INSERT INTO chusan_game_event (id, type, end_date, start_date, enable)
|
||||
VALUES
|
||||
(17090, 1, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17091, 2, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17092, 8, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17093, 1, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17094, 3, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17095, 2, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17096, 11, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17100, 3, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17101, 1, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17102, 3, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17103, 1, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17104, 2, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17105, 2, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17106, 17, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17107, 4, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17108, 5, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17109, 7, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17150, 1, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17151, 2, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17152, 8, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17153, 1, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17154, 2, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17155, 8, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17156, 1, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17157, 1, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17158, 14, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17159, 3, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17160, 11, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17200, 3, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17201, 1, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17202, 2, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17203, 8, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17204, 1, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17205, 3, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17206, 10, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17207, 1, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17208, 2, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17209, 2, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17210, 17, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17211, 8, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17213, 4, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17214, 5, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17250, 1, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17251, 2, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17252, 8, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17256, 1, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17257, 3, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17258, 3, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17259, 11, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17260, 1, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17261, 2, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17262, 8, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17263, 1, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17300, 3, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17301, 1, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17302, 3, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17303, 1, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17304, 2, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17305, 2, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17306, 17, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17307, 1, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17308, 14, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17309, 4, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17310, 5, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17350, 3, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17351, 1, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17352, 2, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17353, 8, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17354, 1, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17355, 2, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17356, 8, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17357, 10, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17358, 11, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17380, 1, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17382, 1, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17383, 1, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17384, 7, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17385, 7, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17386, 3, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17400, 3, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17401, 1, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17402, 2, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17403, 8, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17404, 1, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17405, 3, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17406, 1, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17407, 2, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17408, 2, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17409, 17, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17410, 2, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17411, 1, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17412, 14, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17413, 4, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17414, 5, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17450, 3, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17451, 1, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17452, 2, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17453, 8, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17454, 3, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17480, 1, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17481, 3, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17482, 1, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17483, 2, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17484, 2, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true),
|
||||
(17485, 17, '2029-01-01 00:00:00.000000','2019-01-01 00:00:00.000000',true)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
type = VALUES(type),
|
||||
end_date = VALUES(end_date),
|
||||
start_date = VALUES(start_date),
|
||||
enable = VALUES(enable);
|
||||
Reference in New Issue
Block a user