From e02d74fafa935f05a68bf8710bb1f4ddfa290fef Mon Sep 17 00:00:00 2001 From: skogaby Date: Mon, 21 Jan 2019 18:57:28 -0600 Subject: [PATCH] User ghost data and personal scores now load correctly. Not sure if area/region scores are loading or not, but personal and global scores are implemented --- .../dao/impl/ddr16/UserSongRecordDao.java | 17 +++ .../butterfly/http/ButterflyHttpServer.java | 2 - .../impl/PlayerDataRequestHandler.java | 100 ++++++++++++++++-- .../butterfly/model/ddr16/GhostData.java | 32 +++++- 4 files changed, 142 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/buttongames/butterfly/hibernate/dao/impl/ddr16/UserSongRecordDao.java b/src/main/java/com/buttongames/butterfly/hibernate/dao/impl/ddr16/UserSongRecordDao.java index 3509f8a..5c4f26f 100644 --- a/src/main/java/com/buttongames/butterfly/hibernate/dao/impl/ddr16/UserSongRecordDao.java +++ b/src/main/java/com/buttongames/butterfly/hibernate/dao/impl/ddr16/UserSongRecordDao.java @@ -11,6 +11,7 @@ import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Repository; import java.time.LocalDateTime; +import java.util.List; /** * DAO for interacting with UserSongRecord objects in the database. @@ -63,4 +64,20 @@ public class UserSongRecordDao extends AbstractHibernateDao { this.closeCurrentSession(); return result; } + + /** + * Finds all song records for a user. + * @param user The user of the records + * @return A list of matching records + */ + public List findByUser(final UserProfile user) { + this.openCurrentSession(); + + final Query query = this.currentSession.createQuery("from UserSongRecord where user = :user"); + query.setParameter("user", user); + final List result = query.getResultList(); + + this.closeCurrentSession(); + return result; + } } diff --git a/src/main/java/com/buttongames/butterfly/http/ButterflyHttpServer.java b/src/main/java/com/buttongames/butterfly/http/ButterflyHttpServer.java index b2b5689..de78b3e 100644 --- a/src/main/java/com/buttongames/butterfly/http/ButterflyHttpServer.java +++ b/src/main/java/com/buttongames/butterfly/http/ButterflyHttpServer.java @@ -74,7 +74,6 @@ public class ButterflyHttpServer { private static final ImmutableSet SUPPORTED_MODULES; // Do a static setup of our supported models, modules, etc. - // TODO: Make this not hardcoded static { SUPPORTED_MODELS = ImmutableSet.of("mdx_2018042300"); SUPPORTED_MODULES = ImmutableSet.of("services", "pcbtracker", "message", "facility", "pcbevent", @@ -185,7 +184,6 @@ public class ButterflyHttpServer { /** * Configures the routes on the server, and the exception handlers. - * TODO: Remove all the hardcoded stuff. */ private void configureRoutesAndExceptions() { // configure our root route; its handler will parse the request and go from there diff --git a/src/main/java/com/buttongames/butterfly/http/handlers/impl/PlayerDataRequestHandler.java b/src/main/java/com/buttongames/butterfly/http/handlers/impl/PlayerDataRequestHandler.java index b877a75..522a299 100644 --- a/src/main/java/com/buttongames/butterfly/http/handlers/impl/PlayerDataRequestHandler.java +++ b/src/main/java/com/buttongames/butterfly/http/handlers/impl/PlayerDataRequestHandler.java @@ -50,7 +50,9 @@ import java.time.LocalDateTime; import java.util.ArrayList; import java.util.Arrays; import java.util.Base64; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Random; import java.util.concurrent.ConcurrentHashMap; @@ -329,7 +331,7 @@ public class PlayerDataRequestHandler extends BaseRequestHandler { // we need to return the top score for every song/difficulty for (Song song : SONGS_2018042300) { - for (int i = 0; i < 8; i++) { + for (int i = 0; i < 9; i++) { if (GLOBAL_HIGH_SCORES_CACHE.get(song.getMcode()).containsKey(i)) { record = GLOBAL_HIGH_SCORES_CACHE.get(song.getMcode()).get(i); @@ -362,13 +364,89 @@ public class PlayerDataRequestHandler extends BaseRequestHandler { throw new UnsupportedRequestException(); } - // TODO: Implement this properly and load/save scores... also, events probably isn't a static response KXmlBuilder respBuilder = KXmlBuilder.create("response") .e("playerdata") .s32("result", 0).up() .bool("is_new", false).up(); - // insert the events + // load user scores if this was for a particular user + if (!refId.equals("X0000000000000000000000000000000")) { + // get the user's scores and sort them out so we can get the top scores + // for each song/difficulty + final List userRecords = + this.songRecordDao.findByUser( + this.profileDao.findByUser( + this.cardDao.findByRefId(refId).getUser())); + + // sort them by song and difficulty, then insert them into the response + // key for top map is the song ID + // key for the 2nd map is the difficulty + // the array: a[0] = count, a[1] = top UserSongRecord + final HashMap> userTopScores = new HashMap<>(); + + for (UserSongRecord record : userRecords) { + if (!userTopScores.containsKey(record.getSongId())) { + userTopScores.put(record.getSongId(), new HashMap<>()); + userTopScores.get(record.getSongId()).put(record.getNoteType(), new Object[] { 1, record }); + } else { + if (!userTopScores.get(record.getSongId()).containsKey(record.getNoteType())) { + userTopScores.get(record.getSongId()).put(record.getNoteType(), new Object[] { 1, record }); + } else { + Object[] currRecord = userTopScores.get(record.getSongId()).get(record.getNoteType()); + currRecord[0] = ((Integer) currRecord[0]) + 1; + + if (((UserSongRecord) currRecord[1]).getScore() < record.getScore()) { + currRecord[1] = record; + } + + userTopScores.get(record.getSongId()).put(record.getNoteType(), currRecord); + } + } + } + + int count = 0; + int rank = 0; + int clearkind = 0; + int score = 0; + int ghostid = 0; + + // insert them into the response + for (Map.Entry> entry : userTopScores.entrySet()) { + respBuilder = respBuilder.e("music") + .u32("mcode", entry.getKey()).up(); + + // iterate through each difficulty + for (int i = 0; i < 9; i++) { + if (entry.getValue().containsKey(i)) { + Object[] record = entry.getValue().get(i); + UserSongRecord topRecord = (UserSongRecord) record[1]; + + count = (Integer) record[0]; + rank = topRecord.getRank(); + clearkind = topRecord.getClearKind(); + score = topRecord.getScore(); + ghostid = ((Long) topRecord.getGhostData().getId()).intValue(); + } else { + count = 0; + rank = 0; + clearkind = 0; + score = 0; + ghostid = 0; + } + + respBuilder = respBuilder.e("note") + .u16("count", count).up() + .u8("rank", rank).up() + .u8("clearkind", clearkind).up() + .s32("score", score).up() + .s32("ghostid", ghostid).up().up(); + } + + respBuilder = respBuilder.up(); + } + } + + // TODO: Events probably isn't a static response final Document document = respBuilder.getDocument(); final Element elem = respBuilder.getElement(); @@ -797,11 +875,21 @@ public class PlayerDataRequestHandler extends BaseRequestHandler { * @return A response object for Spark */ private Object handleGhostLoadRequest(final int ghostId, final Request request, final Response response) { - // TODO: Store and load ghost data correctly - final KXmlBuilder builder = KXmlBuilder.create("response") + KXmlBuilder builder = KXmlBuilder.create("response") .e("playerdata") .s32("result", 0).up(); + final GhostData ghostData = this.ghostDataDao.findById((long) ghostId); + + if (ghostData != null) { + builder = builder.e("ghostdata") + .s32("code", 0).up() + .u32("mcode", ghostData.getMcode()).up() + .u8("notetype", ghostData.getNoteType()).up() + .s32("ghostsize", ghostData.getGhostData().length()).up() + .str("ghost", ghostData.getGhostData()); + } + return this.sendResponse(request, response, builder); } @@ -918,7 +1006,7 @@ public class PlayerDataRequestHandler extends BaseRequestHandler { int folder = XmlUtils.intAtChild(recordNode, "folder"); // construct and save - GhostData newGhostData = new GhostData(user, ghostStr); + GhostData newGhostData = new GhostData(user, ghostStr, songId, noteType); this.ghostDataDao.create(newGhostData); UserSongRecord newRecord = new UserSongRecord(user, playSide, playStyle, area, weight100, shopName, isPremium, diff --git a/src/main/java/com/buttongames/butterfly/model/ddr16/GhostData.java b/src/main/java/com/buttongames/butterfly/model/ddr16/GhostData.java index 9455dcd..e944a46 100644 --- a/src/main/java/com/buttongames/butterfly/model/ddr16/GhostData.java +++ b/src/main/java/com/buttongames/butterfly/model/ddr16/GhostData.java @@ -37,11 +37,21 @@ public class GhostData implements Externalizable { @Column(name = "ghost_data", columnDefinition = "TEXT") private String ghostData; + /** The mcode of the song for this data */ + @Column(name = "mcode") + private int mcode; + + /** The difficulty the ghost data was for */ + @Column(name = "note_type") + private int noteType; + public GhostData() { } - public GhostData(UserProfile user, String ghostData) { + public GhostData(UserProfile user, String ghostData, int mcode, int noteType) { this.user = user; this.ghostData = ghostData; + this.mcode = mcode; + this.noteType = noteType; } @Override @@ -49,6 +59,8 @@ public class GhostData implements Externalizable { out.writeLong(this.id); out.writeObject(this.user); out.writeUTF(this.ghostData); + out.writeInt(this.mcode); + out.writeInt(this.noteType); } @Override @@ -56,6 +68,8 @@ public class GhostData implements Externalizable { this.setId(in.readLong()); this.setUser((UserProfile) in.readObject()); this.setGhostData(in.readUTF()); + this.setMcode(in.readInt()); + this.setNoteType(in.readInt()); } public long getId() { @@ -81,4 +95,20 @@ public class GhostData implements Externalizable { public void setGhostData(String ghostData) { this.ghostData = ghostData; } + + public int getMcode() { + return mcode; + } + + public void setMcode(int mcode) { + this.mcode = mcode; + } + + public int getNoteType() { + return noteType; + } + + public void setNoteType(int noteType) { + this.noteType = noteType; + } }