From 3d95a84739c73e3bed3121fbda4f985e61c2a39f Mon Sep 17 00:00:00 2001
From: alexay7 <43906716+alexay7@users.noreply.github.com>
Date: Thu, 21 Aug 2025 22:19:25 +0200
Subject: [PATCH] feat: Add prefecture modification support (#170)
---
.../settings/GeneralGameSettings.svelte | 27 ++++-----
.../components/settings/RegionSelector.svelte | 59 +++++++++++++++++++
AquaNet/src/libs/generalTypes.ts | 1 +
AquaNet/src/libs/i18n/en_ref.ts | 6 +-
AquaNet/src/libs/i18n/zh.ts | 8 +++
AquaNet/src/libs/sdk.ts | 2 +
.../icu/samnyan/aqua/net/UserRegistrar.kt | 19 +++++-
.../icu/samnyan/aqua/net/db/AquaNetUser.kt | 4 ++
.../icu/samnyan/aqua/sega/allnet/AllNet.kt | 6 ++
.../aqua/sega/chusan/handler/ChusanApis.kt | 6 ++
.../sega/chusan/handler/ChusanUpsertApis.kt | 19 ++++++
.../aqua/sega/chusan/model/Chu3Repos.kt | 5 ++
.../sega/chusan/model/userdata/UserRegions.kt | 14 +++++
.../samnyan/aqua/sega/maimai2/Maimai2Apis.kt | 34 ++++++++++-
.../samnyan/aqua/sega/maimai2/model/Repos.kt | 7 ++-
.../maimai2/model/userdata/UserEntities.kt | 18 +++++-
.../samnyan/aqua/sega/ongeki/OngekiApis.kt | 6 ++
.../samnyan/aqua/sega/ongeki/OngekiRepos.kt | 5 ++
.../aqua/sega/ongeki/OngekiUpsertAllApi.kt | 22 +++++++
.../sega/ongeki/model/OngekiUserEntities.kt | 12 ++++
.../resources/db/80/V1000_56__prefectures.sql | 38 ++++++++++++
21 files changed, 294 insertions(+), 24 deletions(-)
create mode 100644 AquaNet/src/components/settings/RegionSelector.svelte
create mode 100644 src/main/java/icu/samnyan/aqua/sega/chusan/model/userdata/UserRegions.kt
create mode 100644 src/main/resources/db/80/V1000_56__prefectures.sql
diff --git a/AquaNet/src/components/settings/GeneralGameSettings.svelte b/AquaNet/src/components/settings/GeneralGameSettings.svelte
index 07146fd1..d400792e 100644
--- a/AquaNet/src/components/settings/GeneralGameSettings.svelte
+++ b/AquaNet/src/components/settings/GeneralGameSettings.svelte
@@ -4,6 +4,7 @@
import GameSettingFields from "./GameSettingFields.svelte";
import { t, ts } from "../../libs/i18n";
import useLocalStorage from "../../libs/hooks/useLocalStorage.svelte";
+ import RegionSelector from "./RegionSelector.svelte";
const rounding = useLocalStorage("rounding", true);
@@ -22,6 +23,11 @@
+
+
+ {ts("settings.regionNotice")}
+
+
diff --git a/AquaNet/src/components/settings/RegionSelector.svelte b/AquaNet/src/components/settings/RegionSelector.svelte
new file mode 100644
index 00000000..e2f74711
--- /dev/null
+++ b/AquaNet/src/components/settings/RegionSelector.svelte
@@ -0,0 +1,59 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/AquaNet/src/libs/generalTypes.ts b/AquaNet/src/libs/generalTypes.ts
index 5dd4cd12..715722b0 100644
--- a/AquaNet/src/libs/generalTypes.ts
+++ b/AquaNet/src/libs/generalTypes.ts
@@ -19,6 +19,7 @@ export interface AquaNetUser {
email: string
displayName: string
country: string
+ region:string
lastLogin: number
regTime: number
profileLocation: string
diff --git a/AquaNet/src/libs/i18n/en_ref.ts b/AquaNet/src/libs/i18n/en_ref.ts
index 6213df51..eb9b9ab5 100644
--- a/AquaNet/src/libs/i18n/en_ref.ts
+++ b/AquaNet/src/libs/i18n/en_ref.ts
@@ -195,7 +195,11 @@ export const EN_REF_SETTINGS = {
'settings.export': 'Export Player Data',
'settings.batchManualExport': "Export in Batch Manual (for Tachi)",
'settings.cabNotice': "Note: These settings will only affect your own cab/setup. If you're playing on someone else's setup, please contact them to change these settings.",
- 'settings.gameNotice': "These only apply to Mai and Wacca."
+ 'settings.gameNotice': "These only apply to Mai and Wacca.",
+ 'settings.regionNotice': "These only apply to Mai, Ongeki and Chuni.",
+ 'settings.regionSelector.title': "Prefecture Selector",
+ 'settings.regionSelector.desc': "Select the region where you want the game to think you are playing",
+ 'settings.regionSelector.select': "Select Prefecture",
}
export const EN_REF_USERBOX = {
diff --git a/AquaNet/src/libs/i18n/zh.ts b/AquaNet/src/libs/i18n/zh.ts
index de3c0236..a56eefda 100644
--- a/AquaNet/src/libs/i18n/zh.ts
+++ b/AquaNet/src/libs/i18n/zh.ts
@@ -208,6 +208,14 @@ const zhSettings: typeof EN_REF_SETTINGS = {
'settings.batchManualExport': "导出 Batch Manual 格式(用于 Tachi)",
'settings.cabNotice': '注意:下面这些设置只会影响你自己的机器,如果你是在其他人的机器上玩的话,请联系机主来改设置',
'settings.gameNotice': "这些设置仅对舞萌和华卡生效。",
+ // AI
+ 'settings.regionNotice': "这些设置仅适用于舞萌、音击和中二。",
+ // AI
+ 'settings.regionSelector.title': "地区选择器",
+ // AI
+ 'settings.regionSelector.desc': "选择游戏中显示的地区",
+ // AI
+ 'settings.regionSelector.select': "选择地区",
}
export const zhUserbox: typeof EN_REF_USERBOX = {
diff --git a/AquaNet/src/libs/sdk.ts b/AquaNet/src/libs/sdk.ts
index 38ae98e6..c6e36a72 100644
--- a/AquaNet/src/libs/sdk.ts
+++ b/AquaNet/src/libs/sdk.ts
@@ -196,6 +196,8 @@ export const USER = {
},
isLoggedIn,
ensureLoggedIn,
+ changeRegion: (regionId: number) =>
+ post('/api/v2/user/change-region', { regionId }),
}
export const USERBOX = {
diff --git a/src/main/java/icu/samnyan/aqua/net/UserRegistrar.kt b/src/main/java/icu/samnyan/aqua/net/UserRegistrar.kt
index d2f39e78..bf9aed47 100644
--- a/src/main/java/icu/samnyan/aqua/net/UserRegistrar.kt
+++ b/src/main/java/icu/samnyan/aqua/net/UserRegistrar.kt
@@ -161,7 +161,7 @@ class UserRegistrar(
// Check if user exists, treat as email / username
val user = async { userRepo.findByEmailIgnoreCase(email) ?: userRepo.findByUsernameIgnoreCase(email) }
?: return SUCCESS // obviously dont tell them if the email exists or not
-
+
// Check if email is verified
if (!user.emailConfirmed && emailProps.enable) 400 - "Email not verified"
@@ -179,7 +179,7 @@ class UserRegistrar(
// Send a password reset email
emailService.sendPasswordReset(user)
-
+
return SUCCESS
}
@@ -189,7 +189,7 @@ class UserRegistrar(
@RP token: Str, @RP password: Str,
request: HttpServletRequest
) : Any {
-
+
// Find the reset token
val reset = async { resetPasswordRepo.findByToken(token) }
@@ -302,4 +302,17 @@ class UserRegistrar(
SUCCESS
}
+
+ @API("/change-region")
+ @Doc("Change the region of the user.", "Success message")
+ suspend fun changeRegion(@RP token: Str, @RP regionId: Str) = jwt.auth(token) { u ->
+ // Check if the region is valid (between 1 and 47)
+ val r = regionId.toIntOrNull() ?: (400 - "Invalid region")
+ if (r !in 1..47) 400 - "Invalid region"
+ async {
+ userRepo.save(u.apply { region = r.toString() })
+ }
+
+ SUCCESS
+ }
}
diff --git a/src/main/java/icu/samnyan/aqua/net/db/AquaNetUser.kt b/src/main/java/icu/samnyan/aqua/net/db/AquaNetUser.kt
index 17b90ed6..8651f41a 100644
--- a/src/main/java/icu/samnyan/aqua/net/db/AquaNetUser.kt
+++ b/src/main/java/icu/samnyan/aqua/net/db/AquaNetUser.kt
@@ -43,6 +43,10 @@ class AquaNetUser(
@Column(length = 3)
var country: String = "",
+ // Region code at most 2 characters
+ @Column(length = 2)
+ var region: String = "",
+
// Last login time
var lastLogin: Long = 0L,
diff --git a/src/main/java/icu/samnyan/aqua/sega/allnet/AllNet.kt b/src/main/java/icu/samnyan/aqua/sega/allnet/AllNet.kt
index 00a88c86..c0c6a6b4 100644
--- a/src/main/java/icu/samnyan/aqua/sega/allnet/AllNet.kt
+++ b/src/main/java/icu/samnyan/aqua/sega/allnet/AllNet.kt
@@ -103,6 +103,7 @@ class AllNet(
// encode UTF-8, format_ver 3, hops 1, token 2010451813
val reqMap = decodeAllNet(dataStream.readAllBytes())
val serial = reqMap["serial"] ?: ""
+ var region = props.map.mut["region0"] ?: "1"
logger.info("AllNet /PowerOn : $reqMap")
var session: String? = null
@@ -114,6 +115,10 @@ class AllNet(
if (u != null) {
// Create a new session for the user
logger.info("> Keychip authenticated: ${u.auId} ${u.computedName}")
+ // If the user defined its own region apply it
+ if (u.region.isNotBlank()) {
+ region = u.region
+ }
session = keychipSessionService.new(u, reqMap["game_id"] ?: "").token
}
@@ -140,6 +145,7 @@ class AllNet(
val resp = props.map.mut + mapOf(
"uri" to switchUri(here, localPort, gameId, ver, session),
"host" to props.host.ifBlank { here },
+ "region0" to region
)
// Different responses for different versions
diff --git a/src/main/java/icu/samnyan/aqua/sega/chusan/handler/ChusanApis.kt b/src/main/java/icu/samnyan/aqua/sega/chusan/handler/ChusanApis.kt
index b8a55e4a..af9ef82d 100644
--- a/src/main/java/icu/samnyan/aqua/sega/chusan/handler/ChusanApis.kt
+++ b/src/main/java/icu/samnyan/aqua/sega/chusan/handler/ChusanApis.kt
@@ -288,6 +288,12 @@ fun ChusanController.chusanInit() {
)
}
+ "GetUserRegion" {
+ db.userRegions.findByUser_Card_ExtId(uid)
+ .map { mapOf("regionId" to it.regionId, "playCount" to it.playCount) }
+ .let { mapOf("userId" to uid, "userRegionList" to it) }
+ }
+
// Game settings
"GetGameSetting" {
val version = data["version"].toString()
diff --git a/src/main/java/icu/samnyan/aqua/sega/chusan/handler/ChusanUpsertApis.kt b/src/main/java/icu/samnyan/aqua/sega/chusan/handler/ChusanUpsertApis.kt
index ccbe9f45..fd07ac29 100644
--- a/src/main/java/icu/samnyan/aqua/sega/chusan/handler/ChusanUpsertApis.kt
+++ b/src/main/java/icu/samnyan/aqua/sega/chusan/handler/ChusanUpsertApis.kt
@@ -29,6 +29,25 @@ fun ChusanController.upsertApiInit() {
userNameEx = ""
}.also { db.userData.saveAndFlush(it) }
+ // Only save if it is a valid region and the user has played at least a song
+ if (req.userPlaylogList?.isNotEmpty() == true) {
+ val region = req.userPlaylogList!![0].regionId
+
+ val userRegion = db.userRegions.findByUserIdAndRegionId(u.id, region)
+ if (userRegion.isPresent) {
+ userRegion.get().apply {
+ playCount += 1
+ db.userRegions.save(this)
+ }
+ } else {
+ db.userRegions.save(UserRegions().apply {
+ user = u
+ regionId = region
+ playCount = 1
+ })
+ }
+ }
+
versionHelper[u.lastClientId] = u.lastDataVersion
// Set users
diff --git a/src/main/java/icu/samnyan/aqua/sega/chusan/model/Chu3Repos.kt b/src/main/java/icu/samnyan/aqua/sega/chusan/model/Chu3Repos.kt
index 936c316f..adf1a16c 100644
--- a/src/main/java/icu/samnyan/aqua/sega/chusan/model/Chu3Repos.kt
+++ b/src/main/java/icu/samnyan/aqua/sega/chusan/model/Chu3Repos.kt
@@ -174,6 +174,10 @@ interface Chu3GameLoginBonusRepo : JpaRepository {
fun findByRequiredDays(version: Int, presetId: Int, requiredDays: Int): Optional
}
+interface Chu3UserRegionsRepo: Chu3UserLinked {
+ fun findByUserIdAndRegionId(userId: Long, regionId: Int): Optional
+}
+
@Component
class Chu3Repos(
val userLoginBonus: Chu3UserLoginBonusRepo,
@@ -191,6 +195,7 @@ class Chu3Repos(
val userMap: Chu3UserMapRepo,
val userMusicDetail: Chu3UserMusicDetailRepo,
val userPlaylog: Chu3UserPlaylogRepo,
+ val userRegions: Chu3UserRegionsRepo,
val userCMission: Chu3UserCMissionRepo,
val userCMissionProgress: Chu3UserCMissionProgressRepo,
val netBattleLog: Chu3NetBattleLogRepo,
diff --git a/src/main/java/icu/samnyan/aqua/sega/chusan/model/userdata/UserRegions.kt b/src/main/java/icu/samnyan/aqua/sega/chusan/model/userdata/UserRegions.kt
new file mode 100644
index 00000000..84fdf608
--- /dev/null
+++ b/src/main/java/icu/samnyan/aqua/sega/chusan/model/userdata/UserRegions.kt
@@ -0,0 +1,14 @@
+package icu.samnyan.aqua.sega.chusan.model.userdata
+
+import jakarta.persistence.Entity
+import jakarta.persistence.Table
+import jakarta.persistence.UniqueConstraint
+import java.time.LocalDate
+
+@Entity(name = "ChusanUserRegions")
+@Table(name = "chusan_user_regions", uniqueConstraints = [UniqueConstraint(columnNames = ["user_id", "region_id"])])
+class UserRegions : Chu3UserEntity() {
+ var regionId = 0
+ var playCount = 0
+ var created: String = LocalDate.now().toString()
+}
diff --git a/src/main/java/icu/samnyan/aqua/sega/maimai2/Maimai2Apis.kt b/src/main/java/icu/samnyan/aqua/sega/maimai2/Maimai2Apis.kt
index b5e4609b..014bda83 100644
--- a/src/main/java/icu/samnyan/aqua/sega/maimai2/Maimai2Apis.kt
+++ b/src/main/java/icu/samnyan/aqua/sega/maimai2/Maimai2Apis.kt
@@ -7,6 +7,7 @@ import icu.samnyan.aqua.sega.general.model.CardStatus
import icu.samnyan.aqua.sega.maimai2.model.UserRivalMusic
import icu.samnyan.aqua.sega.maimai2.model.UserRivalMusicDetail
import icu.samnyan.aqua.sega.maimai2.model.userdata.Mai2UserKaleidx
+import icu.samnyan.aqua.sega.maimai2.model.userdata.UserRegions
import java.time.LocalDate
fun Maimai2ServletController.initApis() {
@@ -134,6 +135,31 @@ fun Maimai2ServletController.initApis() {
res["returnCode"] = 0
}
+ // Get regionId from request
+ val region = data["regionId"] as? Int
+
+ // Only save if it is a valid region and the user has played at least a song
+ if (region!=null && region > 0 && d != null) {
+ val userRegion = db.userRegions.findByUserIdAndRegionId(uid, region)
+ if (userRegion.isPresent) {
+ userRegion.get().apply {
+ playCount += 1
+ db.userRegions.save(this)
+ }
+ } else {
+ logger().info("user: $d")
+ logger().info("region: $region")
+
+// Create a new user region row
+ // Crea una nueva fila de región de usuario
+ db.userRegions.save(UserRegions().apply {
+ user = d
+ regionId = region
+ playCount = 1
+ })
+ }
+ }
+
res
}
@@ -178,13 +204,19 @@ fun Maimai2ServletController.initApis() {
mapOf("userId" to uid, "rivalId" to rivalId, "nextIndex" to 0, "userRivalMusicList" to res.values)
}
+ "GetUserRegion" {
+ logger().info("Getting user regions for user $uid")
+ db.userRegions.findByUser_Card_ExtId(uid)
+ .map { mapOf("regionId" to it.regionId, "playCount" to it.playCount) }
+ .let { mapOf("userId" to uid, "userRegionList" to it) }
+ }
+
"GetUserIntimate".unpaged {
val u = db.userData.findByCardExtId(uid)() ?: (404 - "User not found")
db.userIntimate.findByUser(u)
}
// Empty List Handlers
- "GetUserRegion".unpaged { empty }
"GetUserGhost".unpaged { empty }
"GetUserFriendBonus" { mapOf("userId" to uid, "returnCode" to 0, "getMiles" to 0) }
"GetTransferFriend" { mapOf("userId" to uid, "transferFriendList" to empty) }
diff --git a/src/main/java/icu/samnyan/aqua/sega/maimai2/model/Repos.kt b/src/main/java/icu/samnyan/aqua/sega/maimai2/model/Repos.kt
index 3718971b..0263bdc9 100644
--- a/src/main/java/icu/samnyan/aqua/sega/maimai2/model/Repos.kt
+++ b/src/main/java/icu/samnyan/aqua/sega/maimai2/model/Repos.kt
@@ -127,6 +127,10 @@ interface Mai2GameEventRepo : JpaRepository {
interface Mai2GameSellingCardRepo : JpaRepository
+interface Mai2UserRegionsRepo: Mai2UserLinked {
+ fun findByUserIdAndRegionId(userId: Long, regionId: Int): Optional
+}
+
@Component
class Mai2Repos(
val mapEncountNpc: Mai2MapEncountNpcRepo,
@@ -152,5 +156,6 @@ class Mai2Repos(
val userIntimate: MAi2UserIntimateRepo,
val gameCharge: Mai2GameChargeRepo,
val gameEvent: Mai2GameEventRepo,
- val gameSellingCard: Mai2GameSellingCardRepo
+ val gameSellingCard: Mai2GameSellingCardRepo,
+ val userRegions: Mai2UserRegionsRepo,
)
diff --git a/src/main/java/icu/samnyan/aqua/sega/maimai2/model/userdata/UserEntities.kt b/src/main/java/icu/samnyan/aqua/sega/maimai2/model/userdata/UserEntities.kt
index 211a1011..47548f88 100644
--- a/src/main/java/icu/samnyan/aqua/sega/maimai2/model/userdata/UserEntities.kt
+++ b/src/main/java/icu/samnyan/aqua/sega/maimai2/model/userdata/UserEntities.kt
@@ -21,6 +21,7 @@ import java.time.format.DateTimeFormatter
import com.fasterxml.jackson.databind.JsonSerializer
import com.fasterxml.jackson.databind.SerializerProvider
import com.fasterxml.jackson.core.JsonGenerator
+import java.time.LocalDate
@MappedSuperclass
open class Mai2UserEntity : BaseEntity(), IUserEntity {
@@ -451,9 +452,9 @@ class Mai2UserPlaylog : Mai2UserEntity(), IGenericGamePlaylog {
get() = maxCombo == totalCombo
override val isAllPerfect: Boolean
- get() = tapMiss + tapGood + tapGreat == 0 &&
- holdMiss + holdGood + holdGreat == 0 &&
- slideMiss + slideGood + slideGreat == 0 &&
+ get() = tapMiss + tapGood + tapGreat == 0 &&
+ holdMiss + holdGood + holdGreat == 0 &&
+ slideMiss + slideGood + slideGreat == 0 &&
touchMiss + touchGood + touchGreat == 0 &&
breakMiss + breakGood + breakGreat == 0
}
@@ -551,6 +552,17 @@ class Mai2UserIntimate : Mai2UserEntity() {
var intimateCountRewarded = 0;
}
+@Entity(name = "Maimai2UserRegions")
+@Table(
+ name = "maimai2_user_regions",
+ uniqueConstraints = [UniqueConstraint(columnNames = ["user_id", "region_id"])]
+)
+class UserRegions : Mai2UserEntity() {
+ var regionId = 0
+ var playCount = 0
+ var created: String = LocalDate.now().toString()
+}
+
val MAIMAI_DATETIME = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.0")
class MaimaiDateSerializer : JsonSerializer() {
override fun serialize(v: LocalDateTime, j: JsonGenerator, s: SerializerProvider) {
diff --git a/src/main/java/icu/samnyan/aqua/sega/ongeki/OngekiApis.kt b/src/main/java/icu/samnyan/aqua/sega/ongeki/OngekiApis.kt
index 41bf4a8d..947c9083 100644
--- a/src/main/java/icu/samnyan/aqua/sega/ongeki/OngekiApis.kt
+++ b/src/main/java/icu/samnyan/aqua/sega/ongeki/OngekiApis.kt
@@ -69,4 +69,10 @@ fun OngekiController.ongekiInit() {
"GetClientTestmode" {
empty.staticLst("clientTestmodeList") + mapOf("placeId" to data["placeId"])
}
+
+ "GetUserRegion" {
+ db.regions.findByUser_Card_ExtId(uid)
+ .map { mapOf("regionId" to it.regionId, "playCount" to it.playCount) }
+ .staticLst("userRegionList") + mapOf("userId" to uid)
+ }
}
\ No newline at end of file
diff --git a/src/main/java/icu/samnyan/aqua/sega/ongeki/OngekiRepos.kt b/src/main/java/icu/samnyan/aqua/sega/ongeki/OngekiRepos.kt
index 28a41842..a9af626a 100644
--- a/src/main/java/icu/samnyan/aqua/sega/ongeki/OngekiRepos.kt
+++ b/src/main/java/icu/samnyan/aqua/sega/ongeki/OngekiRepos.kt
@@ -147,6 +147,10 @@ interface OgkUserTrainingRoomRepo : OngekiUserLinked {
fun findByUserAndRoomId(user: UserData, roomId: Int): Optional
}
+interface OgkUserRegionsRepo: OngekiUserLinked {
+ fun findByUserIdAndRegionId(userId: Long, regionId: Int): Optional
+}
+
// Re:Fresh
interface OgkUserEventMapRepo : OngekiUserLinked
interface OgkUserSkinRepo : OngekiUserLinked
@@ -190,6 +194,7 @@ class OngekiUserRepos(
val trainingRoom: OgkUserTrainingRoomRepo,
val eventMap: OgkUserEventMapRepo,
val skin: OgkUserSkinRepo,
+ val regions: OgkUserRegionsRepo,
)
@Component
diff --git a/src/main/java/icu/samnyan/aqua/sega/ongeki/OngekiUpsertAllApi.kt b/src/main/java/icu/samnyan/aqua/sega/ongeki/OngekiUpsertAllApi.kt
index ed38ad93..ed25e9e1 100644
--- a/src/main/java/icu/samnyan/aqua/sega/ongeki/OngekiUpsertAllApi.kt
+++ b/src/main/java/icu/samnyan/aqua/sega/ongeki/OngekiUpsertAllApi.kt
@@ -1,11 +1,13 @@
package icu.samnyan.aqua.sega.ongeki
+import ext.int
import ext.invoke
import ext.mapApply
import ext.minus
import icu.samnyan.aqua.sega.ongeki.model.OngekiUpsertUserAll
import icu.samnyan.aqua.sega.ongeki.model.UserData
import icu.samnyan.aqua.sega.ongeki.model.UserGeneralData
+import icu.samnyan.aqua.sega.ongeki.model.UserRegions
fun OngekiController.initUpsertAll() {
@@ -33,6 +35,26 @@ fun OngekiController.initUpsertAll() {
db.data.save(this)
} ?: oldUser ?: return@api null
+ // User region
+ val region = data["regionId"]?.int ?: 0
+
+ // Only save if it is a valid region and the user has played at least a song
+ if (region > 0 && all.userPlaylogList?.isNotEmpty() == true) {
+ val userRegion = db.regions.findByUserIdAndRegionId(u.id, region)
+ if (userRegion.isPresent) {
+ userRegion.get().apply {
+ playCount += 1
+ db.regions.save(this)
+ }
+ } else {
+ db.regions.save(UserRegions().apply {
+ user = u
+ regionId = region
+ playCount = 1
+ })
+ }
+ }
+
all.run {
// Set users
listOfNotNull(
diff --git a/src/main/java/icu/samnyan/aqua/sega/ongeki/model/OngekiUserEntities.kt b/src/main/java/icu/samnyan/aqua/sega/ongeki/model/OngekiUserEntities.kt
index 59fadaef..5b4f8752 100644
--- a/src/main/java/icu/samnyan/aqua/sega/ongeki/model/OngekiUserEntities.kt
+++ b/src/main/java/icu/samnyan/aqua/sega/ongeki/model/OngekiUserEntities.kt
@@ -7,6 +7,7 @@ import icu.samnyan.aqua.net.games.*
import icu.samnyan.aqua.sega.general.model.Card
import icu.samnyan.aqua.sega.util.jackson.AccessCodeSerializer
import jakarta.persistence.*
+import java.time.LocalDate
@MappedSuperclass
class OngekiUserEntity : BaseEntity(), IUserEntity {
@@ -511,4 +512,15 @@ class UserSkin : OngekiUserEntity() {
var cardId1 = 0
var cardId2 = 0
var cardId3 = 0
+}
+
+@Entity(name = "OngekiUserRegions")
+@Table(
+ name = "ongeki_user_regions",
+ uniqueConstraints = [UniqueConstraint(columnNames = ["user_id", "regionId"])]
+)
+class UserRegions : OngekiUserEntity() {
+ var regionId = 0
+ var playCount = 0
+ var created: String = LocalDate.now().toString()
}
\ No newline at end of file
diff --git a/src/main/resources/db/80/V1000_56__prefectures.sql b/src/main/resources/db/80/V1000_56__prefectures.sql
new file mode 100644
index 00000000..c3e0b9e8
--- /dev/null
+++ b/src/main/resources/db/80/V1000_56__prefectures.sql
@@ -0,0 +1,38 @@
+CREATE TABLE chusan_user_regions
+(
+ id BIGINT AUTO_INCREMENT NOT NULL,
+ user_id BIGINT NULL,
+ region_id INT NOT NULL,
+ play_count INT NOT NULL DEFAULT 1,
+ created VARCHAR(355),
+ PRIMARY KEY (id),
+ CONSTRAINT fk_chusanregions_on_chusan_user_Data FOREIGN KEY (user_id) REFERENCES chusan_user_data (id) ON DELETE CASCADE ON UPDATE CASCADE,
+ CONSTRAINT unq_chusanregions_on_region_user UNIQUE (user_id, region_id)
+);
+
+CREATE TABLE ongeki_user_regions
+(
+ id BIGINT AUTO_INCREMENT NOT NULL,
+ user_id BIGINT NULL,
+ region_id INT NOT NULL,
+ play_count INT NOT NULL DEFAULT 1,
+ created VARCHAR(355),
+ PRIMARY KEY (id),
+ CONSTRAINT fk_ongekiregions_on_aqua_net_user FOREIGN KEY (user_id) REFERENCES aqua_net_user (au_id) ON DELETE CASCADE ON UPDATE CASCADE,
+ CONSTRAINT unq_ongekiregions_on_region_user UNIQUE (user_id, region_id)
+);
+
+CREATE TABLE maimai2_user_regions
+(
+ id BIGINT AUTO_INCREMENT NOT NULL,
+ user_id BIGINT NULL,
+ region_id INT NOT NULL,
+ play_count INT NOT NULL DEFAULT 1,
+ created VARCHAR(355),
+ PRIMARY KEY (id),
+ CONSTRAINT fk_maimai2regions_on_user_Details FOREIGN KEY (user_id) REFERENCES maimai2_user_detail (id) ON DELETE CASCADE ON UPDATE CASCADE,
+ CONSTRAINT unq_maimai2regions_on_region_user UNIQUE (user_id, region_id)
+);
+
+ALTER TABLE aqua_net_user
+ADD COLUMN region VARCHAR(2) NOT NULL DEFAULT '1';
\ No newline at end of file