From b2e2b36b6fcacf53428d679ddb9fe1b0300c9d99 Mon Sep 17 00:00:00 2001 From: Dom Eori <4j6dq2zi8@relay.firefox.com> Date: Mon, 30 Aug 2021 22:31:32 +0900 Subject: [PATCH] [maimai2] Implement game event and user playlog for possible future use --- .../controller/Maimai2ServletController.java | 7 +- .../dao/gamedata/GameEventRepository.java | 16 ++ .../dao/userdata/UserPlaylogRepository.java | 13 + .../handler/impl/GetGameEventHandler.java | 14 +- .../impl/UploadUserPlaylogHandler.java | 50 ++++ .../maimai2/model/gamedata/GameEvent.java | 36 +++ .../model/request/UploadUserPlaylog.java | 20 ++ .../maimai2/model/userdata/UserPlaylog.java | 256 ++++++++++++++++++ .../mysql/V48__add_maimai2_more_table.sql | 118 ++++++++ .../sqlite/V48__add_maimai2_more_table.sql | 122 +++++++++ 10 files changed, 644 insertions(+), 8 deletions(-) create mode 100644 src/main/java/icu/samnyan/aqua/sega/maimai2/dao/gamedata/GameEventRepository.java create mode 100644 src/main/java/icu/samnyan/aqua/sega/maimai2/dao/userdata/UserPlaylogRepository.java create mode 100644 src/main/java/icu/samnyan/aqua/sega/maimai2/handler/impl/UploadUserPlaylogHandler.java create mode 100644 src/main/java/icu/samnyan/aqua/sega/maimai2/model/gamedata/GameEvent.java create mode 100644 src/main/java/icu/samnyan/aqua/sega/maimai2/model/request/UploadUserPlaylog.java create mode 100644 src/main/java/icu/samnyan/aqua/sega/maimai2/model/userdata/UserPlaylog.java create mode 100644 src/main/resources/db/migration/mysql/V48__add_maimai2_more_table.sql create mode 100644 src/main/resources/db/migration/sqlite/V48__add_maimai2_more_table.sql diff --git a/src/main/java/icu/samnyan/aqua/sega/maimai2/controller/Maimai2ServletController.java b/src/main/java/icu/samnyan/aqua/sega/maimai2/controller/Maimai2ServletController.java index ea994d43..5d11ba96 100644 --- a/src/main/java/icu/samnyan/aqua/sega/maimai2/controller/Maimai2ServletController.java +++ b/src/main/java/icu/samnyan/aqua/sega/maimai2/controller/Maimai2ServletController.java @@ -44,6 +44,7 @@ public class Maimai2ServletController { private final GetUserChargeHandler getUserChargeHandler; private final GetUserCourseHandler getUserCourseHandler; private final UploadUserPhotoHandler uploadUserPhotoHandler; + private final UploadUserPlaylogHandler uploadUserPlaylogHandler; public Maimai2ServletController(GetGameSettingHandler getGameSettingHandler, GetGameEventHandler getGameEventHandler, GetGameRankingHandler getGameRankingHandler, GetGameTournamentInfoHandler getGameTournamentInfoHandler, GetTransferFriendHandler getTransferFriendHandler, GetUserActivityHandler getUserActivityHandler, UserLoginHandler userLoginHandler, UserLogoutHandler userLogoutHandler, @@ -51,7 +52,8 @@ public class Maimai2ServletController { GetUserOptionHandler getUserOptionHandler, GetUserItemHandler getUserItemHandler, GetUserExtendHandler getUserExtendHandler, GetUserGhostHandler getUserGhostHandler, GetUserLoginBonusHandler getUserLoginBonusHandler, GetUserMapHandler getUserMapHandler, GetUserFavoriteHandler getUserFavoriteHandler, GetUserCardHandler getUserCardHandler, GetUserMusicHandler getUserMusicHandler, GetUserRatingHandler getUserRatingHandler, GetUserRegionHandler getUserRegionHandler, - GetGameChargeHandler getGameChargeHandler, GetUserChargeHandler getUserChargeHandler, GetUserCourseHandler getUserCourseHandler, UploadUserPhotoHandler uploadUserPhotoHandler) { + GetGameChargeHandler getGameChargeHandler, GetUserChargeHandler getUserChargeHandler, GetUserCourseHandler getUserCourseHandler, UploadUserPhotoHandler uploadUserPhotoHandler, + UploadUserPlaylogHandler uploadUserPlaylogHandler) { this.getGameSettingHandler = getGameSettingHandler; this.getGameEventHandler = getGameEventHandler; this.getGameRankingHandler = getGameRankingHandler; @@ -79,6 +81,7 @@ public class Maimai2ServletController { this.getUserChargeHandler = getUserChargeHandler; this.getUserCourseHandler = getUserCourseHandler; this.uploadUserPhotoHandler = uploadUserPhotoHandler; + this.uploadUserPlaylogHandler = uploadUserPlaylogHandler; } // Mandatory for boot @@ -205,7 +208,7 @@ public class Maimai2ServletController { @PostMapping("UploadUserPlaylogApi") public String uploadUserPlaylogHandler(@ModelAttribute Map request) throws JsonProcessingException { - return "{\"returnCode\":1,\"apiName\":\"com.sega.maimai2servlet.api.UploadUserPlaylogApi\"}"; + return uploadUserPlaylogHandler.handle(request); } // No support, return error code diff --git a/src/main/java/icu/samnyan/aqua/sega/maimai2/dao/gamedata/GameEventRepository.java b/src/main/java/icu/samnyan/aqua/sega/maimai2/dao/gamedata/GameEventRepository.java new file mode 100644 index 00000000..17139813 --- /dev/null +++ b/src/main/java/icu/samnyan/aqua/sega/maimai2/dao/gamedata/GameEventRepository.java @@ -0,0 +1,16 @@ +package icu.samnyan.aqua.sega.maimai2.dao.gamedata; + +import icu.samnyan.aqua.sega.maimai2.model.gamedata.GameEvent; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.List; + +/** + * @author samnyan (privateamusement@protonmail.com) + */ +@Repository("Maimai2GameEventRepository") +public interface GameEventRepository extends JpaRepository { + + List findByTypeAndEnable(int type, boolean enable); +} diff --git a/src/main/java/icu/samnyan/aqua/sega/maimai2/dao/userdata/UserPlaylogRepository.java b/src/main/java/icu/samnyan/aqua/sega/maimai2/dao/userdata/UserPlaylogRepository.java new file mode 100644 index 00000000..9390ec83 --- /dev/null +++ b/src/main/java/icu/samnyan/aqua/sega/maimai2/dao/userdata/UserPlaylogRepository.java @@ -0,0 +1,13 @@ +package icu.samnyan.aqua.sega.maimai2.dao.userdata; + +import icu.samnyan.aqua.sega.maimai2.model.userdata.UserPlaylog; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +/** + * @author samnyan (privateamusement@protonmail.com) + */ +@Repository +public interface UserPlaylogRepository extends JpaRepository { + +} diff --git a/src/main/java/icu/samnyan/aqua/sega/maimai2/handler/impl/GetGameEventHandler.java b/src/main/java/icu/samnyan/aqua/sega/maimai2/handler/impl/GetGameEventHandler.java index 41193915..f18f4a93 100644 --- a/src/main/java/icu/samnyan/aqua/sega/maimai2/handler/impl/GetGameEventHandler.java +++ b/src/main/java/icu/samnyan/aqua/sega/maimai2/handler/impl/GetGameEventHandler.java @@ -1,14 +1,15 @@ package icu.samnyan.aqua.sega.maimai2.handler.impl; import com.fasterxml.jackson.core.JsonProcessingException; + +import icu.samnyan.aqua.sega.maimai2.dao.gamedata.GameEventRepository; import icu.samnyan.aqua.sega.maimai2.handler.BaseHandler; +import icu.samnyan.aqua.sega.maimai2.model.gamedata.GameEvent; import icu.samnyan.aqua.sega.util.jackson.StringMapper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -21,19 +22,20 @@ public class GetGameEventHandler implements BaseHandler { private static final Logger logger = LoggerFactory.getLogger(GetGameEventHandler.class); - //private final GameEventRepository gameEventRepository; + private final GameEventRepository gameEventRepository; private final StringMapper mapper; - public GetGameEventHandler(StringMapper mapper) { + public GetGameEventHandler(GameEventRepository gameEventRepository, StringMapper mapper) { + this.gameEventRepository = gameEventRepository; this.mapper = mapper; } @Override public String handle(Map request) throws JsonProcessingException { - String type = Integer.toString((int) request.get("type")); + int type = ((Number) request.get("type")).intValue(); - List gameEventList = new ArrayList<>(); + List gameEventList = gameEventRepository.findByTypeAndEnable(type, true); Map resultMap = new LinkedHashMap<>(); resultMap.put("type", type); diff --git a/src/main/java/icu/samnyan/aqua/sega/maimai2/handler/impl/UploadUserPlaylogHandler.java b/src/main/java/icu/samnyan/aqua/sega/maimai2/handler/impl/UploadUserPlaylogHandler.java new file mode 100644 index 00000000..ae9f58f7 --- /dev/null +++ b/src/main/java/icu/samnyan/aqua/sega/maimai2/handler/impl/UploadUserPlaylogHandler.java @@ -0,0 +1,50 @@ +package icu.samnyan.aqua.sega.maimai2.handler.impl; + +import com.fasterxml.jackson.core.JsonProcessingException; + +import icu.samnyan.aqua.sega.maimai2.dao.userdata.UserDataRepository; +import icu.samnyan.aqua.sega.maimai2.dao.userdata.UserPlaylogRepository; +import icu.samnyan.aqua.sega.maimai2.handler.BaseHandler; +import icu.samnyan.aqua.sega.maimai2.model.request.UploadUserPlaylog; +import icu.samnyan.aqua.sega.maimai2.model.userdata.UserDetail; +import icu.samnyan.aqua.sega.maimai2.model.userdata.UserPlaylog; +import icu.samnyan.aqua.sega.util.jackson.BasicMapper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +import java.util.Map; +import java.util.Optional; + +/** + * @author samnyan (privateamusement@protonmail.com) + */ +@Component +public class UploadUserPlaylogHandler implements BaseHandler { + + private static final Logger logger = LoggerFactory.getLogger(UploadUserPlaylogHandler.class); + + private final BasicMapper mapper; + private final UserPlaylogRepository userPlaylogRepository; + private final UserDataRepository userDataRepository; + + public UploadUserPlaylogHandler(UserDataRepository userDataRepository, UserPlaylogRepository userPlaylogRepository, BasicMapper mapper) { + this.userDataRepository = userDataRepository; + this.userPlaylogRepository = userPlaylogRepository; + this.mapper = mapper; + } + + @Override + public String handle(Map request) throws JsonProcessingException { + UploadUserPlaylog uploadUserPlaylog = mapper.convert(request, UploadUserPlaylog.class); + + Optional userOptional = userDataRepository.findByCard_ExtId(uploadUserPlaylog.getUserId()); + UserDetail userDetail = userOptional.orElseThrow(); + + UserPlaylog userPlaylog = uploadUserPlaylog.getUserPlaylog(); + userPlaylog.setUser(userDetail); + userPlaylogRepository.save(userPlaylog); + + return "{\"returnCode\":1,\"apiName\":\"com.sega.maimai2servlet.api.UploadUserPlaylogApi\"}"; + } +} diff --git a/src/main/java/icu/samnyan/aqua/sega/maimai2/model/gamedata/GameEvent.java b/src/main/java/icu/samnyan/aqua/sega/maimai2/model/gamedata/GameEvent.java new file mode 100644 index 00000000..b2412892 --- /dev/null +++ b/src/main/java/icu/samnyan/aqua/sega/maimai2/model/gamedata/GameEvent.java @@ -0,0 +1,36 @@ +package icu.samnyan.aqua.sega.maimai2.model.gamedata; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Table; +import java.io.Serializable; + +/** + * @author samnyan (privateamusement@protonmail.com) + */ +@Entity(name = "Maimai2GameEvent") +@Table(name = "maimai2_game_event") +@Data +@AllArgsConstructor +@NoArgsConstructor +public class GameEvent implements Serializable { + + private static final long serialVersionUID = 1L; + + @Id + private int id; + + private int type; + + private String startDate; + + private String endDate; + + @JsonIgnore + private boolean enable; +} diff --git a/src/main/java/icu/samnyan/aqua/sega/maimai2/model/request/UploadUserPlaylog.java b/src/main/java/icu/samnyan/aqua/sega/maimai2/model/request/UploadUserPlaylog.java new file mode 100644 index 00000000..81649ba8 --- /dev/null +++ b/src/main/java/icu/samnyan/aqua/sega/maimai2/model/request/UploadUserPlaylog.java @@ -0,0 +1,20 @@ +package icu.samnyan.aqua.sega.maimai2.model.request; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.io.Serializable; + +import icu.samnyan.aqua.sega.maimai2.model.userdata.UserPlaylog; + +/** + * @author samnyan (privateamusement@protonmail.com) + */ +@Data +@AllArgsConstructor +@NoArgsConstructor +public class UploadUserPlaylog implements Serializable { + private long userId; + private UserPlaylog userPlaylog; +} diff --git a/src/main/java/icu/samnyan/aqua/sega/maimai2/model/userdata/UserPlaylog.java b/src/main/java/icu/samnyan/aqua/sega/maimai2/model/userdata/UserPlaylog.java new file mode 100644 index 00000000..bbd10eb7 --- /dev/null +++ b/src/main/java/icu/samnyan/aqua/sega/maimai2/model/userdata/UserPlaylog.java @@ -0,0 +1,256 @@ +package icu.samnyan.aqua.sega.maimai2.model.userdata; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import javax.persistence.*; +import java.io.Serializable; + +/** + * @author samnyan (privateamusement@protonmail.com) + */ +@Entity(name = "Maimai2UserPlaylog") +@Table(name = "maimai2_user_playlog") +@Data +@NoArgsConstructor +@AllArgsConstructor +public class UserPlaylog implements Serializable { + + private static final long serialVersionUID = 1L; + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @JsonIgnore + private long id; + + @JsonIgnore + @ManyToOne + @JoinColumn(name = "user_id") + private UserDetail user; + + private int orderId; + + private long playlogId; + + private int version; + + private int placeId; + + private String placeName; + + private long loginDate; + + private String playDate; + + private String userPlayDate; + + private int type; + + private int musicId; + + private int level; + + private int trackNo; + + private int vsMode; + + private String vsUserName; + + private int vsStatus; + + private int vsUserRating; + + private int vsUserAchievement; + + private int vsUserGradeRank; + + private int vsRank; + + private int playerNum; + + private long playedUserId1; + + private String playedUserName1; + + private int playedMusicLevel1; + + private long playedUserId2; + + private String playedUserName2; + + private int playedMusicLevel2; + + private long playedUserId3; + + private String playedUserName3; + + private int playedMusicLevel3; + + private int characterId1; + + private int characterLevel1; + + private int characterAwakening1; + + private int characterId2; + + private int characterLevel2; + + private int characterAwakening2; + + private int characterId3; + + private int characterLevel3; + + private int characterAwakening3; + + private int characterId4; + + private int characterLevel4; + + private int characterAwakening4; + + private int characterId5; + + private int characterLevel5; + + private int characterAwakening5; + + private int achievement; + + private int deluxscore; + + private int scoreRank; + + private int maxCombo; + + private int totalCombo; + + private int maxSync; + + private int totalSync; + + private int tapCriticalPerfect; + + private int tapPerfect; + + private int tapGreat; + + private int tapGood; + + private int tapMiss; + + private int holdCriticalPerfect; + + private int holdPerfect; + + private int holdGreat; + + private int holdGood; + + private int holdMiss; + + private int slideCriticalPerfect; + + private int slidePerfect; + + private int slideGreat; + + private int slideGood; + + private int slideMiss; + + private int touchCriticalPerfect; + + private int touchPerfect; + + private int touchGreat; + + private int touchGood; + + private int touchMiss; + + private int breakCriticalPerfect; + + private int breakPerfect; + + private int breakGreat; + + private int breakGood; + + private int breakMiss; + + @JsonProperty("Tap") + private boolean isTap; + + @JsonProperty("Hold") + private boolean isHold; + + @JsonProperty("Slide") + private boolean isSlide; + + @JsonProperty("Touch") + private boolean isTouch; + + @JsonProperty("Break") + private boolean isBreak; + + @JsonProperty("CriticalDisp") + private boolean isCriticalDisp; + + @JsonProperty("FastLateDisp") + private boolean isFastLateDisp; + + private int fastCount; + + private int lateCount; + + @JsonProperty("AchieveNewRecord") + private boolean isAchieveNewRecord; + + @JsonProperty("DeluxscoreNewRecord") + private boolean isDeluxscoreNewRecord; + + private int comboStatus; + + private int syncStatus; + + @JsonProperty("Clear") + private boolean isClear; + + private int beforeRating; + + private int afterRating; + + private int beforeGrade; + + private int afterGrade; + + private int afterGradeRank; + + private int beforeDeluxRating; + + private int afterDeluxRating; + + @JsonProperty("PlayTutorial") + private boolean isPlayTutorial; + + @JsonProperty("EventMode") + private boolean isEventMode; + + @JsonProperty("FreedomMode") + private boolean isFreedomMode; + + private int playMode; + + @JsonProperty("NewFree") + private boolean isNewFree; + + private int extNum1; + + private int extNum2; + +} diff --git a/src/main/resources/db/migration/mysql/V48__add_maimai2_more_table.sql b/src/main/resources/db/migration/mysql/V48__add_maimai2_more_table.sql new file mode 100644 index 00000000..5cdd017b --- /dev/null +++ b/src/main/resources/db/migration/mysql/V48__add_maimai2_more_table.sql @@ -0,0 +1,118 @@ +CREATE TABLE maimai2_game_event ( + id BIGINT auto_increment PRIMARY KEY, + type INTEGER NOT NULL, + start_date VARCHAR (255), + end_date VARCHAR (255), + enable BOOLEAN NOT NULL +); + +CREATE TABLE maimai2_user_playlog ( + id BIGINT auto_increment PRIMARY KEY, + order_id INTEGER, + playlog_id BIGINT, + version INTEGER, + place_id INTEGER, + place_name VARCHAR (255), + login_date BIGINT, + play_date VARCHAR (255), + user_play_date VARCHAR (255), + type INTEGER, + music_id INTEGER, + level INTEGER, + track_no INTEGER, + vs_mode INTEGER, + vs_user_name VARCHAR (255), + vs_status INTEGER, + vs_user_rating INTEGER, + vs_user_achievement INTEGER, + vs_user_grade_rank INTEGER, + vs_rank INTEGER, + player_num INTEGER, + played_user_id1 BIGINT, + played_user_name1 VARCHAR (255), + played_music_level1 INTEGER, + played_user_id2 BIGINT, + played_user_name2 VARCHAR (255), + played_music_level2 INTEGER, + played_user_id3 BIGINT, + played_user_name3 VARCHAR (255), + played_music_level3 INTEGER, + character_id1 INTEGER, + character_level1 INTEGER, + character_awakening1 INTEGER, + character_id2 INTEGER, + character_level2 INTEGER, + character_awakening2 INTEGER, + character_id3 INTEGER, + character_level3 INTEGER, + character_awakening3 INTEGER, + character_id4 INTEGER, + character_level4 INTEGER, + character_awakening4 INTEGER, + character_id5 INTEGER, + character_level5 INTEGER, + character_awakening5 INTEGER, + achievement INTEGER, + deluxscore INTEGER, + score_rank INTEGER, + max_combo INTEGER, + total_combo INTEGER, + max_sync INTEGER, + total_sync INTEGER, + tap_critical_perfect INTEGER, + tap_perfect INTEGER, + tap_great INTEGER, + tap_good INTEGER, + tap_miss INTEGER, + hold_critical_perfect INTEGER, + hold_perfect INTEGER, + hold_great INTEGER, + hold_good INTEGER, + hold_miss INTEGER, + slide_critical_perfect INTEGER, + slide_perfect INTEGER, + slide_great INTEGER, + slide_good INTEGER, + slide_miss INTEGER, + touch_critical_perfect INTEGER, + touch_perfect INTEGER, + touch_great INTEGER, + touch_good INTEGER, + touch_miss INTEGER, + break_critical_perfect INTEGER, + break_perfect INTEGER, + break_great INTEGER, + break_good INTEGER, + break_miss INTEGER, + is_tap BOOLEAN, + is_hold BOOLEAN, + is_slide BOOLEAN, + is_touch BOOLEAN, + is_break BOOLEAN, + is_critical_disp BOOLEAN, + is_fast_late_disp BOOLEAN, + fast_count INTEGER, + late_count INTEGER, + is_achieve_new_record BOOLEAN, + is_deluxscore_new_record BOOLEAN, + combo_status INTEGER, + sync_status INTEGER, + is_clear BOOLEAN, + before_rating INTEGER, + after_rating INTEGER, + before_grade INTEGER, + after_grade INTEGER, + after_grade_rank INTEGER, + before_delux_rating INTEGER, + after_delux_rating INTEGER, + is_play_tutorial BOOLEAN, + is_event_mode BOOLEAN, + is_freedom_mode BOOLEAN, + play_mode INTEGER, + is_new_free BOOLEAN, + ext_num1 INTEGER, + ext_num2 INTEGER, + user_id BIGINT, + constraint FKcszan6hmc7eyjp37 + foreign key (user_id) references maimai2_user_detail (id) +); diff --git a/src/main/resources/db/migration/sqlite/V48__add_maimai2_more_table.sql b/src/main/resources/db/migration/sqlite/V48__add_maimai2_more_table.sql new file mode 100644 index 00000000..ba0fde14 --- /dev/null +++ b/src/main/resources/db/migration/sqlite/V48__add_maimai2_more_table.sql @@ -0,0 +1,122 @@ +CREATE TABLE maimai2_game_event ( + id INTEGER NOT NULL, + type INTEGER NOT NULL, + start_date VARCHAR (255), + end_date VARCHAR (255), + enable BOOLEAN NOT NULL, + PRIMARY KEY ( + id + ) +); + +CREATE TABLE maimai2_user_playlog ( + id INTEGER, + order_id INTEGER, + playlog_id BIGINT, + version INTEGER, + place_id INTEGER, + place_name VARCHAR (255), + login_date BIGINT, + play_date VARCHAR (255), + user_play_date VARCHAR (255), + type INTEGER, + music_id INTEGER, + level INTEGER, + track_no INTEGER, + vs_mode INTEGER, + vs_user_name VARCHAR (255), + vs_status INTEGER, + vs_user_rating INTEGER, + vs_user_achievement INTEGER, + vs_user_grade_rank INTEGER, + vs_rank INTEGER, + player_num INTEGER, + played_user_id1 BIGINT, + played_user_name1 VARCHAR (255), + played_music_level1 INTEGER, + played_user_id2 BIGINT, + played_user_name2 VARCHAR (255), + played_music_level2 INTEGER, + played_user_id3 BIGINT, + played_user_name3 VARCHAR (255), + played_music_level3 INTEGER, + character_id1 INTEGER, + character_level1 INTEGER, + character_awakening1 INTEGER, + character_id2 INTEGER, + character_level2 INTEGER, + character_awakening2 INTEGER, + character_id3 INTEGER, + character_level3 INTEGER, + character_awakening3 INTEGER, + character_id4 INTEGER, + character_level4 INTEGER, + character_awakening4 INTEGER, + character_id5 INTEGER, + character_level5 INTEGER, + character_awakening5 INTEGER, + achievement INTEGER, + deluxscore INTEGER, + score_rank INTEGER, + max_combo INTEGER, + total_combo INTEGER, + max_sync INTEGER, + total_sync INTEGER, + tap_critical_perfect INTEGER, + tap_perfect INTEGER, + tap_great INTEGER, + tap_good INTEGER, + tap_miss INTEGER, + hold_critical_perfect INTEGER, + hold_perfect INTEGER, + hold_great INTEGER, + hold_good INTEGER, + hold_miss INTEGER, + slide_critical_perfect INTEGER, + slide_perfect INTEGER, + slide_great INTEGER, + slide_good INTEGER, + slide_miss INTEGER, + touch_critical_perfect INTEGER, + touch_perfect INTEGER, + touch_great INTEGER, + touch_good INTEGER, + touch_miss INTEGER, + break_critical_perfect INTEGER, + break_perfect INTEGER, + break_great INTEGER, + break_good INTEGER, + break_miss INTEGER, + is_tap BOOLEAN, + is_hold BOOLEAN, + is_slide BOOLEAN, + is_touch BOOLEAN, + is_break BOOLEAN, + is_critical_disp BOOLEAN, + is_fast_late_disp BOOLEAN, + fast_count INTEGER, + late_count INTEGER, + is_achieve_new_record BOOLEAN, + is_deluxscore_new_record BOOLEAN, + combo_status INTEGER, + sync_status INTEGER, + is_clear BOOLEAN, + before_rating INTEGER, + after_rating INTEGER, + before_grade INTEGER, + after_grade INTEGER, + after_grade_rank INTEGER, + before_delux_rating INTEGER, + after_delux_rating INTEGER, + is_play_tutorial BOOLEAN, + is_event_mode BOOLEAN, + is_freedom_mode BOOLEAN, + play_mode INTEGER, + is_new_free BOOLEAN, + ext_num1 INTEGER, + ext_num2 INTEGER, + user_id BIGINT REFERENCES maimai2_user_detail (id) ON DELETE CASCADE, + PRIMARY KEY ( + id + ) +);