[chuni] Fix music score missing again

[ongeki] Fix music score missing again
pull/1/head
samnyan 2020-04-20 10:39:32 +09:00
parent 0c8f19d370
commit 14dec1e3e3
6 changed files with 287 additions and 14 deletions

View File

@ -0,0 +1,85 @@
package icu.samnyan.aqua.api.controller.sega.manage;
import icu.samnyan.aqua.sega.chunithm.model.gamedata.Level;
import icu.samnyan.aqua.sega.chunithm.model.gamedata.Music;
import icu.samnyan.aqua.sega.chunithm.model.userdata.UserData;
import icu.samnyan.aqua.sega.chunithm.model.userdata.UserMusicDetail;
import icu.samnyan.aqua.sega.chunithm.service.GameMusicService;
import icu.samnyan.aqua.sega.chunithm.service.UserDataService;
import icu.samnyan.aqua.sega.chunithm.service.UserMusicDetailService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
/**
* @author samnyan (privateamusement@protonmail.com)
*/
@RestController
@RequestMapping("api/manage/chuni/amazon")
public class ApiAmazonManageController {
private static final Logger logger = LoggerFactory.getLogger(ApiAmazonManageController.class);
private final UserDataService userDataService;
private final UserMusicDetailService userMusicDetailService;
private final GameMusicService gameMusicService;
public ApiAmazonManageController(UserDataService userDataService, UserMusicDetailService userMusicDetailService, GameMusicService gameMusicService) {
this.userDataService = userDataService;
this.userMusicDetailService = userMusicDetailService;
this.gameMusicService = gameMusicService;
}
/**
* A request to fill fake score to all chart. only use for testing
* @param aimeId The internal id of a card
* @return Run result status
*/
// @PostMapping("fill")
public ResponseEntity<Object> fillMockData(@RequestParam String aimeId) {
UserData profile = userDataService.getUserByExtId(aimeId).orElseThrow();
List<Music> musicList = gameMusicService.getAll();
List<UserMusicDetail> detailList = new ArrayList<>();
musicList.forEach(x -> {
Collection<Level> levels = x.getLevels().values();
levels.forEach(l -> {
Optional<UserMusicDetail> userMusicDetailOptional = userMusicDetailService.getByUserAndMusicIdAndLevel(profile, x.getMusicId(), l.getDiff());
if (userMusicDetailOptional.isEmpty()) {
UserMusicDetail temp = new UserMusicDetail(
x.getMusicId(),
l.getDiff(),
1,
980000,
0,
0,
0,
5,
0,
false,
false,
false,
0,
0,
8,
false
);
temp.setUser(profile);
detailList.add(temp);
}
});
});
userMusicDetailService.saveAll(detailList);
return ResponseEntity.ok("OK");
}
}

View File

@ -91,6 +91,6 @@ public class AimeDbRequestHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
super.channelInactive(ctx);
logger.info("Connection closed");
logger.debug("Connection closed");
}
}

View File

@ -7,10 +7,12 @@ import icu.samnyan.aqua.sega.chunithm.model.userdata.UserMusicDetail;
import icu.samnyan.aqua.sega.chunithm.service.GameMusicService;
import icu.samnyan.aqua.sega.chunithm.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.*;
@ -41,11 +43,14 @@ public class GetUserMusicHandler implements BaseHandler {
@Override
public String handle(Map<String, Object> request) throws JsonProcessingException {
String userId = (String) request.get("userId");
int nextIndex = Integer.parseInt((String) request.get("nextIndex"));
int currentIndex = Integer.parseInt((String) request.get("nextIndex"));
int maxCount = Integer.parseInt((String) request.get("maxCount"));
int pageNum = nextIndex / maxCount;
if(currentIndex < 0) {
currentIndex = 0;
}
Page<UserMusicDetail> dbPage = userMusicDetailService.getByUser(userId,pageNum,maxCount);
Page<UserMusicDetail> dbPage = userMusicDetailService
.getByUser(userId, OffsetPageRequest.of(currentIndex, maxCount, Sort.by("musicId")));
// Convert to result format
@ -64,13 +69,25 @@ public class GetUserMusicHandler implements BaseHandler {
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);
}
long currentIndex = maxCount * pageNum + dbPage.getNumberOfElements();
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 : currentIndex);
resultMap.put("nextIndex", dbPage.getNumberOfElements() < maxCount ? -1 : nextIndex);
resultMap.put("userMusicList", userMusicMap.values());
String json = mapper.write(resultMap);

View File

@ -37,8 +37,7 @@ public class UserMusicDetailService {
return userMusicDetailRepository.findByUser_Card_ExtId(Integer.parseInt(userId));
}
public Page<UserMusicDetail> getByUser(String userId, int pageNum, int maxCount) {
Pageable page = PageRequest.of(pageNum, maxCount);
public Page<UserMusicDetail> getByUser(String userId, Pageable page) {
return userMusicDetailRepository.findByUser_Card_ExtId(Integer.parseInt(userId), page);
}

View File

@ -6,15 +6,17 @@ import icu.samnyan.aqua.sega.ongeki.handler.BaseHandler;
import icu.samnyan.aqua.sega.ongeki.model.response.data.UserMusicListItem;
import icu.samnyan.aqua.sega.ongeki.model.userdata.UserMusicDetail;
import icu.samnyan.aqua.sega.util.jackson.BasicMapper;
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.PageRequest;
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;
/**
@ -40,10 +42,13 @@ public class GetUserMusicHandler implements BaseHandler {
public String handle(Map<String, Object> request) throws JsonProcessingException {
Integer userId = (Integer) request.get("userId");
Integer maxCount = (Integer) request.get("maxCount");
Integer nextIndex = (Integer) request.get("nextIndex");
int pageNum = nextIndex / maxCount;
Integer currentIndex = (Integer) request.get("nextIndex");
if(currentIndex < 0) {
currentIndex = 0;
}
Page<UserMusicDetail> dbPage = userMusicDetailRepository.findByUser_Card_ExtId(userId, PageRequest.of(pageNum, maxCount));
Page<UserMusicDetail> dbPage = userMusicDetailRepository
.findByUser_Card_ExtId(userId, OffsetPageRequest.of(currentIndex, maxCount, Sort.by("musicId")));
Map<Integer, UserMusicListItem> userMusicMap = new LinkedHashMap<>();
dbPage.getContent().forEach(userMusicDetail -> {
@ -58,12 +63,23 @@ public class GetUserMusicHandler implements BaseHandler {
list.setLength(list.getUserMusicDetailList().size());
});
long currentIndex = maxCount * pageNum + dbPage.getNumberOfElements();
// Someone report that ongeki also has the score missing problem
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);
}
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 : currentIndex);
resultMap.put("nextIndex", dbPage.getNumberOfElements() < maxCount ? -1 : nextIndex);
resultMap.put("userMusicList", userMusicMap.values());
String json = mapper.write(resultMap);

View File

@ -0,0 +1,156 @@
package icu.samnyan.aqua.spring.data;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import java.io.Serializable;
/**
* Somehow spring boot jpa doesn't provide a class to use offset to to the pagination
* @author samnyan (privateamusement@protonmail.com)
*/
public class OffsetPageRequest implements Pageable, Serializable {
private static final long serialVersionUID = 1L;
private final int offset;
private final int limit;
private final Sort sort;
/**
* Creates a new {@link OffsetPageRequest} with sort parameters applied.
*
* @param offset offset of the request index, must not be negative.
* @param limit the size of the page to be returned, must be greater than 0.
* @param sort must not be {@literal null}, use {@link Sort#unsorted()} instead.
*/
public OffsetPageRequest(int offset, int limit, Sort sort) {
if (offset < 0) {
throw new IllegalArgumentException("Offset must not be less than zero!");
}
if (limit < 1) {
throw new IllegalArgumentException("Limit must not be less than one!");
}
Assert.notNull(sort, "Sort must not be null!");
this.offset = offset;
this.limit = limit;
this.sort = sort;
}
public static OffsetPageRequest of(int page, int size) {
return of(page, size, Sort.unsorted());
}
public static OffsetPageRequest of(int page, int size, Sort sort) {
return new OffsetPageRequest(page, size, sort);
}
/*
* (non-Javadoc)
* @see org.springframework.data.domain.Pageable#getPageNumber()
*/
@Override
public int getPageNumber() {
return offset / limit;
}
/*
* (non-Javadoc)
* @see org.springframework.data.domain.Pageable#getPageSize()
*/
@Override
public int getPageSize() {
return limit;
}
/*
* (non-Javadoc)
* @see org.springframework.data.domain.Pageable#getOffset()
*/
@Override
public long getOffset() {
return offset;
}
/*
* (non-Javadoc)
* @see org.springframework.data.domain.Pageable#getSort()
*/
@Override
public Sort getSort() {
return sort;
}
/*
* (non-Javadoc)
* @see org.springframework.data.domain.Pageable#next()
*/
@Override
public Pageable next() {
return new OffsetPageRequest(Math.toIntExact(getOffset() + getPageSize()), getPageSize(), getSort());
}
/*
* (non-Javadoc)
* @see org.springframework.data.domain.Pageable#previousOrFirst()
*/
@Override
public Pageable previousOrFirst() {
return hasPrevious() ? new OffsetPageRequest(Math.toIntExact(getOffset() - getPageSize()), getPageSize(), getSort()) : this;
}
/*
* (non-Javadoc)
* @see org.springframework.data.domain.Pageable#first()
*/
@Override
public Pageable first() {
return new OffsetPageRequest(0, getPageSize(), getSort());
}
@Override
public boolean hasPrevious() {
return offset > limit;
}
/*
* (non-Javadoc)
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + offset;
result = prime * result + limit;
return result;
}
/*
* (non-Javadoc)
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(@Nullable Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
OffsetPageRequest other = (OffsetPageRequest) obj;
return this.offset == other.offset && this.limit == other.limit;
}
}