diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/conditions/WiredConditionFurniTypeMatch.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/conditions/WiredConditionFurniTypeMatch.java index 02d2a0c9..42ee69c8 100644 --- a/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/conditions/WiredConditionFurniTypeMatch.java +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/conditions/WiredConditionFurniTypeMatch.java @@ -52,6 +52,10 @@ public class WiredConditionFurniTypeMatch extends InteractionWiredCondition { @Override public boolean evaluate(WiredContext ctx) { + if (ctx == null) { + return false; + } + if (this.quantifier == QUANTIFIER_ANY) { return this.evaluateAnyMatches(ctx); } @@ -158,7 +162,14 @@ public class WiredConditionFurniTypeMatch extends InteractionWiredCondition { } if (wiredData.startsWith("{")) { - JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class); + JsonData data; + try { + data = WiredManager.getGson().fromJson(wiredData, JsonData.class); + } catch (RuntimeException exception) { + this.onPickUp(); + return; + } + if (data == null) { return; } @@ -310,8 +321,8 @@ public class WiredConditionFurniTypeMatch extends InteractionWiredCondition { } } - private void loadItems(Room room, List itemIds, THashSet target) { - if (itemIds == null) { + void loadItems(Room room, List itemIds, THashSet target) { + if (room == null || itemIds == null || target == null) { return; } @@ -335,7 +346,7 @@ public class WiredConditionFurniTypeMatch extends InteractionWiredCondition { .collect(Collectors.joining(";")); } - private List parseIds(String value) { + List parseIds(String value) { List result = new ArrayList<>(); if (value == null || value.isEmpty()) { return result; diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/conditions/WiredConditionMatchStatePosition.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/conditions/WiredConditionMatchStatePosition.java index 36e721fc..b6050f44 100644 --- a/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/conditions/WiredConditionMatchStatePosition.java +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/conditions/WiredConditionMatchStatePosition.java @@ -87,7 +87,7 @@ public class WiredConditionMatchStatePosition extends InteractionWiredCondition this.direction = params[1] == 1; this.position = params[2] == 1; this.altitude = (params.length > 3) && (params[3] == 1); - this.furniSource = (params.length > 4) ? params[4] : ((params.length > 3 && params[3] > 1) ? params[3] : WiredSourceUtil.SOURCE_TRIGGER); + this.furniSource = (params.length > 4) ? this.normalizeFurniSource(params[4]) : ((params.length > 3 && params[3] > 1) ? this.normalizeFurniSource(params[3]) : WiredSourceUtil.SOURCE_TRIGGER); this.quantifier = (params.length > 5) ? this.normalizeQuantifier(params[5]) : QUANTIFIER_ALL; Room room = Emulator.getGameEnvironment().getRoomManager().getRoom(this.getRoomId()); @@ -113,6 +113,10 @@ public class WiredConditionMatchStatePosition extends InteractionWiredCondition @Override public boolean evaluate(WiredContext ctx) { + if (ctx == null || ctx.room() == null) { + return false; + } + this.refresh(); if (this.settings.isEmpty()) @@ -126,6 +130,10 @@ public class WiredConditionMatchStatePosition extends InteractionWiredCondition } protected boolean evaluateAllTargetsMatch(WiredContext ctx) { + if (ctx == null || ctx.room() == null) { + return false; + } + Room room = ctx.room(); if (this.furniSource != WiredSourceUtil.SOURCE_SELECTED) { @@ -159,6 +167,10 @@ public class WiredConditionMatchStatePosition extends InteractionWiredCondition } protected boolean evaluateAnyTargetMatches(WiredContext ctx) { + if (ctx == null || ctx.room() == null) { + return false; + } + Room room = ctx.room(); if (this.furniSource != WiredSourceUtil.SOURCE_SELECTED) { @@ -247,18 +259,38 @@ public class WiredConditionMatchStatePosition extends InteractionWiredCondition @Override public void loadWiredData(ResultSet set, Room room) throws SQLException { + this.onPickUp(); String wiredData = set.getString("wired_data"); + if (wiredData == null || wiredData.isEmpty()) { + return; + } if (wiredData.startsWith("{")) { - JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class); + JsonData data; + try { + data = WiredManager.getGson().fromJson(wiredData, JsonData.class); + } catch (RuntimeException exception) { + this.onPickUp(); + return; + } + + if (data == null) { + return; + } + this.state = data.state; this.position = data.position; this.direction = data.direction; this.altitude = data.altitude; if (data.settings != null) { - this.settings.addAll(data.settings); + for (WiredMatchFurniSetting setting : data.settings) { + WiredMatchFurniSetting normalized = this.normalizeSetting(setting); + if (normalized != null) { + this.settings.add(normalized); + } + } } - this.furniSource = data.furniSource; + this.furniSource = this.normalizeFurniSource(data.furniSource); this.quantifier = this.normalizeQuantifier(data.quantifier); } else { String[] data = wiredData.split(":"); @@ -272,10 +304,10 @@ public class WiredConditionMatchStatePosition extends InteractionWiredCondition for (int i = 0; i < itemCount && i < items.length; i++) { String[] stuff = items[i].split("-"); - if (stuff.length >= 6) - this.settings.add(new WiredMatchFurniSetting(Integer.parseInt(stuff[0]), stuff[1], Integer.parseInt(stuff[2]), Integer.parseInt(stuff[3]), Integer.parseInt(stuff[4]), Double.parseDouble(stuff[5]))); - else if (stuff.length >= 5) - this.settings.add(new WiredMatchFurniSetting(Integer.parseInt(stuff[0]), stuff[1], Integer.parseInt(stuff[2]), Integer.parseInt(stuff[3]), Integer.parseInt(stuff[4]))); + WiredMatchFurniSetting parsed = this.parseLegacySetting(stuff); + if (parsed != null) { + this.settings.add(parsed); + } } this.state = data[2].equals("1"); @@ -303,10 +335,58 @@ public class WiredConditionMatchStatePosition extends InteractionWiredCondition this.quantifier = QUANTIFIER_ALL; } - private int normalizeQuantifier(int value) { + int normalizeQuantifier(int value) { return (value == QUANTIFIER_ANY) ? QUANTIFIER_ANY : QUANTIFIER_ALL; } + int normalizeFurniSource(int value) { + switch (value) { + case WiredSourceUtil.SOURCE_TRIGGER: + case WiredSourceUtil.SOURCE_SELECTED: + case WiredSourceUtil.SOURCE_SELECTOR: + case WiredSourceUtil.SOURCE_SIGNAL: + return value; + default: + return WiredSourceUtil.SOURCE_TRIGGER; + } + } + + WiredMatchFurniSetting normalizeSetting(WiredMatchFurniSetting setting) { + if (setting == null || setting.item_id <= 0) { + return null; + } + + int rotation = Math.max(0, Math.min(7, setting.rotation)); + int x = Math.max(0, setting.x); + int y = Math.max(0, setting.y); + double z = Math.max(0.0D, Math.min(Room.MAXIMUM_FURNI_HEIGHT, setting.z)); + + return new WiredMatchFurniSetting(setting.item_id, setting.state, rotation, x, y, z); + } + + WiredMatchFurniSetting parseLegacySetting(String[] values) { + if (values == null || values.length < 5) { + return null; + } + + try { + int itemId = Integer.parseInt(values[0]); + if (itemId <= 0) { + return null; + } + + String state = values[1]; + int rotation = Integer.parseInt(values[2]); + int x = Integer.parseInt(values[3]); + int y = Integer.parseInt(values[4]); + double z = values.length >= 6 ? Double.parseDouble(values[5]) : 0.0D; + + return this.normalizeSetting(new WiredMatchFurniSetting(itemId, state, rotation, x, y, z)); + } catch (RuntimeException exception) { + return null; + } + } + protected void refresh() { Room room = Emulator.getGameEnvironment().getRoomManager().getRoom(this.getRoomId()); diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/conditions/WiredConditionNotFurniTypeMatch.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/conditions/WiredConditionNotFurniTypeMatch.java index 49dc6775..501a7560 100644 --- a/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/conditions/WiredConditionNotFurniTypeMatch.java +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/conditions/WiredConditionNotFurniTypeMatch.java @@ -20,6 +20,10 @@ public class WiredConditionNotFurniTypeMatch extends WiredConditionFurniTypeMatc @Override public boolean evaluate(WiredContext ctx) { + if (ctx == null) { + return false; + } + if (this.getQuantifier() == QUANTIFIER_ANY) { return !this.evaluateAllMatches(ctx); } diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/conditions/WiredConditionNotMatchStatePosition.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/conditions/WiredConditionNotMatchStatePosition.java index e52315dc..8fcaa996 100644 --- a/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/conditions/WiredConditionNotMatchStatePosition.java +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/interactions/wired/conditions/WiredConditionNotMatchStatePosition.java @@ -22,6 +22,10 @@ public class WiredConditionNotMatchStatePosition extends WiredConditionMatchStat @Override public boolean evaluate(WiredContext ctx) { + if (ctx == null || ctx.room() == null) { + return false; + } + this.refresh(); if (this.getMatchFurniSettings().isEmpty()) { diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/wired/WiredMatchFurniSetting.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/wired/WiredMatchFurniSetting.java index 5179e503..241974f0 100644 --- a/Emulator/src/main/java/com/eu/habbo/habbohotel/wired/WiredMatchFurniSetting.java +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/wired/WiredMatchFurniSetting.java @@ -14,7 +14,7 @@ public class WiredMatchFurniSetting { public WiredMatchFurniSetting(int itemId, String state, int rotation, int x, int y, double z) { this.item_id = itemId; - this.state = state.replace("\t\t\t", " "); + this.state = state == null ? "" : state.replace("\t\t\t", " "); this.rotation = rotation; this.x = x; this.y = y; diff --git a/Emulator/src/test/java/com/eu/habbo/habbohotel/items/interactions/wired/conditions/WiredConditionMatchPayloadGuardTest.java b/Emulator/src/test/java/com/eu/habbo/habbohotel/items/interactions/wired/conditions/WiredConditionMatchPayloadGuardTest.java new file mode 100644 index 00000000..e667ae73 --- /dev/null +++ b/Emulator/src/test/java/com/eu/habbo/habbohotel/items/interactions/wired/conditions/WiredConditionMatchPayloadGuardTest.java @@ -0,0 +1,56 @@ +package com.eu.habbo.habbohotel.items.interactions.wired.conditions; + +import com.eu.habbo.habbohotel.rooms.Room; +import com.eu.habbo.habbohotel.wired.WiredMatchFurniSetting; +import com.eu.habbo.habbohotel.wired.core.WiredSourceUtil; +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; + +class WiredConditionMatchPayloadGuardTest { + @Test + void matchStateNormalizesSourcesQuantifierAndSettings() { + WiredConditionMatchStatePosition condition = new WiredConditionMatchStatePosition(1, 1, null, "", 0, 0); + + assertEquals(WiredSourceUtil.SOURCE_SELECTED, condition.normalizeFurniSource(WiredSourceUtil.SOURCE_SELECTED)); + assertEquals(WiredSourceUtil.SOURCE_TRIGGER, condition.normalizeFurniSource(9090)); + assertEquals(1, condition.normalizeQuantifier(1)); + assertEquals(0, condition.normalizeQuantifier(9)); + + WiredMatchFurniSetting normalized = condition.normalizeSetting(new WiredMatchFurniSetting(5, null, 99, -10, -20, Room.MAXIMUM_FURNI_HEIGHT + 100)); + + assertNotNull(normalized); + assertEquals(5, normalized.item_id); + assertEquals("", normalized.state); + assertEquals(7, normalized.rotation); + assertEquals(0, normalized.x); + assertEquals(0, normalized.y); + assertEquals(Room.MAXIMUM_FURNI_HEIGHT, normalized.z); + assertNull(condition.normalizeSetting(new WiredMatchFurniSetting(0, "", 0, 0, 0, 0))); + } + + @Test + void matchStateParsesLegacySettingsSafely() { + WiredConditionMatchStatePosition condition = new WiredConditionMatchStatePosition(1, 1, null, "", 0, 0); + + assertNotNull(condition.parseLegacySetting(new String[]{"7", "1", "2", "3", "4", "5"})); + assertNull(condition.parseLegacySetting(new String[]{"bad", "1", "2", "3", "4"})); + assertNull(condition.parseLegacySetting(new String[]{"7", "1"})); + } + + @Test + void furniTypeMatchBoundsSourcesAndParsesIds() { + WiredConditionFurniTypeMatch condition = new WiredConditionFurniTypeMatch(1, 1, null, "", 0, 0); + + assertEquals(WiredSourceUtil.SOURCE_SIGNAL, condition.normalizeFurniSource(WiredSourceUtil.SOURCE_SIGNAL)); + assertEquals(WiredConditionFurniTypeMatch.SOURCE_SECONDARY_SELECTED, condition.normalizeFurniSource(WiredConditionFurniTypeMatch.SOURCE_SECONDARY_SELECTED)); + assertEquals(WiredSourceUtil.SOURCE_TRIGGER, condition.normalizeFurniSource(-77)); + assertEquals(1, condition.normalizeQuantifier(1)); + assertEquals(0, condition.normalizeQuantifier(6)); + assertEquals(List.of(1, 2, 3), condition.parseIds("1;bad,2\t3")); + } +}