diff --git a/src/engine/objects/PlayerCharacter.java b/src/engine/objects/PlayerCharacter.java index 6a0ba931..ee21afd8 100644 --- a/src/engine/objects/PlayerCharacter.java +++ b/src/engine/objects/PlayerCharacter.java @@ -730,6 +730,14 @@ public class PlayerCharacter extends AbstractCharacter { } + // The client enforces these rules, so a refusal usually means a modified client. + + private static PlayerCharacter refuseCreation(Account account, ClientConnection clientConnection, String reason) { + Logger.warn("Character creation refused: " + reason + " ACCOUNT: " + account.getUname() + "(" + account.getObjectUUID() + + ") IP ADDRESS: " + clientConnection.getClientIpAddress()); + return null; + } + public static PlayerCharacter generatePCFromCommitNewCharacterMsg(Account a, CommitNewCharacterMsg msg, ClientConnection clientConnection) { String firstName = msg.getFirstName().trim(); @@ -768,8 +776,7 @@ public class PlayerCharacter extends AbstractCharacter { Race race = Race.getRace(raceID); if (race == null) { - Logger.info("Invalid RaceID: " + raceID); - return null; + return refuseCreation(a, clientConnection, "Invalid RaceID: " + raceID); } // Verify BaseClass Object. @@ -777,8 +784,7 @@ public class PlayerCharacter extends AbstractCharacter { BaseClass baseClass = DbManager.BaseClassQueries.GET_BASE_CLASS(baseClassID); if (baseClass == null) { - Logger.info("Invalid BaseClasID: " + baseClassID); - return null; + return refuseCreation(a, clientConnection, "Invalid BaseClasID: " + baseClassID); } // Verify Race/baseClass combo. @@ -793,8 +799,7 @@ public class PlayerCharacter extends AbstractCharacter { } if (!valid) { - Logger.info("Invalid BaseClass/Race Combo"); - return null; + return refuseCreation(a, clientConnection, "Invalid BaseClass/Race Combo"); } // Verify HairStyle/BeardStyle/SkinColor/HairColor/BeardColor @@ -805,23 +810,19 @@ public class PlayerCharacter extends AbstractCharacter { int beardColorID = msg.getBeardColor(); if (!race.isValidHairStyle(hairStyleID)) { - Logger.info("Invalid HairStyleID: " + hairStyleID + " for race: " + race.getName()); - return null; + return refuseCreation(a, clientConnection, "Invalid HairStyleID: " + hairStyleID + " for race: " + race.getName()); } if (!race.isValidSkinColor(skinColorID)) { - Logger.info("Invalid skinColorID: " + skinColorID + " for race: " + race.getName()); - return null; + return refuseCreation(a, clientConnection, "Invalid skinColorID: " + skinColorID + " for race: " + race.getName()); } if (!race.isValidHairColor(hairColorID)) { - Logger.info("Invalid hairColorID: " + hairColorID + " for race: " + race.getName()); - return null; + return refuseCreation(a, clientConnection, "Invalid hairColorID: " + hairColorID + " for race: " + race.getName()); } if (!race.isValidBeardColor(beardColorID)) { - Logger.info("Invalid beardColorID: " + beardColorID + " for race: " + race.getName()); - return null; + return refuseCreation(a, clientConnection, "Invalid beardColorID: " + beardColorID + " for race: " + race.getName()); } // Get stat modifiers @@ -833,8 +834,7 @@ public class PlayerCharacter extends AbstractCharacter { if (intMod < -5 || dexMod < -5 || conMod < -5 || strMod < -5 || spiMod < -5) { - Logger.error("NEGATIVE STAT CHEAT ATTEMPTED! ACCOUNT: " + a.getUname() + "(" + a.getObjectUUID() + ") IP ADDRESS: " + clientConnection.getClientIpAddress()); - return null; + return refuseCreation(a, clientConnection, "Negative stat mod"); } // calculate current stats: @@ -855,8 +855,7 @@ public class PlayerCharacter extends AbstractCharacter { int numRunes = msg.getNumRunes(); if (numRunes > 10) { - Logger.info("Too many Runes applied"); - return null; + return refuseCreation(a, clientConnection, "Too many Runes applied"); } // Get Runes @@ -907,39 +906,33 @@ public class PlayerCharacter extends AbstractCharacter { // Null check if (runeBase == null) { - Logger.info("GOM returned NULL RuneBase"); - return null; + return refuseCreation(a, clientConnection, "GOM returned NULL RuneBase"); } // Validate Rune against Race if (!race.isAllowedRune(runeBase)) { - Logger.info("Trait Not valid for Race"); - return null; + return refuseCreation(a, clientConnection, "Trait Not valid for Race"); } // Validate BaseClass against Race if (!baseClass.isAllowedRune(runeBase)) { - Logger.info("Trait Not valid for BaseClass"); - return null; + return refuseCreation(a, clientConnection, "Trait Not valid for BaseClass"); } if (!usedRuneIDs.add(runeBase.getObjectUUID())) { - Logger.info("Duplicate RuneBase"); - return null; + return refuseCreation(a, clientConnection, "Duplicate RuneBase"); } // Creation talents are rank 0, so two of the same sub type block each other (client 0x4695D0) if (runeBase.getSubTypeToken() != 0 && !usedSubTypeTokens.add(runeBase.getSubTypeToken())) { - Logger.info("Duplicate RuneBase Subtype"); - return null; + return refuseCreation(a, clientConnection, "Duplicate RuneBase Subtype"); } usedRunes.add(runeBase); // Talent cap of 8 (client 0x4695D0) if (usedRunes.size() > 8) { - Logger.info("Too many talents applied"); - return null; + return refuseCreation(a, clientConnection, "Too many talents applied"); } int maxValue = 0; @@ -984,43 +977,37 @@ public class PlayerCharacter extends AbstractCharacter { remainingPoints -= value; continue; } - Logger.info("Not enough points left"); - return null; + return refuseCreation(a, clientConnection, "Not enough points left"); case MBServerStatics.RUNE_STR_MIN_NEEDED_ATTRIBUTE_ID: if (strCur >= value) continue; - Logger.info("STR fails to meet Rune Minimum --> " + rb.getName()); - return null; + return refuseCreation(a, clientConnection, "STR fails to meet Rune Minimum --> " + rb.getName()); case MBServerStatics.RUNE_DEX_MIN_NEEDED_ATTRIBUTE_ID: if (dexCur >= value) continue; - Logger.info("DEX fails to meet Rune Minimum --> " + rb.getName()); - return null; + return refuseCreation(a, clientConnection, "DEX fails to meet Rune Minimum --> " + rb.getName()); case MBServerStatics.RUNE_CON_MIN_NEEDED_ATTRIBUTE_ID: if (conCur >= value) continue; - Logger.info("CON fails to meet Rune Minimum --> " + rb.getName()); - return null; + return refuseCreation(a, clientConnection, "CON fails to meet Rune Minimum --> " + rb.getName()); case MBServerStatics.RUNE_INT_MIN_NEEDED_ATTRIBUTE_ID: if (intCur >= value) continue; - Logger.info("INT fails to meet Rune Minimum --> " + rb.getName()); - return null; + return refuseCreation(a, clientConnection, "INT fails to meet Rune Minimum --> " + rb.getName()); case MBServerStatics.RUNE_SPI_MIN_NEEDED_ATTRIBUTE_ID: if (spiCur >= value) continue; - Logger.info("SPI fails to meet Rune Minimum --> " + rb.getName()); - return null; + return refuseCreation(a, clientConnection, "SPI fails to meet Rune Minimum --> " + rb.getName()); case MBServerStatics.RUNE_STR_ATTRIBUTE_ID: if (value < 0) @@ -1085,21 +1072,18 @@ public class PlayerCharacter extends AbstractCharacter { continue; default: - Logger.info("Unknown ATTRIBUTE_ID while checking RuneBaseAttributes: " + attrID); - return null; + return refuseCreation(a, clientConnection, "Unknown ATTRIBUTE_ID while checking RuneBaseAttributes: " + attrID); } } } // Checked before the penalties, as the client's +/- does (0xBAC140): Giant's Blood cuts a max below its stat if (strCur < 1 || dexCur < 1 || conCur < 1 || intCur < 1 || spiCur < 1) { - Logger.info("Attribute below 1"); - return null; + return refuseCreation(a, clientConnection, "Attribute below 1"); } if (strCur > strMax || dexCur > dexMax || conCur > conMax || intCur > intMax || spiCur > spiMax) { - Logger.info("Attribute above racial maximum"); - return null; + return refuseCreation(a, clientConnection, "Attribute above racial maximum"); } // Add in all of the penalties. @@ -1130,8 +1114,7 @@ public class PlayerCharacter extends AbstractCharacter { } if (kit == null) { - Logger.info("Unable to find matching kitID: " + kitID); - return null; + return refuseCreation(a, clientConnection, "Unable to find matching kitID: " + kitID); } byte runningTrains = 0;