Skip to content

Commit

Permalink
Check if JSON data still matches what's on the sign
Browse files Browse the repository at this point in the history
BlockLocker uses hidden JSON data to store the UUIDs of players.

Now that Spigot leaves the hidden JSON data intact when updating a sign (see https://hub.spigotmc.org/stash/projects/SPIGOT/repos/craftbukkit/commits/560b65c4f8a15619aaa4a1737c7040f21e725cce#src/main/java/org/bukkit/craftbukkit/block/CraftSign.java ), this data has the potential to become outdated. For example, the /blocklocker <line number> command didn't update the player UUIDs stored on the sign, because the old UUIDs weren't removed anymore.

Now the JSON-data is cross-checked against the text on the sign. If the JSON data doesn't match the text, it is now ignored.

Fixes #92, #93.
  • Loading branch information
rutgerkok committed Jan 5, 2021
1 parent 1f715b5 commit cf38ecc
Showing 1 changed file with 45 additions and 17 deletions.
62 changes: 45 additions & 17 deletions src/main/java/nl/rutgerkok/blocklocker/impl/SignParserImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,16 @@ class SignParserImpl implements SignParser {
this.chestSettings = chestSettings;
}

private int countProfileLines(String[] linesOnSign) {
int count = 0;
for (int i = 1; i < linesOnSign.length; i++) {
if (linesOnSign[i].length() > 0) {
count++;
}
}
return count;
}

@Override
public Optional<SignType> getSignType(Sign sign) {
String header = sign.getLine(0);
Expand Down Expand Up @@ -72,36 +82,54 @@ public boolean hasValidHeader(Sign sign) {
*
* @param location
* The location of the sign.
* @param header
* The header on the sign.
* @param list
* The profile collection to add all profiles to.
* @param jsonSign
* The hidden JSON stored on the sign.
* @param linesOnSign
* The displayed lines stored on the sign.
* @return The parsed sign, if the sign is actually a protection sign.
*/
private Optional<ProtectionSign> parseAdvancedSign(Location location, String header, Iterable<JsonObject> list) {
SignType signType = getSignTypeOrNull(header);
private Optional<ProtectionSign> parseAdvancedSign(Location location, JsonSign jsonSign, String[] linesOnSign) {
SignType signType = getSignTypeOrNull(jsonSign.getFirstLine());
if (signType == null) {
return Optional.empty();
}

List<Profile> profiles = new ArrayList<Profile>();
for (JsonObject object : list) {
Optional<Profile> profile = profileFactory.fromSavedObject(object);
if (profile.isPresent()) {
profiles.add(profile.get());
List<Profile> profiles = new ArrayList<>();
int lineNumber = 1; // Starts as one, as line 0 contains the sign header`
for (JsonObject object : jsonSign) {
Optional<Profile> oProfile = profileFactory.fromSavedObject(object);
if (oProfile.isPresent()) {
Profile profile = oProfile.get();

String lineOnSign = linesOnSign[lineNumber];
if (!profile.getDisplayName().equals(lineOnSign)) {
// JSON data doesn't match sign contents, so it must be corrupt or outdated
// Therefore, ignore the data
return parseSimpleSign(location, linesOnSign);
}

profiles.add(profile);
}
lineNumber++;
}

return Optional.<ProtectionSign> of(new ProtectionSignImpl(location, signType, profiles));
if (countProfileLines(linesOnSign) > profiles.size()) {
// JSON data is incomplete, therefore corrupt or outdated
// Therefore, ignore the data
return parseSimpleSign(location, linesOnSign);
}

return Optional.<ProtectionSign>of(new ProtectionSignImpl(location, signType, profiles));
}

@Override
public Optional<ProtectionSign> parseSign(Block sign) {
JsonSign foundTextData = nms.getJsonData(sign.getWorld(), sign.getX(), sign.getY(), sign.getZ());
String[] lines = ((Sign) sign.getState()).getLines();
if (foundTextData.hasData()) {
return parseAdvancedSign(sign.getLocation(), foundTextData.getFirstLine(), foundTextData);
return parseAdvancedSign(sign.getLocation(), foundTextData, lines);
} else {
return parseSimpleSign(sign.getLocation(), ((Sign)sign.getState()).getLines());
return parseSimpleSign(sign.getLocation(), lines);
}
}

Expand All @@ -127,7 +155,7 @@ private Optional<ProtectionSign> parseSimpleSign(Location location, String[] lin
return Optional.empty();
}

List<Profile> profiles = new ArrayList<Profile>();
List<Profile> profiles = new ArrayList<>();
for (int i = 1; i < lines.length; i++) {
String name = lines[i].trim();
profiles.add(profileFactory.fromDisplayText(name));
Expand All @@ -137,7 +165,7 @@ private Optional<ProtectionSign> parseSimpleSign(Location location, String[] lin
// advanced signs
return Optional.<ProtectionSign> of(new ProtectionSignImpl(location, signType, profiles));
}

@Override
public void saveSign(ProtectionSign sign) {
// Find sign
Expand All @@ -150,7 +178,7 @@ public void saveSign(ProtectionSign sign) {

// Update sign, both visual and using raw JSON
Sign signState = (Sign) blockState;

signState.setLine(0, chestSettings.getFancyLocalizedHeader(sign.getType(), signState.getLine(0)));

JsonArray jsonArray = new JsonArray();
Expand Down

0 comments on commit cf38ecc

Please sign in to comment.