[O] DIVA utils > kt

This commit is contained in:
Azalea 2025-10-25 07:29:09 +08:00
parent 32c3226db7
commit 8d48ab0d3f
23 changed files with 131 additions and 209 deletions

View File

@ -212,6 +212,8 @@ val <K, V> Map<K, V>.mut get() = toMutableMap()
val <T> Set<T>.mut get() = toMutableSet()
fun <T> List<T>.unique(fn: (T) -> Any) = distinctBy(fn).ifEmpty { null }
val <T> Collection<T>.csv get() = joinToString(",")
val IntArray.csv get() = joinToString(",")
// Optionals
operator fun <T> Optional<T>.invoke(): T? = orElse(null)

View File

@ -1,9 +1,10 @@
package icu.samnyan.aqua.sega.diva.handler
import ext.JDict
import icu.samnyan.aqua.sega.diva.util.DivaMapper
import org.springframework.stereotype.Component
fun buildResultMap(map: MutableMap<String, Any?>) =
fun buildResultMap(map: JDict) =
map.filterValues { it != null && !(it is String && it == "") }
.map { (k, v) -> "$k=$v" }.joinToString("&")
@ -15,5 +16,5 @@ class BaseHandler {
@JvmField
final var mapper = DivaMapper()
fun build(map: MutableMap<String, Any?>) = buildResultMap(map)
fun build(map: JDict) = buildResultMap(map)
}

View File

@ -2,8 +2,8 @@ package icu.samnyan.aqua.sega.diva.handler.card
import ext.invoke
import icu.samnyan.aqua.sega.diva.DivaRepos
import icu.samnyan.aqua.sega.diva.ProfileNotFoundException
import icu.samnyan.aqua.sega.diva.SessionNotFoundException
import icu.samnyan.aqua.sega.diva.util.ProfileNotFoundException
import icu.samnyan.aqua.sega.diva.util.SessionNotFoundException
import icu.samnyan.aqua.sega.diva.model.common.Result
import icu.samnyan.aqua.sega.diva.model.request.card.ChangeNameRequest
import icu.samnyan.aqua.sega.diva.model.response.card.ChangeNameResponse

View File

@ -1,8 +1,8 @@
package icu.samnyan.aqua.sega.diva.handler.card
import icu.samnyan.aqua.sega.diva.DivaRepos
import icu.samnyan.aqua.sega.diva.ProfileNotFoundException
import icu.samnyan.aqua.sega.diva.SessionNotFoundException
import icu.samnyan.aqua.sega.diva.util.ProfileNotFoundException
import icu.samnyan.aqua.sega.diva.util.SessionNotFoundException
import icu.samnyan.aqua.sega.diva.model.common.PassStat
import icu.samnyan.aqua.sega.diva.model.common.Result
import icu.samnyan.aqua.sega.diva.model.request.card.ChangePasswdRequest

View File

@ -2,8 +2,8 @@ package icu.samnyan.aqua.sega.diva.handler.ingame
import icu.samnyan.aqua.sega.diva.DivaCustomizeRepository
import icu.samnyan.aqua.sega.diva.GameSessionRepository
import icu.samnyan.aqua.sega.diva.ProfileNotFoundException
import icu.samnyan.aqua.sega.diva.SessionNotFoundException
import icu.samnyan.aqua.sega.diva.util.ProfileNotFoundException
import icu.samnyan.aqua.sega.diva.util.SessionNotFoundException
import icu.samnyan.aqua.sega.diva.handler.BaseHandler
import icu.samnyan.aqua.sega.diva.model.common.Result
import icu.samnyan.aqua.sega.diva.model.request.ingame.BuyCstmzItmRequest

View File

@ -2,8 +2,8 @@ package icu.samnyan.aqua.sega.diva.handler.ingame
import icu.samnyan.aqua.sega.diva.DivaModuleRepository
import icu.samnyan.aqua.sega.diva.GameSessionRepository
import icu.samnyan.aqua.sega.diva.ProfileNotFoundException
import icu.samnyan.aqua.sega.diva.SessionNotFoundException
import icu.samnyan.aqua.sega.diva.util.ProfileNotFoundException
import icu.samnyan.aqua.sega.diva.util.SessionNotFoundException
import icu.samnyan.aqua.sega.diva.handler.BaseHandler
import icu.samnyan.aqua.sega.diva.model.common.Result
import icu.samnyan.aqua.sega.diva.model.request.ingame.BuyModuleRequest

View File

@ -1,14 +1,14 @@
package icu.samnyan.aqua.sega.diva.handler.ingame
import ext.csv
import icu.samnyan.aqua.sega.diva.PlayerPvCustomizeRepository
import icu.samnyan.aqua.sega.diva.ProfileNotFoundException
import icu.samnyan.aqua.sega.diva.util.ProfileNotFoundException
import icu.samnyan.aqua.sega.diva.handler.BaseHandler
import icu.samnyan.aqua.sega.diva.model.common.Result
import icu.samnyan.aqua.sega.diva.model.request.ingame.ShopExitRequest
import icu.samnyan.aqua.sega.diva.model.response.ingame.ShopExitResponse
import icu.samnyan.aqua.sega.diva.model.userdata.PlayerPvCustomize
import icu.samnyan.aqua.sega.diva.service.PlayerProfileService
import icu.samnyan.aqua.sega.diva.util.DivaStringUtils
import org.springframework.stereotype.Component
import java.util.function.Supplier
@ -27,18 +27,18 @@ class ShopExitHandler(
.orElseGet(Supplier { PlayerPvCustomize(profile, request.ply_pv_id) })
if (request.use_pv_mdl_eqp == 1) {
customize.module = DivaStringUtils.arrToCsv(request.mdl_eqp_pv_ary)
customize.customize = DivaStringUtils.arrToCsv(request.c_itm_eqp_pv_ary)
customize.customizeFlag = DivaStringUtils.arrToCsv(request.ms_itm_flg_pv_ary)
customize.module = request.mdl_eqp_pv_ary.csv
customize.customize = request.c_itm_eqp_pv_ary.csv
customize.customizeFlag = request.ms_itm_flg_pv_ary.csv
} else {
customize.module = "-1,-1,-1"
customize.customize = "-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1"
customize.customizeFlag = "1,1,1,1,1,1,1,1,1,1,1,1"
}
profile.commonModule = DivaStringUtils.arrToCsv(request.mdl_eqp_cmn_ary)
profile.commonCustomizeItems = DivaStringUtils.arrToCsv(request.c_itm_eqp_cmn_ary)
profile.moduleSelectItemFlag = DivaStringUtils.arrToCsv(request.ms_itm_flg_cmn_ary)
profile.commonModule = request.mdl_eqp_cmn_ary.csv
profile.commonCustomizeItems = request.c_itm_eqp_cmn_ary.csv
profile.moduleSelectItemFlag = request.ms_itm_flg_cmn_ary.csv
playerProfileService.save(profile)
pvCustomizeRepository.save<PlayerPvCustomize?>(customize)

View File

@ -8,8 +8,8 @@ import icu.samnyan.aqua.sega.diva.PlayerContestRepository
import icu.samnyan.aqua.sega.diva.PlayerCustomizeRepository
import icu.samnyan.aqua.sega.diva.PlayerInventoryRepository
import icu.samnyan.aqua.sega.diva.PlayerPvRecordRepository
import icu.samnyan.aqua.sega.diva.ProfileNotFoundException
import icu.samnyan.aqua.sega.diva.SessionNotFoundException
import icu.samnyan.aqua.sega.diva.util.ProfileNotFoundException
import icu.samnyan.aqua.sega.diva.util.SessionNotFoundException
import icu.samnyan.aqua.sega.diva.handler.BaseHandler
import icu.samnyan.aqua.sega.diva.model.common.*
import icu.samnyan.aqua.sega.diva.model.request.ingame.StageResultRequest

View File

@ -1,8 +1,8 @@
package icu.samnyan.aqua.sega.diva.handler.ingame
import icu.samnyan.aqua.sega.diva.GameSessionRepository
import icu.samnyan.aqua.sega.diva.ProfileNotFoundException
import icu.samnyan.aqua.sega.diva.SessionNotFoundException
import icu.samnyan.aqua.sega.diva.util.ProfileNotFoundException
import icu.samnyan.aqua.sega.diva.util.SessionNotFoundException
import icu.samnyan.aqua.sega.diva.handler.BaseHandler
import icu.samnyan.aqua.sega.diva.model.request.ingame.StageStartRequest
import icu.samnyan.aqua.sega.diva.model.response.BaseResponse

View File

@ -1,14 +1,14 @@
package icu.samnyan.aqua.sega.diva.handler.ingame
import ext.csv
import ext.logger
import icu.samnyan.aqua.sega.diva.PlayerScreenShotRepository
import icu.samnyan.aqua.sega.diva.ProfileNotFoundException
import icu.samnyan.aqua.sega.diva.util.ProfileNotFoundException
import icu.samnyan.aqua.sega.diva.handler.BaseHandler
import icu.samnyan.aqua.sega.diva.model.request.ingame.StoreSsRequest
import icu.samnyan.aqua.sega.diva.model.response.BaseResponse
import icu.samnyan.aqua.sega.diva.model.userdata.PlayerScreenShot
import icu.samnyan.aqua.sega.diva.service.PlayerProfileService
import icu.samnyan.aqua.sega.diva.util.DivaStringUtils
import org.springframework.stereotype.Component
import org.springframework.web.multipart.MultipartFile
import java.io.IOException
@ -41,8 +41,8 @@ class StoreSsHandler(
profile,
filename,
request.pd_id,
DivaStringUtils.arrToCsv(request.ss_mdl_id),
DivaStringUtils.arrToCsv(request.ss_c_itm_id)
request.ss_mdl_id.csv,
request.ss_c_itm_id.csv
)
screenShotRepository.save<PlayerScreenShot?>(ss)

View File

@ -3,8 +3,8 @@ package icu.samnyan.aqua.sega.diva.handler.user
import icu.samnyan.aqua.sega.diva.ContestRepository
import icu.samnyan.aqua.sega.diva.GameSessionRepository
import icu.samnyan.aqua.sega.diva.PlayerContestRepository
import icu.samnyan.aqua.sega.diva.ProfileNotFoundException
import icu.samnyan.aqua.sega.diva.SessionNotFoundException
import icu.samnyan.aqua.sega.diva.util.ProfileNotFoundException
import icu.samnyan.aqua.sega.diva.util.SessionNotFoundException
import icu.samnyan.aqua.sega.diva.handler.BaseHandler
import icu.samnyan.aqua.sega.diva.model.common.ContestBorder
import icu.samnyan.aqua.sega.diva.model.common.Difficulty

View File

@ -1,8 +1,8 @@
package icu.samnyan.aqua.sega.diva.handler.user
import icu.samnyan.aqua.sega.diva.GameSessionRepository
import icu.samnyan.aqua.sega.diva.ProfileNotFoundException
import icu.samnyan.aqua.sega.diva.SessionNotFoundException
import icu.samnyan.aqua.sega.diva.util.ProfileNotFoundException
import icu.samnyan.aqua.sega.diva.util.SessionNotFoundException
import icu.samnyan.aqua.sega.diva.handler.BaseHandler
import icu.samnyan.aqua.sega.diva.model.request.user.PdUnlockRequest
import icu.samnyan.aqua.sega.diva.model.response.BaseResponse

View File

@ -1,6 +1,6 @@
package icu.samnyan.aqua.sega.diva.handler.user
import icu.samnyan.aqua.sega.diva.ProfileNotFoundException
import icu.samnyan.aqua.sega.diva.util.ProfileNotFoundException
import icu.samnyan.aqua.sega.diva.handler.BaseHandler
import icu.samnyan.aqua.sega.diva.model.request.user.SpendCreditRequest
import icu.samnyan.aqua.sega.diva.model.response.user.SpendCreditResponse

View File

@ -14,6 +14,9 @@ import icu.samnyan.aqua.sega.diva.model.userdata.PlayerPvRecord
import icu.samnyan.aqua.sega.diva.service.PlayerCustomizeService
import icu.samnyan.aqua.sega.diva.service.PlayerModuleService
import icu.samnyan.aqua.sega.diva.service.PlayerProfileService
import icu.samnyan.aqua.sega.diva.util.ProfileNotFoundException
import icu.samnyan.aqua.sega.diva.util.PvRecordDataException
import icu.samnyan.aqua.sega.diva.util.SessionNotFoundException
import org.springframework.stereotype.Component
import java.time.LocalDateTime
import java.util.*

View File

@ -1,37 +0,0 @@
package icu.samnyan.aqua.sega.diva.util;
import icu.samnyan.aqua.sega.diva.PlayerPvRecordRepository;
import icu.samnyan.aqua.sega.diva.model.common.Edition;
import icu.samnyan.aqua.sega.diva.model.common.LevelInfo;
import icu.samnyan.aqua.sega.diva.model.userdata.PlayerProfile;
import icu.samnyan.aqua.sega.diva.model.userdata.PlayerPvRecord;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* @author samnyan (privateamusement@protonmail.com)
*/
@Component
public class DivaCalculator {
private final PlayerPvRecordRepository playerPvRecordRepository;
public DivaCalculator(PlayerPvRecordRepository playerPvRecordRepository) {
this.playerPvRecordRepository = playerPvRecordRepository;
}
public LevelInfo getLevelInfo(PlayerProfile profile) {
List<PlayerPvRecord> recordList = playerPvRecordRepository.findByPdIdAndEdition(profile, Edition.ORIGINAL);
int totalAttain = 0;
for (PlayerPvRecord record :
recordList) {
totalAttain += record.getMaxAttain();
}
int level = totalAttain / 13979;
int exp = Math.round((totalAttain % 13979) / 13979.0f * 100.0f);
return new LevelInfo(level + 1, exp);
}
}

View File

@ -1,27 +0,0 @@
package icu.samnyan.aqua.sega.diva.util;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
import java.io.IOException;
import java.time.LocalDateTime;
/**
* @author samnyan (privateamusement@protonmail.com)
*/
public class DivaDateTimeSerializer extends StdSerializer<LocalDateTime> {
public DivaDateTimeSerializer() {
this(null);
}
public DivaDateTimeSerializer(Class<LocalDateTime> t) {
super(t);
}
@Override
public void serialize(LocalDateTime value, JsonGenerator gen, SerializerProvider provider) throws IOException {
gen.writeString(DivaDateTimeUtil.getString(value));
}
}

View File

@ -1,18 +0,0 @@
package icu.samnyan.aqua.sega.diva.util;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
/**
* @author samnyan (privateamusement@protonmail.com)
*/
public class DivaDateTimeUtil {
public static String getString(LocalDateTime time) {
return URIEncoder.encode(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.0").format(time));
}
public static String format(LocalDateTime time) {
return DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.0").format(time);
}
}

View File

@ -1,59 +0,0 @@
package icu.samnyan.aqua.sega.diva.util;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.json.JsonWriteFeature;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.json.JsonMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import icu.samnyan.aqua.sega.util.BooleanNumberDeserializer;
import icu.samnyan.aqua.sega.util.BooleanNumberSerializer;
import icu.samnyan.aqua.sega.util.ZonedDateTimeDeserializer;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* @author samnyan (privateamusement@protonmail.com)
*/
@Component
public class DivaMapper {
private final ObjectMapper mapper;
public DivaMapper() {
SimpleModule module = new SimpleModule();
module.addSerializer(LocalDateTime.class, new DivaDateTimeSerializer());
module.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.0")));
module.addDeserializer(ZonedDateTime.class, new ZonedDateTimeDeserializer());
module.addSerializer(Boolean.class, new BooleanNumberSerializer());
module.addSerializer(boolean.class, new BooleanNumberSerializer());
module.addDeserializer(Boolean.class, new BooleanNumberDeserializer());
module.addDeserializer(boolean.class, new BooleanNumberDeserializer());
mapper = JsonMapper.builder().enable(JsonWriteFeature.WRITE_NUMBERS_AS_STRINGS)
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
.build();
mapper.registerModule(module);
}
public String write(Object o) throws JsonProcessingException {
return mapper.writeValueAsString(o);
}
public <T> T convert(Map<String, Object> map, Class<T> toClass) {
return mapper.convertValue(map, toClass);
}
public LinkedHashMap<String, Object> toMap(Object object) {
return mapper.convertValue(object, new TypeReference<>() {
});
}
}

View File

@ -0,0 +1,38 @@
package icu.samnyan.aqua.sega.diva.util
import com.fasterxml.jackson.core.json.JsonWriteFeature
import com.fasterxml.jackson.core.type.TypeReference
import com.fasterxml.jackson.databind.DeserializationFeature
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.databind.json.JsonMapper
import com.fasterxml.jackson.databind.module.SimpleModule
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer
import ext.JDict
import icu.samnyan.aqua.sega.util.BooleanNumberDeserializer
import icu.samnyan.aqua.sega.util.BooleanNumberSerializer
import icu.samnyan.aqua.sega.util.ZonedDateTimeDeserializer
import org.springframework.stereotype.Component
import java.time.LocalDateTime
import java.time.ZonedDateTime
import java.time.format.DateTimeFormatter
@Component
class DivaMapper {
private val mapper: ObjectMapper = JsonMapper.builder().enable(JsonWriteFeature.WRITE_NUMBERS_AS_STRINGS)
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
.build().apply {
registerModule(SimpleModule().apply {
addSerializer(LocalDateTime::class.java, DivaDateTimeSerializer())
addDeserializer(LocalDateTime::class.java, LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.0")))
addDeserializer(ZonedDateTime::class.java, ZonedDateTimeDeserializer())
addSerializer(Boolean::class.java, BooleanNumberSerializer())
addSerializer(Boolean::class.javaPrimitiveType, BooleanNumberSerializer())
addDeserializer(Boolean::class.java, BooleanNumberDeserializer())
addDeserializer(Boolean::class.javaPrimitiveType, BooleanNumberDeserializer())
})
}
fun write(o: Any) = mapper.writeValueAsString(o)
fun <T> convert(map: JDict, toClass: Class<T>) = mapper.convertValue<T>(map, toClass)
fun toMap(obj: Any) = mapper.convertValue(obj, object : TypeReference<LinkedHashMap<String, Any>>() {})
}

View File

@ -1,24 +0,0 @@
package icu.samnyan.aqua.sega.diva.util;
/**
* @author samnyan (privateamusement@protonmail.com)
*/
public class DivaStringUtils {
public static String arrToCsv(int[] arr) {
StringBuilder sb = new StringBuilder();
for (int i :
arr) {
sb.append(i).append(",");
}
sb.deleteCharAt(sb.length() - 1);
return sb.toString();
}
public static String getDummyString(String content, int length) {
StringBuilder sb = new StringBuilder();
sb.append((content + ",").repeat(length));
sb.deleteCharAt(sb.length() - 1);
return sb.toString();
}
}

View File

@ -0,0 +1,55 @@
package icu.samnyan.aqua.sega.diva.util
import com.fasterxml.jackson.core.JsonGenerator
import com.fasterxml.jackson.databind.SerializerProvider
import com.fasterxml.jackson.databind.ser.std.StdSerializer
import icu.samnyan.aqua.sega.diva.PlayerPvRecordRepository
import icu.samnyan.aqua.sega.diva.model.common.Edition
import icu.samnyan.aqua.sega.diva.model.common.LevelInfo
import icu.samnyan.aqua.sega.diva.model.userdata.PlayerProfile
import org.springframework.stereotype.Component
import java.net.URLEncoder
import java.nio.charset.StandardCharsets
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
import kotlin.math.roundToInt
object DivaStringUtils {
@JvmStatic
fun getDummyString(content: String, length: Int) = "$content,".repeat(length).removeSuffix(",")
}
object DivaDateTimeUtil {
@JvmStatic
fun getString(time: LocalDateTime) =
URIEncoder.encode(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.0").format(time))
@JvmStatic
fun format(time: LocalDateTime) = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.0").format(time)
}
class DivaDateTimeSerializer(t: Class<LocalDateTime>? = null) : StdSerializer<LocalDateTime>(t) {
override fun serialize(value: LocalDateTime, gen: JsonGenerator, provider: SerializerProvider) {
gen.writeString(DivaDateTimeUtil.getString(value))
}
}
@Component
class DivaCalculator(private val playerPvRecordRepository: PlayerPvRecordRepository) {
fun getLevelInfo(profile: PlayerProfile): LevelInfo {
val recordList = playerPvRecordRepository.findByPdIdAndEdition(profile, Edition.ORIGINAL)
var totalAttain = 0
for (record in recordList) {
totalAttain += record.maxAttain
}
val level = totalAttain / 13979
val exp = ((totalAttain % 13979) / 13979.0f * 100.0f).roundToInt()
return LevelInfo(level + 1, exp)
}
}
object URIEncoder {
@JvmStatic
fun encode(str: String) = URLEncoder.encode(str, StandardCharsets.UTF_8).replace("\\+".toRegex(), "%20")
}

View File

@ -1,4 +1,4 @@
package icu.samnyan.aqua.sega.diva
package icu.samnyan.aqua.sega.diva.util
class PvRecordDataException(message: String?) : RuntimeException(message)
class SessionNotFoundException : RuntimeException()

View File

@ -1,12 +0,0 @@
package icu.samnyan.aqua.sega.diva.util
import java.net.URLEncoder
import java.nio.charset.StandardCharsets
/**
* @author samnyan (privateamusement@protonmail.com)
*/
object URIEncoder {
@JvmStatic
fun encode(str: String) = URLEncoder.encode(str, StandardCharsets.UTF_8).replace("\\+".toRegex(), "%20")
}