Merge pull request #255 from simoleo89/fix/wired-match-payloads

fix(wired): bound match payloads
This commit is contained in:
DuckieTM
2026-06-18 12:45:53 +02:00
committed by GitHub
6 changed files with 157 additions and 7 deletions
@@ -52,6 +52,10 @@ public class WiredConditionFurniTypeMatch extends InteractionWiredCondition {
@Override @Override
public boolean evaluate(WiredContext ctx) { public boolean evaluate(WiredContext ctx) {
if (ctx == null) {
return false;
}
if (this.quantifier == QUANTIFIER_ANY) { if (this.quantifier == QUANTIFIER_ANY) {
return this.evaluateAnyMatches(ctx); return this.evaluateAnyMatches(ctx);
} }
@@ -158,7 +162,14 @@ public class WiredConditionFurniTypeMatch extends InteractionWiredCondition {
} }
if (wiredData.startsWith("{")) { 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) { if (data == null) {
return; return;
} }
@@ -310,8 +321,8 @@ public class WiredConditionFurniTypeMatch extends InteractionWiredCondition {
} }
} }
private void loadItems(Room room, List<Integer> itemIds, THashSet<HabboItem> target) { void loadItems(Room room, List<Integer> itemIds, THashSet<HabboItem> target) {
if (itemIds == null) { if (room == null || itemIds == null || target == null) {
return; return;
} }
@@ -335,7 +346,7 @@ public class WiredConditionFurniTypeMatch extends InteractionWiredCondition {
.collect(Collectors.joining(";")); .collect(Collectors.joining(";"));
} }
private List<Integer> parseIds(String value) { List<Integer> parseIds(String value) {
List<Integer> result = new ArrayList<>(); List<Integer> result = new ArrayList<>();
if (value == null || value.isEmpty()) { if (value == null || value.isEmpty()) {
return result; return result;
@@ -115,6 +115,10 @@ public class WiredConditionMatchStatePosition extends InteractionWiredCondition
@Override @Override
public boolean evaluate(WiredContext ctx) { public boolean evaluate(WiredContext ctx) {
if (ctx == null || ctx.room() == null) {
return false;
}
this.refresh(); this.refresh();
if (this.settings.isEmpty()) if (this.settings.isEmpty())
@@ -128,6 +132,10 @@ public class WiredConditionMatchStatePosition extends InteractionWiredCondition
} }
protected boolean evaluateAllTargetsMatch(WiredContext ctx) { protected boolean evaluateAllTargetsMatch(WiredContext ctx) {
if (ctx == null || ctx.room() == null) {
return false;
}
Room room = ctx.room(); Room room = ctx.room();
if (this.furniSource != WiredSourceUtil.SOURCE_SELECTED) { if (this.furniSource != WiredSourceUtil.SOURCE_SELECTED) {
@@ -161,6 +169,10 @@ public class WiredConditionMatchStatePosition extends InteractionWiredCondition
} }
protected boolean evaluateAnyTargetMatches(WiredContext ctx) { protected boolean evaluateAnyTargetMatches(WiredContext ctx) {
if (ctx == null || ctx.room() == null) {
return false;
}
Room room = ctx.room(); Room room = ctx.room();
if (this.furniSource != WiredSourceUtil.SOURCE_SELECTED) { if (this.furniSource != WiredSourceUtil.SOURCE_SELECTED) {
@@ -249,10 +261,25 @@ public class WiredConditionMatchStatePosition extends InteractionWiredCondition
@Override @Override
public void loadWiredData(ResultSet set, Room room) throws SQLException { public void loadWiredData(ResultSet set, Room room) throws SQLException {
this.onPickUp();
String wiredData = set.getString("wired_data"); String wiredData = set.getString("wired_data");
if (wiredData == null || wiredData.isEmpty()) {
return;
}
if (wiredData.startsWith("{")) { 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.state = data.state;
this.position = data.position; this.position = data.position;
this.direction = data.direction; this.direction = data.direction;
@@ -323,10 +350,58 @@ public class WiredConditionMatchStatePosition extends InteractionWiredCondition
this.quantifier = QUANTIFIER_ALL; this.quantifier = QUANTIFIER_ALL;
} }
private int normalizeQuantifier(int value) { int normalizeQuantifier(int value) {
return (value == QUANTIFIER_ANY) ? QUANTIFIER_ANY : QUANTIFIER_ALL; 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() { protected void refresh() {
Room room = Emulator.getGameEnvironment().getRoomManager().getRoom(this.getRoomId()); Room room = Emulator.getGameEnvironment().getRoomManager().getRoom(this.getRoomId());
@@ -20,6 +20,10 @@ public class WiredConditionNotFurniTypeMatch extends WiredConditionFurniTypeMatc
@Override @Override
public boolean evaluate(WiredContext ctx) { public boolean evaluate(WiredContext ctx) {
if (ctx == null) {
return false;
}
if (this.getQuantifier() == QUANTIFIER_ANY) { if (this.getQuantifier() == QUANTIFIER_ANY) {
return !this.evaluateAllMatches(ctx); return !this.evaluateAllMatches(ctx);
} }
@@ -22,6 +22,10 @@ public class WiredConditionNotMatchStatePosition extends WiredConditionMatchStat
@Override @Override
public boolean evaluate(WiredContext ctx) { public boolean evaluate(WiredContext ctx) {
if (ctx == null || ctx.room() == null) {
return false;
}
this.refresh(); this.refresh();
if (this.getMatchFurniSettings().isEmpty()) { if (this.getMatchFurniSettings().isEmpty()) {
@@ -14,7 +14,7 @@ public class WiredMatchFurniSetting {
public WiredMatchFurniSetting(int itemId, String state, int rotation, int x, int y, double z) { public WiredMatchFurniSetting(int itemId, String state, int rotation, int x, int y, double z) {
this.item_id = itemId; this.item_id = itemId;
this.state = state.replace("\t\t\t", " "); this.state = state == null ? "" : state.replace("\t\t\t", " ");
this.rotation = rotation; this.rotation = rotation;
this.x = x; this.x = x;
this.y = y; this.y = y;
@@ -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"));
}
}