feat(wired): add antenna signals and selector-aware snapshots

This commit is contained in:
Lorenzune
2026-03-16 15:12:42 +01:00
parent fd3599d7fd
commit 264bea3c8b
9 changed files with 503 additions and 221 deletions
@@ -202,6 +202,7 @@ public class ItemManager {
this.interactionsList.add(new ItemInteraction("random_state", InteractionRandomState.class)); this.interactionsList.add(new ItemInteraction("random_state", InteractionRandomState.class));
this.interactionsList.add(new ItemInteraction("vendingmachine_no_sides", InteractionNoSidesVendingMachine.class)); this.interactionsList.add(new ItemInteraction("vendingmachine_no_sides", InteractionNoSidesVendingMachine.class));
this.interactionsList.add(new ItemInteraction("tile_walkmagic", InteractionTileWalkMagic.class)); this.interactionsList.add(new ItemInteraction("tile_walkmagic", InteractionTileWalkMagic.class));
this.interactionsList.add(new ItemInteraction("antenna", InteractionDefault.class));
this.interactionsList.add(new ItemInteraction("game_timer", InteractionGameTimer.class)); this.interactionsList.add(new ItemInteraction("game_timer", InteractionGameTimer.class));
@@ -19,9 +19,7 @@ import gnu.trove.set.hash.THashSet;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set;
public class WiredConditionMatchStatePosition extends InteractionWiredCondition implements InteractionWiredMatchFurniSettings { public class WiredConditionMatchStatePosition extends InteractionWiredCondition implements InteractionWiredMatchFurniSettings {
public static final WiredConditionType type = WiredConditionType.MATCH_SSHOT; public static final WiredConditionType type = WiredConditionType.MATCH_SSHOT;
@@ -92,7 +90,6 @@ public class WiredConditionMatchStatePosition extends InteractionWiredCondition
this.settings.clear(); this.settings.clear();
if (this.furniSource == WiredSourceUtil.SOURCE_SELECTED) {
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
int itemId = settings.getFurniIds()[i]; int itemId = settings.getFurniIds()[i];
HabboItem item = room.getHabboItem(itemId); HabboItem item = room.getHabboItem(itemId);
@@ -100,7 +97,6 @@ public class WiredConditionMatchStatePosition extends InteractionWiredCondition
if (item != null) if (item != null)
this.settings.add(new WiredMatchFurniSetting(item.getId(), item.getExtradata(), item.getRotation(), item.getX(), item.getY())); this.settings.add(new WiredMatchFurniSetting(item.getId(), item.getExtradata(), item.getRotation(), item.getX(), item.getY()));
} }
}
return true; return true;
} }
@@ -108,65 +104,71 @@ public class WiredConditionMatchStatePosition extends InteractionWiredCondition
@Override @Override
public boolean evaluate(WiredContext ctx) { public boolean evaluate(WiredContext ctx) {
Room room = ctx.room(); Room room = ctx.room();
this.refresh();
if (this.settings.isEmpty()) if (this.settings.isEmpty())
return true; return true;
List<HabboItem> targets = null;
Set<Integer> targetIds = null;
if (this.furniSource != WiredSourceUtil.SOURCE_SELECTED) { if (this.furniSource != WiredSourceUtil.SOURCE_SELECTED) {
targets = WiredSourceUtil.resolveItems(ctx, this.furniSource, null); List<HabboItem> targets = WiredSourceUtil.resolveItems(ctx, this.furniSource, null);
if (targets.isEmpty()) return false; if (targets.isEmpty()) return false;
targetIds = new HashSet<>();
for (HabboItem item : targets) { for (HabboItem item : targets) {
if (item != null) targetIds.add(item.getId()); if (item == null) return false;
}
if (targetIds.isEmpty()) return false;
}
THashSet<WiredMatchFurniSetting> toRemove = new THashSet<>(); WiredMatchFurniSetting setting = this.resolveSettingForTarget(room, item);
Set<Integer> settingsIds = new HashSet<>(); if (setting == null) {
for (WiredMatchFurniSetting setting : this.settings) {
if (targetIds != null && !targetIds.contains(setting.item_id)) {
continue;
}
HabboItem item = room.getHabboItem(setting.item_id);
if (item != null) {
settingsIds.add(setting.item_id);
if (this.state) {
if (!item.getExtradata().equals(setting.state))
return false; return false;
} }
if (this.position) { if (!this.matchesSetting(item, setting)) {
if (!(setting.x == item.getX() && setting.y == item.getY()))
return false; return false;
} }
if (this.direction) {
if (setting.rotation != item.getRotation())
return false;
}
} else {
toRemove.add(setting);
}
}
if (targetIds != null && !settingsIds.containsAll(targetIds)) {
return false;
}
if (!toRemove.isEmpty()) {
for (WiredMatchFurniSetting setting : toRemove) {
this.settings.remove(setting);
}
} }
return true; return true;
} }
for (WiredMatchFurniSetting setting : this.settings) {
HabboItem item = room.getHabboItem(setting.item_id);
if (item == null) continue;
if (!this.matchesSetting(item, setting))
return false;
}
return true;
}
private WiredMatchFurniSetting resolveSettingForTarget(Room room, HabboItem target) {
WiredMatchFurniSetting fallback = null;
for (WiredMatchFurniSetting setting : this.settings) {
HabboItem sourceItem = room.getHabboItem(setting.item_id);
if (sourceItem == null) continue;
if (sourceItem.getBaseItem().getId() != target.getBaseItem().getId()) continue;
if (setting.state.equals(target.getExtradata())) {
return setting;
}
if (fallback == null) {
fallback = setting;
}
}
return fallback;
}
private boolean matchesSetting(HabboItem item, WiredMatchFurniSetting setting) {
if (this.state && !item.getExtradata().equals(setting.state))
return false;
if (this.position && !(setting.x == item.getX() && setting.y == item.getY()))
return false;
return !this.direction || setting.rotation == item.getRotation();
}
@Deprecated @Deprecated
@Override @Override
public boolean execute(RoomUnit roomUnit, Room room, Object[] stuff) { public boolean execute(RoomUnit roomUnit, Room room, Object[] stuff) {
@@ -214,9 +216,6 @@ public class WiredConditionMatchStatePosition extends InteractionWiredCondition
this.position = data[4].equals("1"); this.position = data[4].equals("1");
this.furniSource = this.settings.isEmpty() ? WiredSourceUtil.SOURCE_TRIGGER : WiredSourceUtil.SOURCE_SELECTED; this.furniSource = this.settings.isEmpty() ? WiredSourceUtil.SOURCE_TRIGGER : WiredSourceUtil.SOURCE_SELECTED;
} }
if (this.furniSource == WiredSourceUtil.SOURCE_TRIGGER && !this.settings.isEmpty()) {
this.furniSource = WiredSourceUtil.SOURCE_SELECTED;
}
} }
@Override @Override
@@ -50,6 +50,7 @@ public class WiredEffectMatchFurni extends InteractionWiredEffect implements Int
@Override @Override
public void execute(WiredContext ctx) { public void execute(WiredContext ctx) {
Room room = ctx.room(); Room room = ctx.room();
this.refresh();
if(this.settings.isEmpty()) if(this.settings.isEmpty())
return; return;
@@ -57,24 +58,53 @@ public class WiredEffectMatchFurni extends InteractionWiredEffect implements Int
if (room.getLayout() == null) if (room.getLayout() == null)
return; return;
java.util.Set<Integer> allowedItemIds = null; if (this.furniSource == WiredSourceUtil.SOURCE_SELECTED) {
if (this.furniSource != WiredSourceUtil.SOURCE_SELECTED) {
allowedItemIds = new java.util.HashSet<>();
for (HabboItem si : WiredSourceUtil.resolveItems(ctx, this.furniSource, null)) {
if (si != null) {
allowedItemIds.add(si.getId());
}
}
if (allowedItemIds.isEmpty()) {
return;
}
}
for (WiredMatchFurniSetting setting : this.settings) { for (WiredMatchFurniSetting setting : this.settings) {
if (allowedItemIds != null && !allowedItemIds.contains(setting.item_id)) continue;
HabboItem item = room.getHabboItem(setting.item_id); HabboItem item = room.getHabboItem(setting.item_id);
if (item != null) { if (item != null) {
this.applySetting(room, item, setting);
}
}
return;
}
List<HabboItem> targets = WiredSourceUtil.resolveItems(ctx, this.furniSource, null);
if (targets.isEmpty()) {
return;
}
for (HabboItem item : targets) {
if (item == null) continue;
WiredMatchFurniSetting setting = this.resolveSettingForTarget(room, item);
if (setting == null) continue;
this.applySetting(room, item, setting);
}
}
private WiredMatchFurniSetting resolveSettingForTarget(Room room, HabboItem target) {
WiredMatchFurniSetting fallback = null;
for (WiredMatchFurniSetting setting : this.settings) {
HabboItem sourceItem = room.getHabboItem(setting.item_id);
if (sourceItem == null) continue;
if (sourceItem.getBaseItem().getId() != target.getBaseItem().getId()) continue;
if (setting.state.equals(target.getExtradata())) {
return setting;
}
if (fallback == null) {
fallback = setting;
}
}
return fallback;
}
private void applySetting(Room room, HabboItem item, WiredMatchFurniSetting setting) {
if (this.state && (this.checkForWiredResetPermission && item.allowWiredResetState())) { if (this.state && (this.checkForWiredResetPermission && item.allowWiredResetState())) {
if (!setting.state.equals(" ") && !item.getExtradata().equals(setting.state)) { if (!setting.state.equals(" ") && !item.getExtradata().equals(setting.state)) {
item.setExtradata(setting.state); item.setExtradata(setting.state);
@@ -83,7 +113,7 @@ public class WiredEffectMatchFurni extends InteractionWiredEffect implements Int
} }
RoomTile oldLocation = room.getLayout().getTile(item.getX(), item.getY()); RoomTile oldLocation = room.getLayout().getTile(item.getX(), item.getY());
if (oldLocation == null) continue; if (oldLocation == null) return;
double oldZ = item.getZ(); double oldZ = item.getZ();
if(this.direction && !this.position) { if(this.direction && !this.position) {
@@ -104,9 +134,6 @@ public class WiredEffectMatchFurni extends InteractionWiredEffect implements Int
} }
} }
} }
}
}
} }
@Deprecated @Deprecated
@@ -134,9 +161,6 @@ public class WiredEffectMatchFurni extends InteractionWiredEffect implements Int
this.settings.clear(); this.settings.clear();
this.settings.addAll(data.items); this.settings.addAll(data.items);
this.furniSource = data.furniSource; this.furniSource = data.furniSource;
if (this.furniSource == WiredSourceUtil.SOURCE_TRIGGER && !this.settings.isEmpty()) {
this.furniSource = WiredSourceUtil.SOURCE_SELECTED;
}
} }
else { else {
String[] data = set.getString("wired_data").split(":"); String[] data = set.getString("wired_data").split(":");
@@ -221,14 +245,14 @@ public class WiredEffectMatchFurni extends InteractionWiredEffect implements Int
if (room == null) if (room == null)
throw new WiredSaveException("Trying to save wired in unloaded room"); throw new WiredSaveException("Trying to save wired in unloaded room");
List<WiredMatchFurniSetting> newSettings = new ArrayList<>();
if (this.furniSource == WiredSourceUtil.SOURCE_SELECTED) {
int itemsCount = settings.getFurniIds().length; int itemsCount = settings.getFurniIds().length;
if(itemsCount > Emulator.getConfig().getInt("hotel.wired.furni.selection.count")) { if(itemsCount > Emulator.getConfig().getInt("hotel.wired.furni.selection.count")) {
throw new WiredSaveException("Too many furni selected"); throw new WiredSaveException("Too many furni selected");
} }
List<WiredMatchFurniSetting> newSettings = new ArrayList<>();
for (int i = 0; i < itemsCount; i++) { for (int i = 0; i < itemsCount; i++) {
int itemId = settings.getFurniIds()[i]; int itemId = settings.getFurniIds()[i];
HabboItem it = room.getHabboItem(itemId); HabboItem it = room.getHabboItem(itemId);
@@ -238,7 +262,6 @@ public class WiredEffectMatchFurni extends InteractionWiredEffect implements Int
newSettings.add(new WiredMatchFurniSetting(it.getId(), this.checkForWiredResetPermission && it.allowWiredResetState() ? it.getExtradata() : " ", it.getRotation(), it.getX(), it.getY())); newSettings.add(new WiredMatchFurniSetting(it.getId(), this.checkForWiredResetPermission && it.allowWiredResetState() ? it.getExtradata() : " ", it.getRotation(), it.getX(), it.getY()));
} }
}
int delay = settings.getDelay(); int delay = settings.getDelay();
@@ -249,9 +272,7 @@ public class WiredEffectMatchFurni extends InteractionWiredEffect implements Int
this.direction = setDirection; this.direction = setDirection;
this.position = setPosition; this.position = setPosition;
this.settings.clear(); this.settings.clear();
if (this.furniSource == WiredSourceUtil.SOURCE_SELECTED) {
this.settings.addAll(newSettings); this.settings.addAll(newSettings);
}
this.setDelay(delay); this.setDelay(delay);
return true; return true;
@@ -24,6 +24,7 @@ import org.slf4j.LoggerFactory;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.*; import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@@ -36,14 +37,16 @@ public class WiredEffectSendSignal extends InteractionWiredEffect {
private static final int ANTENNA_PICKED = 0; private static final int ANTENNA_PICKED = 0;
private static final int ANTENNA_TRIGGER = 1; private static final int ANTENNA_TRIGGER = 1;
private static final String ANTENNA_INTERACTION = "antenna";
private static final int FORWARD_NONE = 0; private static final String FORWARD_ITEM_SPLIT_REGEX = "[;,\\t]";
private static final int FORWARD_TRIGGER = 1; private static final long ANTENNA_PULSE_MS = 300L;
private static final ConcurrentHashMap<Integer, Long> ANTENNA_PULSE_TOKENS = new ConcurrentHashMap<>();
private THashSet<HabboItem> items; private THashSet<HabboItem> items;
private THashSet<HabboItem> forwardItems;
private int antennaSource = ANTENNA_PICKED; private int antennaSource = ANTENNA_PICKED;
private int furniForward = FORWARD_NONE; private int furniForward = WiredSourceUtil.SOURCE_TRIGGER;
private int userForward = FORWARD_NONE; private int userForward = WiredSourceUtil.SOURCE_TRIGGER;
private boolean signalPerFurni = false; private boolean signalPerFurni = false;
private boolean signalPerUser = false; private boolean signalPerUser = false;
private int channel = 0; private int channel = 0;
@@ -51,11 +54,13 @@ public class WiredEffectSendSignal extends InteractionWiredEffect {
public WiredEffectSendSignal(ResultSet set, Item baseItem) throws SQLException { public WiredEffectSendSignal(ResultSet set, Item baseItem) throws SQLException {
super(set, baseItem); super(set, baseItem);
this.items = new THashSet<>(); this.items = new THashSet<>();
this.forwardItems = new THashSet<>();
} }
public WiredEffectSendSignal(int id, int userId, Item item, String extradata, int limitedStack, int limitedSells) { public WiredEffectSendSignal(int id, int userId, Item item, String extradata, int limitedStack, int limitedSells) {
super(id, userId, item, extradata, limitedStack, limitedSells); super(id, userId, item, extradata, limitedStack, limitedSells);
this.items = new THashSet<>(); this.items = new THashSet<>();
this.forwardItems = new THashSet<>();
} }
@Override @Override
@@ -77,73 +82,68 @@ public class WiredEffectSendSignal extends InteractionWiredEffect {
.map(Collections::<HabboItem>singleton) .map(Collections::<HabboItem>singleton)
.orElse(Collections.emptySet()); .orElse(Collections.emptySet());
} else { } else {
antennas = ctx.targets().isItemsModifiedBySelector() Collection<HabboItem> baseAntennas = new ArrayList<>(this.items);
? new ArrayList<>(ctx.targets().items())
: new ArrayList<>(this.items); if (baseAntennas.isEmpty() && antennaSource > ANTENNA_TRIGGER) {
HabboItem antenna = room.getHabboItem(antennaSource);
antennas = (antenna != null) ? Collections.singleton(antenna) : Collections.emptySet();
} else {
antennas = baseAntennas;
}
} }
if (antennas.isEmpty()) { List<HabboItem> resolvedAntennas = antennas.stream()
.filter(Objects::nonNull)
.filter(this::isAntennaItem)
.collect(Collectors.toList());
if (resolvedAntennas.isEmpty()) {
LOGGER.debug("[SendSignal] No antennas resolved, aborting. antennaSource={}, selectorModified={}", antennaSource, ctx.targets().isItemsModifiedBySelector()); LOGGER.debug("[SendSignal] No antennas resolved, aborting. antennaSource={}, selectorModified={}", antennaSource, ctx.targets().isItemsModifiedBySelector());
return; return;
} }
LOGGER.debug("[SendSignal] Resolved {} antenna(s), firing signals", antennas.size()); LOGGER.debug("[SendSignal] Resolved {} antenna(s), firing signals", resolvedAntennas.size());
RoomUnit forwardedUser = null; List<RoomUnit> forwardedUsers = WiredSourceUtil.resolveUsers(ctx, this.userForward);
if (userForward == FORWARD_TRIGGER) { List<HabboItem> forwardedFurni = WiredSourceUtil.resolveItems(ctx, this.furniForward, this.forwardItems);
forwardedUser = ctx.actor().orElse(null);
}
HabboItem forwardedFurni = null; RoomUnit defaultUser = forwardedUsers.isEmpty() ? null : forwardedUsers.get(0);
if (furniForward == FORWARD_TRIGGER) { HabboItem defaultFurni = forwardedFurni.isEmpty() ? null : forwardedFurni.get(0);
forwardedFurni = ctx.sourceItem().orElse(null);
}
Set<String> visitedTiles = new HashSet<>(); Collection<RoomUnit> usersToSend = (signalPerUser && !forwardedUsers.isEmpty())
List<RoomTile> antennaTiles = new ArrayList<>(); ? forwardedUsers
for (HabboItem antenna : antennas) { : Collections.singletonList(defaultUser);
if (antenna == null) continue;
String key = antenna.getX() + "," + antenna.getY(); Collection<HabboItem> furniToSend = (signalPerFurni && !forwardedFurni.isEmpty())
if (visitedTiles.add(key)) { ? forwardedFurni
RoomTile tile = room.getLayout().getTile(antenna.getX(), antenna.getY()); : Collections.singletonList(defaultFurni);
if (tile != null) {
antennaTiles.add(tile);
}
}
}
int nextDepth = currentDepth + 1; int nextDepth = currentDepth + 1;
if (signalPerFurni || signalPerUser) { for (RoomUnit user : usersToSend) {
if (signalPerFurni) { for (HabboItem sourceItem : furniToSend) {
for (RoomTile tile : antennaTiles) { for (HabboItem antenna : resolvedAntennas) {
fireSignalAtTile(room, tile, forwardedUser, forwardedFurni, nextDepth); fireSignalAtAntenna(room, antenna, user, sourceItem, nextDepth);
} }
} }
if (signalPerUser && ctx.targets().hasUsers()) {
for (RoomUnit user : ctx.targets().users()) {
for (RoomTile tile : antennaTiles) {
fireSignalAtTile(room, tile, user, forwardedFurni, nextDepth);
}
}
} else if (!signalPerFurni) {
for (RoomTile tile : antennaTiles) {
fireSignalAtTile(room, tile, forwardedUser, forwardedFurni, nextDepth);
}
}
} else {
for (RoomTile tile : antennaTiles) {
fireSignalAtTile(room, tile, forwardedUser, forwardedFurni, nextDepth);
}
} }
} }
private void fireSignalAtTile(Room room, RoomTile tile, RoomUnit actor, HabboItem sourceItem, int depth) { private void fireSignalAtAntenna(Room room, HabboItem antenna, RoomUnit actor, HabboItem sourceItem, int depth) {
LOGGER.debug("[SendSignal] fireSignalAtTile: tile={},{} depth={} channel={} actor={} sourceItem={}", tile.x, tile.y, depth, channel, actor != null ? actor.getId() : "null", sourceItem != null ? sourceItem.getId() : "null"); if (antenna == null) return;
RoomTile tile = room.getLayout().getTile(antenna.getX(), antenna.getY());
if (tile == null) return;
pulseAntenna(room, antenna);
int signalChannel = antenna.getId();
LOGGER.debug("[SendSignal] fireSignalAtAntenna: antennaId={} tile={},{} depth={} channel={} actor={} sourceItem={}",
signalChannel, tile.x, tile.y, depth, signalChannel, actor != null ? actor.getId() : "null", sourceItem != null ? sourceItem.getId() : "null");
WiredEvent.Builder builder = WiredEvent.builder(WiredEvent.Type.SIGNAL_RECEIVED, room) WiredEvent.Builder builder = WiredEvent.builder(WiredEvent.Type.SIGNAL_RECEIVED, room)
.tile(tile) .tile(tile)
.callStackDepth(depth) .callStackDepth(depth)
.signalChannel(this.channel) .signalChannel(signalChannel)
.triggeredByEffect(true); .triggeredByEffect(true);
if (actor != null) builder.actor(actor); if (actor != null) builder.actor(actor);
@@ -153,6 +153,33 @@ public class WiredEffectSendSignal extends InteractionWiredEffect {
LOGGER.debug("[SendSignal] handleEvent returned: {}", result); LOGGER.debug("[SendSignal] handleEvent returned: {}", result);
} }
private void pulseAntenna(Room room, HabboItem antenna) {
if (room == null || antenna == null || antenna.getBaseItem() == null) return;
if (antenna.getBaseItem().getStateCount() <= 1) return;
final long token = System.currentTimeMillis();
ANTENNA_PULSE_TOKENS.put(antenna.getId(), token);
if ("1".equals(antenna.getExtradata())) {
antenna.setExtradata("0");
room.updateItemState(antenna);
}
antenna.setExtradata("1");
room.updateItemState(antenna);
Emulator.getThreading().run(() -> {
if (!room.isLoaded()) return;
Long currentToken = ANTENNA_PULSE_TOKENS.get(antenna.getId());
if (currentToken == null || currentToken.longValue() != token) return;
antenna.setExtradata("0");
room.updateItemState(antenna);
ANTENNA_PULSE_TOKENS.remove(antenna.getId(), token);
}, ANTENNA_PULSE_MS);
}
@Override @Override
public void serializeWiredData(ServerMessage message, Room room) { public void serializeWiredData(ServerMessage message, Room room) {
List<HabboItem> itemsSnapshot = new ArrayList<>(this.items); List<HabboItem> itemsSnapshot = new ArrayList<>(this.items);
@@ -161,6 +188,16 @@ public class WiredEffectSendSignal extends InteractionWiredEffect {
item.getRoomId() != this.getRoomId() || room.getHabboItem(item.getId()) == null); item.getRoomId() != this.getRoomId() || room.getHabboItem(item.getId()) == null);
this.items.retainAll(itemsSnapshot); this.items.retainAll(itemsSnapshot);
List<HabboItem> forwardSnapshot = new ArrayList<>(this.forwardItems);
forwardSnapshot.removeIf(item ->
item.getRoomId() != this.getRoomId() || room.getHabboItem(item.getId()) == null);
this.forwardItems.retainAll(forwardSnapshot);
String forwardString = forwardSnapshot.stream()
.filter(Objects::nonNull)
.map(item -> Integer.toString(item.getId()))
.collect(Collectors.joining(";"));
message.appendBoolean(false); message.appendBoolean(false);
message.appendInt(WiredManager.MAXIMUM_FURNI_SELECTION); message.appendInt(WiredManager.MAXIMUM_FURNI_SELECTION);
message.appendInt(itemsSnapshot.size()); message.appendInt(itemsSnapshot.size());
@@ -169,7 +206,7 @@ public class WiredEffectSendSignal extends InteractionWiredEffect {
} }
message.appendInt(this.getBaseItem().getSpriteId()); message.appendInt(this.getBaseItem().getSpriteId());
message.appendInt(this.getId()); message.appendInt(this.getId());
message.appendString(""); message.appendString(forwardString);
message.appendInt(6); message.appendInt(6);
message.appendInt(antennaSource); message.appendInt(antennaSource);
@@ -219,6 +256,12 @@ public class WiredEffectSendSignal extends InteractionWiredEffect {
newItems.add(it); newItems.add(it);
} }
for (HabboItem receiver : newItems) {
if (!isAntennaItem(receiver)) {
throw new WiredSaveException("Only antenna furni can be selected");
}
}
if (room != null && room.getRoomSpecialTypes() != null) { if (room != null && room.getRoomSpecialTypes() != null) {
for (HabboItem receiver : newItems) { for (HabboItem receiver : newItems) {
int count = room.getRoomSpecialTypes().countSendersTargetingReceiver(receiver.getId(), this); int count = room.getRoomSpecialTypes().countSendersTargetingReceiver(receiver.getId(), this);
@@ -234,18 +277,36 @@ public class WiredEffectSendSignal extends InteractionWiredEffect {
} }
int[] params = settings.getIntParams(); int[] params = settings.getIntParams();
this.antennaSource = params.length > 0 ? params[0] : ANTENNA_PICKED; int requestedAntennaSource = params.length > 0 ? params[0] : ANTENNA_PICKED;
this.furniForward = params.length > 1 ? params[1] : FORWARD_NONE; this.furniForward = normalizeSource(params.length > 1 ? params[1] : WiredSourceUtil.SOURCE_TRIGGER);
this.userForward = params.length > 2 ? params[2] : FORWARD_NONE; this.userForward = normalizeSource(params.length > 2 ? params[2] : WiredSourceUtil.SOURCE_TRIGGER);
this.signalPerFurni = params.length > 3 && params[3] == 1; this.signalPerFurni = params.length > 3 && params[3] == 1;
this.signalPerUser = params.length > 4 && params[4] == 1; this.signalPerUser = params.length > 4 && params[4] == 1;
this.channel = params.length > 5 ? params[5] : 0; this.channel = params.length > 5 ? params[5] : 0;
this.antennaSource = requestedAntennaSource;
if (!newItems.isEmpty()) {
this.antennaSource = newItems.get(0).getId();
}
List<HabboItem> newForwardItems = new ArrayList<>();
if (this.furniForward == WiredSourceUtil.SOURCE_SELECTED && room != null) {
newForwardItems = parseForwardItems(settings.getStringParam(), room);
}
if (newForwardItems.size() > Emulator.getConfig().getInt("hotel.wired.furni.selection.count")) {
throw new WiredSaveException("Too many furni selected");
}
this.items.clear(); this.items.clear();
this.items.addAll(newItems); this.items.addAll(newItems);
this.forwardItems.clear();
if (this.furniForward == WiredSourceUtil.SOURCE_SELECTED) {
this.forwardItems.addAll(newForwardItems);
}
this.setDelay(delay); this.setDelay(delay);
LOGGER.debug("[SendSignal] saveData: antennaSource={}, furniForward={}, userForward={}, signalPerFurni={}, signalPerUser={}, channel={}, items={}", LOGGER.debug("[SendSignal] saveData: antennaSource={}, furniForward={}, userForward={}, signalPerFurni={}, signalPerUser={}, channel={}, items={}, forwardItems={}",
antennaSource, furniForward, userForward, signalPerFurni, signalPerUser, channel, items.size()); antennaSource, furniForward, userForward, signalPerFurni, signalPerUser, channel, items.size(), forwardItems.size());
return true; return true;
} }
@@ -259,9 +320,11 @@ public class WiredEffectSendSignal extends InteractionWiredEffect {
@Override @Override
public String getWiredData() { public String getWiredData() {
List<HabboItem> itemsSnapshot = new ArrayList<>(this.items); List<HabboItem> itemsSnapshot = new ArrayList<>(this.items);
List<HabboItem> forwardSnapshot = new ArrayList<>(this.forwardItems);
return WiredManager.getGson().toJson(new JsonData( return WiredManager.getGson().toJson(new JsonData(
this.getDelay(), this.getDelay(),
itemsSnapshot.stream().map(HabboItem::getId).collect(Collectors.toList()), itemsSnapshot.stream().map(HabboItem::getId).collect(Collectors.toList()),
forwardSnapshot.stream().map(HabboItem::getId).collect(Collectors.toList()),
antennaSource, furniForward, userForward, signalPerFurni, signalPerUser, channel antennaSource, furniForward, userForward, signalPerFurni, signalPerUser, channel
)); ));
} }
@@ -269,14 +332,15 @@ public class WiredEffectSendSignal extends InteractionWiredEffect {
@Override @Override
public void loadWiredData(ResultSet set, Room room) throws SQLException { public void loadWiredData(ResultSet set, Room room) throws SQLException {
this.items = new THashSet<>(); this.items = new THashSet<>();
this.forwardItems = new THashSet<>();
String wiredData = set.getString("wired_data"); String wiredData = set.getString("wired_data");
if (wiredData != null && wiredData.startsWith("{")) { if (wiredData != null && wiredData.startsWith("{")) {
JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class); JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class);
this.setDelay(data.delay); this.setDelay(data.delay);
this.antennaSource = data.antennaSource; this.antennaSource = data.antennaSource;
this.furniForward = data.furniForward; this.furniForward = normalizeSource(data.furniForward);
this.userForward = data.userForward; this.userForward = normalizeSource(data.userForward);
this.signalPerFurni = data.signalPerFurni; this.signalPerFurni = data.signalPerFurni;
this.signalPerUser = data.signalPerUser; this.signalPerUser = data.signalPerUser;
this.channel = data.channel; this.channel = data.channel;
@@ -286,21 +350,84 @@ public class WiredEffectSendSignal extends InteractionWiredEffect {
if (item != null) this.items.add(item); if (item != null) this.items.add(item);
} }
} }
if (data.forwardItemIds != null) {
for (Integer id : data.forwardItemIds) {
HabboItem item = room.getHabboItem(id);
if (item != null) this.forwardItems.add(item);
}
}
if (this.antennaSource <= ANTENNA_TRIGGER && !this.items.isEmpty()) {
HabboItem first = this.items.iterator().next();
if (first != null) this.antennaSource = first.getId();
}
} }
} }
@Override @Override
public void onPickUp() { public void onPickUp() {
this.items.clear(); this.items.clear();
this.forwardItems.clear();
this.antennaSource = ANTENNA_PICKED; this.antennaSource = ANTENNA_PICKED;
this.furniForward = FORWARD_NONE; this.furniForward = WiredSourceUtil.SOURCE_TRIGGER;
this.userForward = FORWARD_NONE; this.userForward = WiredSourceUtil.SOURCE_TRIGGER;
this.signalPerFurni = false; this.signalPerFurni = false;
this.signalPerUser = false; this.signalPerUser = false;
this.channel = 0; this.channel = 0;
this.setDelay(0); this.setDelay(0);
} }
private int normalizeSource(int source) {
if (source == 1) return WiredSourceUtil.SOURCE_TRIGGER;
if (source == WiredSourceUtil.SOURCE_TRIGGER
|| source == WiredSourceUtil.SOURCE_SELECTED
|| source == WiredSourceUtil.SOURCE_SELECTOR
|| source == WiredSourceUtil.SOURCE_SIGNAL) {
return source;
}
return WiredSourceUtil.SOURCE_TRIGGER;
}
private List<HabboItem> parseForwardItems(String data, Room room) throws WiredSaveException {
List<HabboItem> results = new ArrayList<>();
if (data == null || data.trim().isEmpty() || room == null) return results;
Set<Integer> seen = new HashSet<>();
String[] parts = data.split(FORWARD_ITEM_SPLIT_REGEX);
for (String part : parts) {
if (part == null) continue;
String trimmed = part.trim();
if (trimmed.isEmpty()) continue;
int itemId;
try {
itemId = Integer.parseInt(trimmed);
} catch (NumberFormatException e) {
continue;
}
if (itemId <= 0 || !seen.add(itemId)) continue;
HabboItem item = room.getHabboItem(itemId);
if (item == null) throw new WiredSaveException(String.format("Item %s not found", itemId));
results.add(item);
}
return results;
}
private boolean isAntennaItem(HabboItem item) {
if (item == null || item.getBaseItem() == null || item.getBaseItem().getInteractionType() == null) return false;
String interaction = item.getBaseItem().getInteractionType().getName();
if (interaction == null) return false;
String normalized = interaction.toLowerCase();
return normalized.equals(ANTENNA_INTERACTION);
}
@Override @Override
public WiredEffectType getType() { public WiredEffectType getType() {
return type; return type;
@@ -328,6 +455,7 @@ public class WiredEffectSendSignal extends InteractionWiredEffect {
static class JsonData { static class JsonData {
int delay; int delay;
List<Integer> itemIds; List<Integer> itemIds;
List<Integer> forwardItemIds;
int antennaSource; int antennaSource;
int furniForward; int furniForward;
int userForward; int userForward;
@@ -335,10 +463,11 @@ public class WiredEffectSendSignal extends InteractionWiredEffect {
boolean signalPerUser; boolean signalPerUser;
int channel; int channel;
public JsonData(int delay, List<Integer> itemIds, int antennaSource, int furniForward, public JsonData(int delay, List<Integer> itemIds, List<Integer> forwardItemIds, int antennaSource, int furniForward,
int userForward, boolean signalPerFurni, boolean signalPerUser, int channel) { int userForward, boolean signalPerFurni, boolean signalPerUser, int channel) {
this.delay = delay; this.delay = delay;
this.itemIds = itemIds; this.itemIds = itemIds;
this.forwardItemIds = forwardItemIds;
this.antennaSource = antennaSource; this.antennaSource = antennaSource;
this.furniForward = furniForward; this.furniForward = furniForward;
this.userForward = userForward; this.userForward = userForward;
@@ -112,17 +112,17 @@ public class WiredEffectFurniByType extends InteractionWiredEffect {
@Override @Override
public boolean saveData(WiredSettings settings, GameClient gameClient) throws WiredSaveException { public boolean saveData(WiredSettings settings, GameClient gameClient) throws WiredSaveException {
int[] params = settings.getIntParams(); int[] params = settings.getIntParams();
if (params == null || params.length < 1) { if (params == null || params.length < 4) {
throw new WiredSaveException("wf_slc_furni_bytype: intParams must have at least 1 element"); throw new WiredSaveException("wf_slc_furni_bytype: intParams must have at least 4 elements");
} }
this.sourceType = params[0]; this.sourceType = SOURCE_FURNI_PICKED;
this.matchState = params.length > 1 && params[1] == 1; this.matchState = params.length > 1 && params[1] == 1;
this.filterExisting = params.length > 2 && params[2] == 1; this.filterExisting = params.length > 2 && params[2] == 1;
this.invert = params.length > 3 && params[3] == 1; this.invert = params.length > 3 && params[3] == 1;
this.pickedFurniIds = new ArrayList<>(); this.pickedFurniIds = new ArrayList<>();
if (this.sourceType == SOURCE_FURNI_PICKED && settings.getFurniIds() != null) { if (settings.getFurniIds() != null) {
for (int id : settings.getFurniIds()) { for (int id : settings.getFurniIds()) {
if (pickedFurniIds.size() >= MAX_PICKED_FURNI) break; if (pickedFurniIds.size() >= MAX_PICKED_FURNI) break;
pickedFurniIds.add(id); pickedFurniIds.add(id);
@@ -135,12 +135,10 @@ public class WiredEffectFurniByType extends InteractionWiredEffect {
@Override @Override
public void serializeWiredData(ServerMessage message, Room room) { public void serializeWiredData(ServerMessage message, Room room) {
boolean pickMode = (sourceType == SOURCE_FURNI_PICKED); message.appendBoolean(true);
message.appendInt(MAX_PICKED_FURNI);
message.appendBoolean(pickMode); if (!pickedFurniIds.isEmpty()) {
message.appendInt(pickMode ? MAX_PICKED_FURNI : 0);
if (pickMode && !pickedFurniIds.isEmpty()) {
message.appendInt(pickedFurniIds.size()); message.appendInt(pickedFurniIds.size());
pickedFurniIds.forEach(message::appendInt); pickedFurniIds.forEach(message::appendInt);
} else { } else {
@@ -152,7 +150,7 @@ public class WiredEffectFurniByType extends InteractionWiredEffect {
message.appendString(""); message.appendString("");
message.appendInt(4); message.appendInt(4);
message.appendInt(sourceType); message.appendInt(SOURCE_FURNI_PICKED);
message.appendInt(matchState ? 1 : 0); message.appendInt(matchState ? 1 : 0);
message.appendInt(filterExisting ? 1 : 0); message.appendInt(filterExisting ? 1 : 0);
message.appendInt(invert ? 1 : 0); message.appendInt(invert ? 1 : 0);
@@ -1,5 +1,6 @@
package com.eu.habbo.habbohotel.items.interactions.wired.triggers; package com.eu.habbo.habbohotel.items.interactions.wired.triggers;
import com.eu.habbo.Emulator;
import com.eu.habbo.habbohotel.items.Item; import com.eu.habbo.habbohotel.items.Item;
import com.eu.habbo.habbohotel.items.interactions.InteractionWiredTrigger; import com.eu.habbo.habbohotel.items.interactions.InteractionWiredTrigger;
import com.eu.habbo.habbohotel.items.interactions.wired.WiredSettings; import com.eu.habbo.habbohotel.items.interactions.wired.WiredSettings;
@@ -11,27 +12,49 @@ import com.eu.habbo.habbohotel.wired.WiredTriggerType;
import com.eu.habbo.habbohotel.wired.core.WiredEvent; import com.eu.habbo.habbohotel.wired.core.WiredEvent;
import com.eu.habbo.habbohotel.wired.core.WiredManager; import com.eu.habbo.habbohotel.wired.core.WiredManager;
import com.eu.habbo.messages.ServerMessage; import com.eu.habbo.messages.ServerMessage;
import com.eu.habbo.messages.incoming.wired.WiredTriggerSaveException;
import com.eu.habbo.messages.outgoing.rooms.items.ItemStateComposer;
import gnu.trove.set.hash.THashSet;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Collectors;
public class WiredTriggerReceiveSignal extends InteractionWiredTrigger { public class WiredTriggerReceiveSignal extends InteractionWiredTrigger {
public static final WiredTriggerType type = WiredTriggerType.RECEIVE_SIGNAL; public static final WiredTriggerType type = WiredTriggerType.RECEIVE_SIGNAL;
private static final String ANTENNA_INTERACTION = "antenna";
private static final long ACTIVATION_PULSE_MS = 300L;
private int channel = 0; // signal channel (0-based) private int channel = 0; // signal channel (0-based)
private THashSet<HabboItem> items;
private final AtomicLong activationToken = new AtomicLong();
public WiredTriggerReceiveSignal(ResultSet set, Item baseItem) throws SQLException { public WiredTriggerReceiveSignal(ResultSet set, Item baseItem) throws SQLException {
super(set, baseItem); super(set, baseItem);
this.items = new THashSet<>();
} }
public WiredTriggerReceiveSignal(int id, int userId, Item item, String extradata, int limitedStack, int limitedSells) { public WiredTriggerReceiveSignal(int id, int userId, Item item, String extradata, int limitedStack, int limitedSells) {
super(id, userId, item, extradata, limitedStack, limitedSells); super(id, userId, item, extradata, limitedStack, limitedSells);
this.items = new THashSet<>();
} }
@Override @Override
public boolean matches(HabboItem triggerItem, WiredEvent event) { public boolean matches(HabboItem triggerItem, WiredEvent event) {
return event.getType() == WiredEvent.Type.SIGNAL_RECEIVED if (event.getType() != WiredEvent.Type.SIGNAL_RECEIVED) return false;
&& event.getSignalChannel() == this.channel;
if (!this.items.isEmpty()) {
int signalChannel = event.getSignalChannel();
for (HabboItem antenna : this.items) {
if (antenna != null && antenna.getId() == signalChannel) return true;
}
return false;
}
return event.getSignalChannel() == this.channel;
} }
public int getChannel() { public int getChannel() {
@@ -59,14 +82,33 @@ public class WiredTriggerReceiveSignal extends InteractionWiredTrigger {
int senderCount = 0; int senderCount = 0;
try { try {
if (room != null && room.getRoomSpecialTypes() != null) { if (room != null && room.getRoomSpecialTypes() != null) {
if (!this.items.isEmpty()) {
for (HabboItem item : this.items) {
senderCount += room.getRoomSpecialTypes().countSendersTargetingReceiver(item.getId());
}
} else {
senderCount = room.getRoomSpecialTypes().countSendersTargetingReceiver(this.getId()); senderCount = room.getRoomSpecialTypes().countSendersTargetingReceiver(this.getId());
} }
}
} catch (Exception e) { } catch (Exception e) {
} }
THashSet<HabboItem> itemsToRemove = new THashSet<>();
for (HabboItem item : this.items) {
if (item.getRoomId() != this.getRoomId() || room.getHabboItem(item.getId()) == null) {
itemsToRemove.add(item);
}
}
for (HabboItem item : itemsToRemove) {
this.items.remove(item);
}
message.appendBoolean(false); message.appendBoolean(false);
message.appendInt(0); message.appendInt(WiredManager.MAXIMUM_FURNI_SELECTION);
message.appendInt(0); message.appendInt(this.items.size());
for (HabboItem item : this.items) {
message.appendInt(item.getId());
}
message.appendInt(this.getBaseItem().getSpriteId()); message.appendInt(this.getBaseItem().getSpriteId());
message.appendInt(this.getId()); message.appendInt(this.getId());
message.appendString(""); message.appendString("");
@@ -82,37 +124,100 @@ public class WiredTriggerReceiveSignal extends InteractionWiredTrigger {
@Override @Override
public boolean saveData(WiredSettings settings) { public boolean saveData(WiredSettings settings) {
this.items.clear();
Room room = Emulator.getGameEnvironment().getRoomManager().getRoom(this.getRoomId());
int count = settings.getFurniIds().length;
for (int i = 0; i < count; i++) {
HabboItem item = room.getHabboItem(settings.getFurniIds()[i]);
if (item == null) continue;
if (!isAntennaItem(item)) throw new WiredTriggerSaveException("wiredfurni.error.require_antenna_furni");
this.items.add(item);
}
int[] params = settings.getIntParams(); int[] params = settings.getIntParams();
this.channel = params.length > 0 ? params[0] : 0; this.channel = params.length > 0 ? params[0] : 0;
return true; return true;
} }
@Override
public void activateBox(Room room, RoomUnit roomUnit, long millis) {
if (roomUnit != null) {
this.addUserExecutionCache(roomUnit.getId(), millis);
}
if (room == null || room.isHideWired() || this.getBaseItem().getStateCount() <= 1) {
return;
}
final long token = this.activationToken.incrementAndGet();
if ("1".equals(this.getExtradata())) {
this.setExtradata("0");
room.sendComposer(new ItemStateComposer(this).compose());
}
this.setExtradata("1");
room.sendComposer(new ItemStateComposer(this).compose());
Emulator.getThreading().run(() -> {
if (!room.isLoaded()) return;
if (this.activationToken.get() != token) return;
this.setExtradata("0");
room.sendComposer(new ItemStateComposer(this).compose());
}, ACTIVATION_PULSE_MS);
}
@Override @Override
public String getWiredData() { public String getWiredData() {
return WiredManager.getGson().toJson(new JsonData(channel)); return WiredManager.getGson().toJson(new JsonData(
channel,
this.items.stream().map(HabboItem::getId).collect(Collectors.toList())
));
} }
@Override @Override
public void loadWiredData(ResultSet set, Room room) throws SQLException { public void loadWiredData(ResultSet set, Room room) throws SQLException {
this.items = new THashSet<>();
String wiredData = set.getString("wired_data"); String wiredData = set.getString("wired_data");
if (wiredData != null && wiredData.startsWith("{")) { if (wiredData != null && wiredData.startsWith("{")) {
JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class); JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class);
this.channel = data.channel; this.channel = data.channel;
if (data.itemIds != null) {
for (Integer id : data.itemIds) {
HabboItem item = room.getHabboItem(id);
if (item != null) this.items.add(item);
}
}
} }
} }
@Override @Override
public void onPickUp() { public void onPickUp() {
this.channel = 0; this.channel = 0;
this.items.clear();
}
private boolean isAntennaItem(HabboItem item) {
if (item == null || item.getBaseItem() == null || item.getBaseItem().getInteractionType() == null) return false;
String interaction = item.getBaseItem().getInteractionType().getName();
if (interaction == null) return false;
String normalized = interaction.toLowerCase();
return normalized.equals(ANTENNA_INTERACTION);
} }
static class JsonData { static class JsonData {
int channel; int channel;
List<Integer> itemIds;
public JsonData() {} public JsonData() {}
public JsonData(int channel) { public JsonData(int channel, List<Integer> itemIds) {
this.channel = channel; this.channel = channel;
this.itemIds = itemIds;
} }
} }
} }
@@ -214,24 +214,16 @@ public final class WiredEngine {
// Initial step for trigger // Initial step for trigger
state.step(); state.step();
// Activate the trigger box animation
if (stack.triggerItem() instanceof InteractionWiredTrigger) {
InteractionWiredTrigger trigger = (InteractionWiredTrigger) stack.triggerItem();
trigger.activateBox(room, event.getActor().orElse(null), currentTime);
}
debug(room, "Trigger matched: {} at item {} (conditions: {}, effects: {})", debug(room, "Trigger matched: {} at item {} (conditions: {}, effects: {})",
event.getType(), event.getType(),
stack.triggerItem() != null ? stack.triggerItem().getId() : "null", stack.triggerItem() != null ? stack.triggerItem().getId() : "null",
stack.conditions().size(), stack.conditions().size(),
stack.effects().size()); stack.effects().size());
// Activate extras (for their animation)
activateExtras(room, stack.triggerItem(), event.getActor().orElse(null), currentTime);
// Run selectors before conditions so targets are available // Run selectors before conditions so targets are available
List<InteractionWiredEffect> executedSelectors = Collections.emptyList();
if (stack.hasEffects()) { if (stack.hasEffects()) {
executeSelectors(stack, ctx, currentTime); executedSelectors = executeSelectors(stack, ctx);
} }
// Evaluate conditions // Evaluate conditions
@@ -253,6 +245,17 @@ public final class WiredEngine {
return false; return false;
} }
RoomUnit actor = event.getActor().orElse(null);
// Only show the trigger/selector activation when the stack is actually allowed to continue.
if (stack.triggerItem() instanceof InteractionWiredTrigger) {
InteractionWiredTrigger trigger = (InteractionWiredTrigger) stack.triggerItem();
trigger.activateBox(room, actor, currentTime);
}
activateExtras(room, stack.triggerItem(), actor, currentTime);
finalizeSelectors(executedSelectors, ctx, currentTime);
// Execute effects // Execute effects
if (stack.hasEffects()) { if (stack.hasEffects()) {
executeEffects(stack, ctx, currentTime); executeEffects(stack, ctx, currentTime);
@@ -420,9 +423,11 @@ public final class WiredEngine {
/** /**
* Execute selector effects before conditions so ctx.targets() is populated. * Execute selector effects before conditions so ctx.targets() is populated.
*/ */
private void executeSelectors(WiredStack stack, WiredContext ctx, long currentTime) { private List<InteractionWiredEffect> executeSelectors(WiredStack stack, WiredContext ctx) {
List<IWiredEffect> effects = stack.effects(); List<IWiredEffect> effects = stack.effects();
if (effects.isEmpty()) return; if (effects.isEmpty()) return Collections.emptyList();
List<InteractionWiredEffect> executedSelectors = new ArrayList<>();
for (IWiredEffect effect : effects) { for (IWiredEffect effect : effects) {
if (!effect.isSelector()) continue; if (!effect.isSelector()) continue;
@@ -433,16 +438,29 @@ public final class WiredEngine {
ctx.state().step(); ctx.state().step();
try { try {
effect.execute(ctx); effect.execute(ctx);
if (effect instanceof InteractionWiredEffect) { if (effect instanceof InteractionWiredEffect) {
InteractionWiredEffect wiredEffect = (InteractionWiredEffect) effect; executedSelectors.add((InteractionWiredEffect) effect);
wiredEffect.setCooldown(currentTime);
wiredEffect.activateBox(ctx.room(), ctx.actor().orElse(null), currentTime);
} }
} catch (Exception e) { } catch (Exception e) {
LOGGER.warn("Error executing selector: {}", e.getMessage()); LOGGER.warn("Error executing selector: {}", e.getMessage());
} }
} }
return executedSelectors;
}
private void finalizeSelectors(List<InteractionWiredEffect> executedSelectors, WiredContext ctx, long currentTime) {
if (executedSelectors == null || executedSelectors.isEmpty()) {
return;
}
Room room = ctx.room();
RoomUnit actor = ctx.actor().orElse(null);
for (InteractionWiredEffect wiredEffect : executedSelectors) {
wiredEffect.setCooldown(currentTime);
wiredEffect.activateBox(room, actor, currentTime);
}
} }
/** /**
@@ -34,6 +34,7 @@ public class WiredTriggerSaveDataEvent extends MessageHandler {
if (saveMethod.get().getParameterTypes()[0] == WiredSettings.class) { if (saveMethod.get().getParameterTypes()[0] == WiredSettings.class) {
WiredSettings settings = InteractionWired.readSettings(this.packet, false); WiredSettings settings = InteractionWired.readSettings(this.packet, false);
try {
if (trigger.saveData(settings)) { if (trigger.saveData(settings)) {
this.client.sendResponse(new WiredSavedComposer()); this.client.sendResponse(new WiredSavedComposer());
@@ -46,6 +47,9 @@ public class WiredTriggerSaveDataEvent extends MessageHandler {
} else { } else {
this.client.sendResponse(new UpdateFailedComposer("There was an error while saving that trigger")); this.client.sendResponse(new UpdateFailedComposer("There was an error while saving that trigger"));
} }
} catch (WiredTriggerSaveException e) {
this.client.sendResponse(new UpdateFailedComposer(e.getMessage()));
}
} else { } else {
if ((boolean) saveMethod.get().invoke(trigger, this.packet)) { if ((boolean) saveMethod.get().invoke(trigger, this.packet)) {
this.client.sendResponse(new WiredSavedComposer()); this.client.sendResponse(new WiredSavedComposer());
@@ -0,0 +1,7 @@
package com.eu.habbo.messages.incoming.wired;
public class WiredTriggerSaveException extends RuntimeException {
public WiredTriggerSaveException(String message) {
super(message);
}
}