diff --git a/src/main/java/com/buttongames/butterfly/http/ButterflyHttpServer.java b/src/main/java/com/buttongames/butterfly/http/ButterflyHttpServer.java index b87babc..91c888a 100644 --- a/src/main/java/com/buttongames/butterfly/http/ButterflyHttpServer.java +++ b/src/main/java/com/buttongames/butterfly/http/ButterflyHttpServer.java @@ -264,7 +264,7 @@ public class ButterflyHttpServer { * @throws SAXException */ private Element validateAndUnpackRequest(Request request) { - /*final String requestUriModel = request.queryParams("model"); + final String requestUriModel = request.queryParams("model"); final String requestUriModule = request.queryParams("module"); final String requestUriMethod = request.queryParams("method"); @@ -280,7 +280,7 @@ public class ButterflyHttpServer { if (!SUPPORTED_MODULES.contains(requestUriModule)) { LOG.warn("Invalid module requested: " + requestUriModule); throw new InvalidRequestModuleException(); - }*/ + } // 3) validate that the PCBID exists in the database final String encryptionKey = request.headers(CRYPT_KEY_HEADER); @@ -333,14 +333,14 @@ public class ButterflyHttpServer { } // 4) validate that the request URI matches the request body - /*if (StringUtils.isBlank(requestBodyModel) || + if (StringUtils.isBlank(requestBodyModel) || StringUtils.isBlank(requestBodyModule) || StringUtils.isBlank(requestBodyMethod) || !requestBodyModel.equals(requestUriModel) || !requestBodyModule.equals(requestUriModule) || !requestBodyMethod.equals(requestUriMethod)) { throw new MismatchedRequestUriException(); - }*/ + } // set the model, pcbid, module, and method as request "attributes" so they can be // used by the request handlers if needed diff --git a/src/main/java/com/buttongames/butterfly/http/handlers/BaseRequestHandler.java b/src/main/java/com/buttongames/butterfly/http/handlers/BaseRequestHandler.java index 91b16c5..9b6e713 100644 --- a/src/main/java/com/buttongames/butterfly/http/handlers/BaseRequestHandler.java +++ b/src/main/java/com/buttongames/butterfly/http/handlers/BaseRequestHandler.java @@ -21,9 +21,6 @@ import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import java.io.ByteArrayOutputStream; import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; import static com.buttongames.butterfly.util.Constants.COMPRESSION_HEADER; import static com.buttongames.butterfly.util.Constants.CRYPT_KEY_HEADER; @@ -81,7 +78,7 @@ public abstract class BaseRequestHandler { * @param response The response object we can use to send the data. * @return A response object for Spark */ - private Object sendBytesToClient(byte[] respBytes, final Request request, final Response response) { + protected Object sendBytesToClient(byte[] respBytes, final Request request, final Response response) { response.header("Connection", "keep-alive"); // convert them to binary XML @@ -89,7 +86,6 @@ public abstract class BaseRequestHandler { respBytes = PublicKt.kbinEncode(new String(respBytes)); } - // TODO: FIX THIS SHIT // compress if needed /*final String compressionScheme = request.headers(COMPRESSION_HEADER); 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 3120af9..2ac6902 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 @@ -282,7 +282,7 @@ public class PlayerDataRequestHandler extends BaseRequestHandler { String dancerCodeStr = String.format("%08d", dancerCode); dancerCodeStr = dancerCodeStr.substring(0, 4) + "-" + dancerCodeStr.substring(4, 8); - profile = new UserProfile(card.getUser(), null, dancerCode, 1, true, 0, 0, 0, 0, 0.0, DancerOption.RANDOM, + profile = new UserProfile(card.getUser(), null, dancerCode, 1, true, 0, 0, 0, -1, 0.0, DancerOption.RANDOM, SpeedOption.X_1_00, BoostOption.NORMAL, AppearanceOption.VISIBLE, TurnOption.OFF, StepZoneOption.ON, ScrollOption.NORMAL, ArrowColorOption.RAINBOW, CutOption.OFF, FreezeArrowOption.ON, JumpsOption.ON, ArrowSkinOption.NORMAL, ScreenFilterOption.OFF, GuideLinesOption.ARROW_CENTER, LifeGaugeOption.NORMAL, @@ -326,20 +326,16 @@ public class PlayerDataRequestHandler extends BaseRequestHandler { // figure out which fields are requested final int recvNum = XmlUtils.intValueAtPath(requestBody, "/playerdata/data/recv_num"); final String recvCsv = XmlUtils.strValueAtPath(requestBody, "/playerdata/data/recv_csv"); - String[] tmp = recvCsv.split(","); + String[] tmp = recvCsv.split(",", -1); String[] colsToSend = new String[recvNum]; for (int i = 0; i < recvNum; i++) { colsToSend[i] = tmp[i * 2]; } - // iterate through each column and send the response - KXmlBuilder builder = KXmlBuilder.create("response") - .e("playerdata") - .s32("result", 0).up() - .e("player") - .u32("record_num", recvNum).up() - .e("record"); + // this response needs to be constructed jankily and manually, because XML libraries don't like the idea + // of embedding a sub-element inside the text content of a node + String csvStrings = ""; for (String col : colsToSend) { String val = null; @@ -358,12 +354,16 @@ public class PlayerDataRequestHandler extends BaseRequestHandler { throw new InvalidRequestException(); } - val = Base64.getEncoder().encodeToString(val.getBytes()); - builder = builder.str("d", val).up(); + val = "" + Base64.getEncoder().encodeToString(val.getBytes()) + ""; + csvStrings += val; } + final String responseStr = String.format("" + + "0%d%s" + + "", recvNum, csvStrings); + // send the response - return this.sendResponse(request, response, builder); + return this.sendBytesToClient(responseStr.getBytes(), request, response); } /** @@ -402,16 +402,16 @@ public class PlayerDataRequestHandler extends BaseRequestHandler { // split these out into CSV arrays, and omit the first 2 elements since those are headers if (value.startsWith("ffffffff,COMMON")) { - commonElems = value.split(","); + commonElems = value.split(",", -1); commonElems = Arrays.copyOfRange(commonElems, 2, commonElems.length); } else if (value.startsWith("ffffffff,OPTION")) { - optionElems = value.split(","); + optionElems = value.split(",", -1); optionElems = Arrays.copyOfRange(optionElems, 2, optionElems.length); } else if (value.startsWith("ffffffff,LAST")) { - lastElems = value.split(","); + lastElems = value.split(",", -1); lastElems = Arrays.copyOfRange(lastElems, 2, lastElems.length); } else if (value.startsWith("ffffffff,RIVAL")) { - rivalElems = value.split(","); + rivalElems = value.split(",", -1); rivalElems = Arrays.copyOfRange(rivalElems, 2, rivalElems.length); } } @@ -432,7 +432,7 @@ public class PlayerDataRequestHandler extends BaseRequestHandler { * @return The CSV string. */ private String buildCommonCsv(final UserProfile profile) { - final String[] elems = "1,0,fffffff,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,,0000-0000,,,,,,".split(","); + final String[] elems = "1,0,fffffff,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,,0000-0000,,,,,,".split(",", -1); // modify the contents to send back String dancerCodeStr = String.format("%08d", profile.getDancerCode()); @@ -443,13 +443,19 @@ public class PlayerDataRequestHandler extends BaseRequestHandler { elems[GAME_COMMON_WEIGHT_DISPLAY_OFFSET] = profile.isDisplayWeight() ? "1" : "0"; elems[GAME_COMMON_CHARACTER_OFFSET] = String.valueOf(profile.getCharacter().ordinal()); elems[GAME_COMMON_EXTRA_CHARGE_OFFSET] = String.valueOf(profile.getExtraCharge()); - elems[GAME_COMMON_TOTAL_PLAYS_OFFSET] = (profile.getTotalPlays() == 0) ? "" : String.valueOf(profile.getTotalPlays()); + elems[GAME_COMMON_TOTAL_PLAYS_OFFSET] = (profile.getTotalPlays() == -1) ? "ffffffffffffffff" : String.valueOf(profile.getTotalPlays()); elems[GAME_COMMON_SINGLE_PLAYS_OFFSET] = String.valueOf(profile.getSinglesPlays()); elems[GAME_COMMON_DOUBLE_PLAYS_OFFSET] = String.valueOf(profile.getDoublesPlays()); elems[GAME_COMMON_WEIGHT_OFFSET] = String.valueOf(profile.getWeight()); - elems[GAME_COMMON_NAME_OFFSET] = (profile.getName() == null) ? "ffffffffffffffff" : profile.getName(); + elems[GAME_COMMON_NAME_OFFSET] = (profile.getName() == null) ? "" : profile.getName(); elems[GAME_COMMON_SEQ_OFFSET] = dancerCodeStr; + // if the total plays was -1, update it to 0 so the user doesn't see the EULA again + if (profile.getTotalPlays() == -1) { + profile.setTotalPlays(0); + this.profileDao.update(profile); + } + return String.join(",", elems); } @@ -459,7 +465,7 @@ public class PlayerDataRequestHandler extends BaseRequestHandler { * @return The CSV string. */ private String buildOptionCsv(final UserProfile profile) { - final String[] elems = "1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10.000000,10.0,10.0,10.0,0.0,0.0,0.0,0.0,,,,,,,,".split(","); + final String[] elems = "1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10.0,10.0,10.0,10.0,0.0,0.0,0.0,0.0,,,,,,,,".split(",", -1); // modify the contents to send back elems[GAME_OPTION_SPEED_OFFSET] = String.valueOf(profile.getSpeedOption().ordinal()); @@ -488,10 +494,11 @@ public class PlayerDataRequestHandler extends BaseRequestHandler { * @return The CSV string. */ private String buildLastCsv(final UserProfile profile) { - final String[] elems = "1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,,,,,,,,".split(","); + final String[] elems = "1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,,,,,,,,".split(",", -1); // modify the contents to send back - elems[GAME_LAST_CALORIES_OFFSET] = String.format("%05x", profile.getLastCalories()); + elems[GAME_LAST_CALORIES_OFFSET] = Integer.toHexString(profile.getLastCalories()); + elems[15] = StringUtils.getRandomHexString(8).toLowerCase(); return String.join(",", elems); } @@ -502,7 +509,7 @@ public class PlayerDataRequestHandler extends BaseRequestHandler { * @return The CSV string. */ private String buildRivalCsv(final UserProfile profile) { - final String[] elems = "1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,,,,,,,,".split(","); + final String[] elems = "1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,,,,,,,,".split(",", -1); // modify the contents to send back elems[GAME_RIVAL_SLOT_1_ACTIVE_OFFSET] = profile.getRival1() == null ? "0" : "1"; @@ -562,7 +569,7 @@ public class PlayerDataRequestHandler extends BaseRequestHandler { final int doublePlays = Integer.parseInt(common[GAME_COMMON_DOUBLE_PLAYS_OFFSET]); final double weight = Double.parseDouble(common[GAME_COMMON_WEIGHT_OFFSET]); final String name = common[GAME_COMMON_NAME_OFFSET]; - final int dancerCode = Integer.parseInt(String.join("", common[GAME_COMMON_SEQ_OFFSET].split("-"))); + final int dancerCode = Integer.parseInt(String.join("", common[GAME_COMMON_SEQ_OFFSET].split("-", -1))); profile.setArea(area); profile.setDisplayWeight(displayWeight); diff --git a/src/main/java/com/buttongames/butterfly/xml/kbinxml/XmlUtil.kt b/src/main/java/com/buttongames/butterfly/xml/kbinxml/XmlUtil.kt index 93a0e63..688697f 100644 --- a/src/main/java/com/buttongames/butterfly/xml/kbinxml/XmlUtil.kt +++ b/src/main/java/com/buttongames/butterfly/xml/kbinxml/XmlUtil.kt @@ -44,8 +44,8 @@ fun Document.prettyString(): String { var Element.text: String get() { - if (this.childCount == 1) { - val e = this.getChild(0) + for (i in 0 until childCount) { + val e = getChild(i) if (e is Text) { return e.value } @@ -53,7 +53,6 @@ var Element.text: String return "" } set(value: String) { - this.removeChildren() this.appendChild(value) }