[O] Rewrite GetUserMusic

matching
Azalea 2024-12-26 21:30:34 -05:00
parent fa1d69f1f9
commit 806e24b9f1
5 changed files with 16 additions and 263 deletions

View File

@ -10,6 +10,7 @@ import icu.samnyan.aqua.sega.chusan.model.response.data.MatchingMemberInfo
import icu.samnyan.aqua.sega.chusan.model.response.data.MatchingWaitState
import icu.samnyan.aqua.sega.chusan.model.response.data.UserEmoney
import icu.samnyan.aqua.sega.chusan.model.userdata.UserCharge
import icu.samnyan.aqua.sega.chusan.model.userdata.UserMusicDetail
import icu.samnyan.aqua.sega.general.BaseHandler
import icu.samnyan.aqua.sega.general.RequestContext
import icu.samnyan.aqua.sega.general.SpecialHandler
@ -33,8 +34,6 @@ import kotlin.reflect.full.declaredMemberProperties
@API(value = ["/g/chu3/{version}/ChuniServlet", "/g/chu3/{version}"])
class ChusanServletController(
val gameLogin: GameLoginHandler,
val getUserMusic: GetUserMusicHandler,
val getUserRecentRating: GetUserRecentRatingHandler,
val upsertUserAll: UpsertUserAllHandler,
val cmGetUserCharacter: CMGetUserCharacterHandler,
val cmUpsertUserGacha: CMUpsertUserGachaHandler,
@ -50,10 +49,8 @@ class ChusanServletController(
val log = LoggerFactory.getLogger(ChusanServletController::class.java)
// Below are code related to handling the handlers
val externalHandlers = mutableListOf(
"GameLoginApi", "GetUserMusicApi", "UpsertUserAllApi",
"CMGetUserCharacterApi", "CMUpsertUserGachaApi",
"CMUpsertUserPrintCancelApi", "CMUpsertUserPrintSubtractApi")
val externalHandlers = mutableListOf("GameLoginApi", "UpsertUserAllApi", "CMGetUserCharacterApi",
"CMUpsertUserGachaApi", "CMUpsertUserPrintCancelApi", "CMUpsertUserPrintSubtractApi")
val noopEndpoint = setOf("UpsertClientBookkeepingApi", "UpsertClientDevelopApi", "UpsertClientErrorApi",
"UpsertClientSettingApi", "UpsertClientTestmodeApi", "CreateTokenApi", "RemoveTokenApi", "UpsertClientUploadApi",
@ -263,6 +260,19 @@ fun ChusanServletController.init() {
) + userDict
}
"GetUserMusic" {
// Compatibility: Older chusan uses boolean for isSuccess
fun checkAncient(d: List<UserMusicDetail>) =
data["version"]?.double?.let { if (it >= 2.15) d else d.map {
d.toJson().jsonMap().toMutableMap().apply { this["isSuccess"] = this["isSuccess"].truthy }
} } ?: d
val lst = db.userMusicDetail.findByUser_Card_ExtId(uid).groupBy { it.musicId }
.mapValues { mapOf("length" to it.value.size, "userMusicDetailList" to checkAncient(it.value)) }
mapOf("userId" to uid, "length" to lst.size, "nextIndex" to -1, "userMusicList" to lst.values)
}
"GetUserLoginBonus" api@ {
if (!props.loginBonusEnable) return@api mapOf("userId" to uid, "length" to 0, "userLoginBonusList" to empty)

View File

@ -1,84 +0,0 @@
package icu.samnyan.aqua.sega.chusan.dto;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
@Data
@NoArgsConstructor
@AllArgsConstructor
@JsonPropertyOrder({
"musicId",
"level",
"playCount",
"scoreMax",
"missCount",
"maxComboCount",
"isFullCombo",
"isAllJustice",
"isSuccess",
"fullChain",
"maxChain",
"isLock",
"theoryCount",
"ext1"
})
public class UserMusicDetailForAncientChusan implements Serializable {
private static final long serialVersionUID = 1L;
private int musicId;
private int level;
private int playCount;
private int scoreMax;
private int missCount;
private int maxComboCount;
@JsonProperty("isFullCombo")
private boolean isFullCombo;
@JsonProperty("isAllJustice")
private boolean isAllJustice;
@JsonProperty("isSuccess")
private boolean isSuccess;
private int fullChain;
private int maxChain;
private int scoreRank;
@JsonProperty("isLock")
private boolean isLock;
private int theoryCount;
private int ext1;
public UserMusicDetailForAncientChusan(int musicId, int level, int playCount, int scoreMax, int missCount, int maxComboCount, boolean isFullCombo, boolean isAllJustice, int isSuccess, int fullChain, int maxChain, int scoreRank, boolean isLock, int theoryCount, int ext1) {
this.musicId = musicId;
this.level = level;
this.playCount = playCount;
this.scoreMax = scoreMax;
this.missCount = missCount;
this.maxComboCount = maxComboCount;
this.isFullCombo = isFullCombo;
this.isAllJustice = isAllJustice;
this.isSuccess = isSuccess > 0;
this.fullChain = fullChain;
this.maxChain = maxChain;
this.scoreRank = scoreRank;
this.isLock = isLock;
this.theoryCount = theoryCount;
this.ext1 = ext1;
}
}

View File

@ -1,18 +0,0 @@
package icu.samnyan.aqua.sega.chusan.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
/**
* @author samnyan (privateamusement@protonmail.com)
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserMusicListItemForAncientChusan {
private int length;
private List<UserMusicDetailForAncientChusan> userMusicDetailList;
}

View File

@ -1,136 +0,0 @@
package icu.samnyan.aqua.sega.chusan.handler;
import com.fasterxml.jackson.core.JsonProcessingException;
import icu.samnyan.aqua.sega.chusan.dto.UserMusicDetailForAncientChusan;
import icu.samnyan.aqua.sega.chusan.dto.UserMusicListItemForAncientChusan;
import icu.samnyan.aqua.sega.general.BaseHandler;
import icu.samnyan.aqua.sega.chusan.model.response.data.UserMusicListItem;
import icu.samnyan.aqua.sega.chusan.model.userdata.UserMusicDetail;
import icu.samnyan.aqua.sega.chusan.service.UserMusicDetailService;
import icu.samnyan.aqua.sega.util.jackson.StringMapper;
import icu.samnyan.aqua.spring.data.OffsetPageRequest;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
/**
* Response:
*
* @author samnyan (privateamusement@protonmail.com)
*/
@Component("ChusanGetUserMusicHandler")
public class GetUserMusicHandler implements BaseHandler {
private static final Logger logger = LoggerFactory.getLogger(GetUserMusicHandler.class);
private final StringMapper mapper;
private final UserMusicDetailService userMusicDetailService;
@Autowired
public GetUserMusicHandler(StringMapper mapper, UserMusicDetailService userMusicDetailService) {
this.mapper = mapper;
this.userMusicDetailService = userMusicDetailService;
}
@Override
public String handle(Map<String, ?> request) throws JsonProcessingException {
String userId = (String) request.get("userId");
int currentIndex = Integer.parseInt((String) request.get("nextIndex"));
int maxCount = Integer.parseInt((String) request.get("maxCount"));
if(currentIndex < 0) {
currentIndex = 0;
}
Page<UserMusicDetail> dbPage = userMusicDetailService
.getByUserId(userId, OffsetPageRequest.of(currentIndex, maxCount, Sort.by("musicId")));
// Convert to result format
// Result Map
Map<Integer, UserMusicListItem> userMusicMap = new LinkedHashMap<>();
dbPage.getContent().forEach(userMusicDetail -> {
UserMusicListItem list;
if (userMusicMap.containsKey(userMusicDetail.getMusicId())) {
list = userMusicMap.get(userMusicDetail.getMusicId());
} else {
list = new UserMusicListItem(0, new ArrayList<>());
userMusicMap.put(userMusicDetail.getMusicId(), list);
}
list.getUserMusicDetailList().add(userMusicDetail);
list.setLength(list.getUserMusicDetailList().size());
});
// Remove the last music id if the result length is the same as maxCount,
// to prevent a music id split across multiple page, which will cause some
// problem with the game.
int lastListSize = 0;
if(dbPage.getNumberOfElements() >= maxCount) {
// Get last key
int lastMusicId = userMusicMap.keySet().stream().reduce((a, b) -> b).orElseThrow();
List<UserMusicDetail> lastList = userMusicMap.get(lastMusicId).getUserMusicDetailList();
lastListSize = lastList.size();
// Remove last one from map
userMusicMap.remove(lastMusicId);
}
String version = (String) request.get("version");
Map<Integer, UserMusicListItemForAncientChusan> userMusicMapForAncientChusan = new LinkedHashMap<>();
boolean isAncient = false;
try {
if (Double.parseDouble(version) < 2.15){
userMusicMap.forEach((k, v) -> {
UserMusicListItemForAncientChusan list = new UserMusicListItemForAncientChusan();
list.setLength(v.getLength());
List<UserMusicDetailForAncientChusan> userMusicDetailForAncientChusanList = new ArrayList<>();
v.getUserMusicDetailList().forEach(userMusicDetail -> {
UserMusicDetailForAncientChusan userMusicDetailForAncientChusan = new UserMusicDetailForAncientChusan(
userMusicDetail.getMusicId(),
userMusicDetail.getLevel(),
userMusicDetail.getPlayCount(),
userMusicDetail.getScoreMax(),
userMusicDetail.getMissCount(),
userMusicDetail.getMaxComboCount(),
userMusicDetail.isFullCombo(),
userMusicDetail.isAllJustice(),
userMusicDetail.getIsSuccess(),
userMusicDetail.getFullChain(),
userMusicDetail.getMaxChain(),
userMusicDetail.getScoreRank(),
userMusicDetail.isLock(),
userMusicDetail.getTheoryCount(),
userMusicDetail.getExt1()
);
userMusicDetailForAncientChusanList.add(userMusicDetailForAncientChusan);
});
list.setUserMusicDetailList(userMusicDetailForAncientChusanList);
userMusicMapForAncientChusan.put(k, list);
});
isAncient = true;
}
} catch (Exception e) {
logger.error("Error when handling ancient version of chusan", e);
}
long nextIndex = currentIndex + dbPage.getNumberOfElements() - lastListSize;
Map<String, Object> resultMap = new LinkedHashMap<>();
resultMap.put("userId", userId);
resultMap.put("length", userMusicMap.size());
resultMap.put("nextIndex", dbPage.getNumberOfElements() < maxCount ? -1 : nextIndex);
resultMap.put("userMusicList", isAncient ? userMusicMapForAncientChusan.values() : userMusicMap.values());
String json = mapper.write(resultMap);
logger.info("Response: " + json);
return json;
}
}

View File

@ -1,19 +0,0 @@
package icu.samnyan.aqua.sega.chusan.model.response.data;
import icu.samnyan.aqua.sega.chusan.model.userdata.UserMusicDetail;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
/**
* @author samnyan (privateamusement@protonmail.com)
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserMusicListItem {
private int length;
private List<UserMusicDetail> userMusicDetailList;
}