You've already forked Arcturus-Morningstar-Extended
mirror of
https://github.com/duckietm/Arcturus-Morningstar-Extended.git
synced 2026-06-19 15:06:19 +00:00
Merge pull request #45 from Lorenzune/feature/pr-20260325
Refine wired movement sync, extra behavior, and source handling
This commit is contained in:
Generated
+1
-1
@@ -8,5 +8,5 @@
|
|||||||
</list>
|
</list>
|
||||||
</option>
|
</option>
|
||||||
</component>
|
</component>
|
||||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_23" default="true" project-jdk-name="openjdk-23" project-jdk-type="JavaSDK" />
|
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="graalvm-jdk-21" project-jdk-type="JavaSDK" />
|
||||||
</project>
|
</project>
|
||||||
@@ -54,6 +54,8 @@ import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredExtraAnimatio
|
|||||||
import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredExtraFilterFurni;
|
import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredExtraFilterFurni;
|
||||||
import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredExtraFilterUser;
|
import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredExtraFilterUser;
|
||||||
import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredExtraMoveCarryUsers;
|
import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredExtraMoveCarryUsers;
|
||||||
|
import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredExtraExecuteInOrder;
|
||||||
|
import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredExtraExecutionLimit;
|
||||||
import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredExtraMovePhysics;
|
import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredExtraMovePhysics;
|
||||||
import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredExtraMoveNoAnimation;
|
import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredExtraMoveNoAnimation;
|
||||||
import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredExtraOrEval;
|
import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredExtraOrEval;
|
||||||
@@ -349,6 +351,8 @@ public class ItemManager {
|
|||||||
this.interactionsList.add(new ItemInteraction("wf_xtra_mov_no_animation", WiredExtraMoveNoAnimation.class));
|
this.interactionsList.add(new ItemInteraction("wf_xtra_mov_no_animation", WiredExtraMoveNoAnimation.class));
|
||||||
this.interactionsList.add(new ItemInteraction("wf_xtra_anim_time", WiredExtraAnimationTime.class));
|
this.interactionsList.add(new ItemInteraction("wf_xtra_anim_time", WiredExtraAnimationTime.class));
|
||||||
this.interactionsList.add(new ItemInteraction("wf_xtra_mov_physics", WiredExtraMovePhysics.class));
|
this.interactionsList.add(new ItemInteraction("wf_xtra_mov_physics", WiredExtraMovePhysics.class));
|
||||||
|
this.interactionsList.add(new ItemInteraction("wf_xtra_exec_in_order", WiredExtraExecuteInOrder.class));
|
||||||
|
this.interactionsList.add(new ItemInteraction("wf_xtra_execution_limit", WiredExtraExecutionLimit.class));
|
||||||
|
|
||||||
|
|
||||||
this.interactionsList.add(new ItemInteraction("wf_highscore", InteractionWiredHighscore.class));
|
this.interactionsList.add(new ItemInteraction("wf_highscore", InteractionWiredHighscore.class));
|
||||||
|
|||||||
+1
-8
@@ -162,14 +162,7 @@ public class WiredConditionActorDir extends InteractionWiredCondition {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private int normalizeUserSource(int value) {
|
private int normalizeUserSource(int value) {
|
||||||
switch (value) {
|
return WiredSourceUtil.isDefaultUserSource(value) ? value : WiredSourceUtil.SOURCE_TRIGGER;
|
||||||
case WiredSourceUtil.SOURCE_SELECTOR:
|
|
||||||
case WiredSourceUtil.SOURCE_SIGNAL:
|
|
||||||
case WiredSourceUtil.SOURCE_TRIGGER:
|
|
||||||
return value;
|
|
||||||
default:
|
|
||||||
return WiredSourceUtil.SOURCE_TRIGGER;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private int normalizeQuantifier(int value) {
|
private int normalizeQuantifier(int value) {
|
||||||
|
|||||||
+1
-8
@@ -170,14 +170,7 @@ public class WiredConditionGroupMember extends InteractionWiredCondition {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private int normalizeUserSource(int value) {
|
private int normalizeUserSource(int value) {
|
||||||
switch (value) {
|
return WiredSourceUtil.isDefaultUserSource(value) ? value : WiredSourceUtil.SOURCE_TRIGGER;
|
||||||
case WiredSourceUtil.SOURCE_TRIGGER:
|
|
||||||
case WiredSourceUtil.SOURCE_SELECTOR:
|
|
||||||
case WiredSourceUtil.SOURCE_SIGNAL:
|
|
||||||
return value;
|
|
||||||
default:
|
|
||||||
return WiredSourceUtil.SOURCE_TRIGGER;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private int normalizeGroupType(int value) {
|
private int normalizeGroupType(int value) {
|
||||||
|
|||||||
+1
-8
@@ -170,14 +170,7 @@ public class WiredConditionNotInGroup extends InteractionWiredCondition {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private int normalizeUserSource(int value) {
|
private int normalizeUserSource(int value) {
|
||||||
switch (value) {
|
return WiredSourceUtil.isDefaultUserSource(value) ? value : WiredSourceUtil.SOURCE_TRIGGER;
|
||||||
case WiredSourceUtil.SOURCE_TRIGGER:
|
|
||||||
case WiredSourceUtil.SOURCE_SELECTOR:
|
|
||||||
case WiredSourceUtil.SOURCE_SIGNAL:
|
|
||||||
return value;
|
|
||||||
default:
|
|
||||||
return WiredSourceUtil.SOURCE_TRIGGER;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private int normalizeGroupType(int value) {
|
private int normalizeGroupType(int value) {
|
||||||
|
|||||||
+4
@@ -187,6 +187,10 @@ public class WiredConditionSelectionQuantity extends InteractionWiredCondition {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private int normalizeSourceType(int group, int value) {
|
private int normalizeSourceType(int group, int value) {
|
||||||
|
if (group == SOURCE_GROUP_USERS) {
|
||||||
|
return WiredSourceUtil.isDefaultUserSource(value) ? value : WiredSourceUtil.SOURCE_TRIGGER;
|
||||||
|
}
|
||||||
|
|
||||||
switch (value) {
|
switch (value) {
|
||||||
case WiredSourceUtil.SOURCE_SELECTOR:
|
case WiredSourceUtil.SOURCE_SELECTOR:
|
||||||
case WiredSourceUtil.SOURCE_SIGNAL:
|
case WiredSourceUtil.SOURCE_SIGNAL:
|
||||||
|
|||||||
+1
-8
@@ -84,14 +84,7 @@ abstract class WiredConditionTeamGameBase extends InteractionWiredCondition {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected int normalizeUserSource(int value) {
|
protected int normalizeUserSource(int value) {
|
||||||
switch (value) {
|
return WiredSourceUtil.isDefaultUserSource(value) ? value : WiredSourceUtil.SOURCE_TRIGGER;
|
||||||
case WiredSourceUtil.SOURCE_SELECTOR:
|
|
||||||
case WiredSourceUtil.SOURCE_SIGNAL:
|
|
||||||
case WiredSourceUtil.SOURCE_TRIGGER:
|
|
||||||
return value;
|
|
||||||
default:
|
|
||||||
return WiredSourceUtil.SOURCE_TRIGGER;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected int normalizePlacement(int value) {
|
protected int normalizePlacement(int value) {
|
||||||
|
|||||||
+3
-12
@@ -304,25 +304,16 @@ public class WiredConditionTriggererMatch extends InteractionWiredCondition {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private int normalizePrimaryUserSource(int value) {
|
private int normalizePrimaryUserSource(int value) {
|
||||||
switch (value) {
|
return WiredSourceUtil.isDefaultUserSource(value) ? value : WiredSourceUtil.SOURCE_TRIGGER;
|
||||||
case WiredSourceUtil.SOURCE_SELECTOR:
|
|
||||||
case WiredSourceUtil.SOURCE_SIGNAL:
|
|
||||||
case WiredSourceUtil.SOURCE_TRIGGER:
|
|
||||||
return value;
|
|
||||||
default:
|
|
||||||
return WiredSourceUtil.SOURCE_TRIGGER;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private int normalizeCompareUserSource(int value) {
|
private int normalizeCompareUserSource(int value) {
|
||||||
switch (value) {
|
switch (value) {
|
||||||
case WiredSourceUtil.SOURCE_SELECTOR:
|
case WiredSourceUtil.SOURCE_CLICKED_USER:
|
||||||
case WiredSourceUtil.SOURCE_SIGNAL:
|
|
||||||
case WiredSourceUtil.SOURCE_TRIGGER:
|
|
||||||
case SOURCE_SPECIFIED_USERNAME:
|
case SOURCE_SPECIFIED_USERNAME:
|
||||||
return value;
|
return value;
|
||||||
default:
|
default:
|
||||||
return WiredSourceUtil.SOURCE_TRIGGER;
|
return WiredSourceUtil.isDefaultUserSource(value) ? value : WiredSourceUtil.SOURCE_TRIGGER;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-8
@@ -185,14 +185,7 @@ public class WiredConditionUserPerformsAction extends InteractionWiredCondition
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected int normalizeUserSource(int value) {
|
protected int normalizeUserSource(int value) {
|
||||||
switch (value) {
|
return WiredSourceUtil.isDefaultUserSource(value) ? value : WiredSourceUtil.SOURCE_TRIGGER;
|
||||||
case WiredSourceUtil.SOURCE_SELECTOR:
|
|
||||||
case WiredSourceUtil.SOURCE_SIGNAL:
|
|
||||||
case WiredSourceUtil.SOURCE_TRIGGER:
|
|
||||||
return value;
|
|
||||||
default:
|
|
||||||
return WiredSourceUtil.SOURCE_TRIGGER;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected int normalizeSignId(int value) {
|
protected int normalizeSignId(int value) {
|
||||||
|
|||||||
+1
-8
@@ -213,14 +213,7 @@ public class WiredEffectBotGiveHandItem extends InteractionWiredEffect {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private int normalizeUserSource(int value) {
|
private int normalizeUserSource(int value) {
|
||||||
switch (value) {
|
return WiredSourceUtil.isDefaultUserSource(value) ? value : WiredSourceUtil.SOURCE_TRIGGER;
|
||||||
case WiredSourceUtil.SOURCE_SELECTOR:
|
|
||||||
case WiredSourceUtil.SOURCE_SIGNAL:
|
|
||||||
case WiredSourceUtil.SOURCE_TRIGGER:
|
|
||||||
return value;
|
|
||||||
default:
|
|
||||||
return WiredSourceUtil.SOURCE_TRIGGER;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private int normalizeBotSource(int value) {
|
private int normalizeBotSource(int value) {
|
||||||
|
|||||||
+92
-9
@@ -4,14 +4,22 @@ import com.eu.habbo.habbohotel.items.Item;
|
|||||||
import com.eu.habbo.habbohotel.rooms.FurnitureMovementError;
|
import com.eu.habbo.habbohotel.rooms.FurnitureMovementError;
|
||||||
import com.eu.habbo.habbohotel.rooms.Room;
|
import com.eu.habbo.habbohotel.rooms.Room;
|
||||||
import com.eu.habbo.habbohotel.rooms.RoomTile;
|
import com.eu.habbo.habbohotel.rooms.RoomTile;
|
||||||
|
import com.eu.habbo.habbohotel.rooms.RoomUnit;
|
||||||
|
import com.eu.habbo.habbohotel.rooms.RoomUnitStatus;
|
||||||
import com.eu.habbo.habbohotel.users.Habbo;
|
import com.eu.habbo.habbohotel.users.Habbo;
|
||||||
import com.eu.habbo.habbohotel.users.HabboItem;
|
import com.eu.habbo.habbohotel.users.HabboItem;
|
||||||
import com.eu.habbo.habbohotel.wired.WiredEffectType;
|
import com.eu.habbo.habbohotel.wired.WiredEffectType;
|
||||||
import com.eu.habbo.habbohotel.wired.core.WiredContext;
|
import com.eu.habbo.habbohotel.wired.core.WiredContext;
|
||||||
import com.eu.habbo.habbohotel.wired.core.WiredMoveCarryHelper;
|
import com.eu.habbo.habbohotel.wired.core.WiredMoveCarryHelper;
|
||||||
|
import com.eu.habbo.messages.outgoing.rooms.WiredMovementsComposer;
|
||||||
|
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
public class WiredEffectFurniToUser extends WiredEffectUserFurniBase {
|
public class WiredEffectFurniToUser extends WiredEffectUserFurniBase {
|
||||||
public static final WiredEffectType type = WiredEffectType.FURNI_TO_USER;
|
public static final WiredEffectType type = WiredEffectType.FURNI_TO_USER;
|
||||||
@@ -27,27 +35,102 @@ public class WiredEffectFurniToUser extends WiredEffectUserFurniBase {
|
|||||||
@Override
|
@Override
|
||||||
public void execute(WiredContext ctx) {
|
public void execute(WiredContext ctx) {
|
||||||
Room room = ctx.room();
|
Room room = ctx.room();
|
||||||
HabboItem item = this.resolveLastItem(ctx);
|
List<HabboItem> items = new ArrayList<>(this.resolveItems(ctx));
|
||||||
Habbo habbo = this.resolveLastHabbo(room, ctx);
|
Habbo habbo = this.resolveLastHabbo(room, ctx);
|
||||||
|
|
||||||
if (room == null || item == null || habbo == null || habbo.getRoomUnit() == null) {
|
if (room == null || habbo == null || habbo.getRoomUnit() == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
RoomTile targetTile = habbo.getRoomUnit().getCurrentLocation();
|
items.removeIf(item -> item == null);
|
||||||
|
|
||||||
|
if (items.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
items.sort(Comparator
|
||||||
|
.comparingDouble(HabboItem::getZ)
|
||||||
|
.thenComparingInt(HabboItem::getId));
|
||||||
|
|
||||||
|
Map<Integer, Double> followerZOverrides = new HashMap<>();
|
||||||
|
|
||||||
|
for (HabboItem item : items) {
|
||||||
|
followerZOverrides.put(item.getId(), item.getZ());
|
||||||
|
}
|
||||||
|
|
||||||
|
RoomUnit roomUnit = habbo.getRoomUnit();
|
||||||
|
boolean hasActiveMoveStatus = roomUnit.hasStatus(RoomUnitStatus.MOVE);
|
||||||
|
long moveStatusTimestamp = hasActiveMoveStatus ? roomUnit.getMoveStatusTimestamp() : 0L;
|
||||||
|
|
||||||
|
if (roomUnit.isWalking()) {
|
||||||
|
for (HabboItem item : items) {
|
||||||
|
if (item == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
WiredMoveCarryHelper.registerUserFollower(room, this, item, roomUnit, followerZOverrides.get(item.getId()), ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hasActiveMoveStatus) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RoomTile targetTile = this.resolveTargetTile(habbo);
|
||||||
if (targetTile == null) {
|
if (targetTile == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
FurnitureMovementError error = WiredMoveCarryHelper.moveFurni(room, this, item, targetTile, item.getRotation(), null, false, ctx);
|
Integer animationDurationOverride = WiredMoveCarryHelper.hasNoAnimationExtra(room, this)
|
||||||
if (error == FurnitureMovementError.NONE) {
|
? null
|
||||||
return;
|
: this.resolveFollowAnimationDuration(room, habbo, this);
|
||||||
|
int anchorType = hasActiveMoveStatus ? WiredMovementsComposer.FURNI_ANCHOR_USER : WiredMovementsComposer.FURNI_ANCHOR_NONE;
|
||||||
|
int anchorId = hasActiveMoveStatus ? roomUnit.getId() : 0;
|
||||||
|
|
||||||
|
if (hasActiveMoveStatus) {
|
||||||
|
int animationDuration = WiredMoveCarryHelper.resolveMoveStepDuration(roomUnit);
|
||||||
|
int animationElapsed = WiredMoveCarryHelper.resolveMoveStepElapsed(roomUnit);
|
||||||
|
|
||||||
|
for (HabboItem item : items) {
|
||||||
|
if (item == null || WiredMoveCarryHelper.isUserFollowerProcessed(roomUnit, item, moveStatusTimestamp)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Double targetZ = WiredMoveCarryHelper.resolveFollowerStackZ(room, item, targetTile, item.getRotation());
|
||||||
|
FurnitureMovementError error = WiredMoveCarryHelper.moveFurni(room, this, item, targetTile, item.getRotation(), targetZ, null, false, ctx, animationDuration, animationElapsed, WiredMovementsComposer.FURNI_ANCHOR_USER, roomUnit.getId());
|
||||||
|
if (error != FurnitureMovementError.NONE) {
|
||||||
|
Double fallbackZ = followerZOverrides.get(item.getId());
|
||||||
|
|
||||||
|
if (fallbackZ != null) {
|
||||||
|
error = WiredMoveCarryHelper.moveFurni(room, this, item, targetTile, item.getRotation(), fallbackZ, null, false, ctx, animationDuration, animationElapsed, WiredMovementsComposer.FURNI_ANCHOR_USER, roomUnit.getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error == FurnitureMovementError.NONE) {
|
||||||
|
WiredMoveCarryHelper.markUserFollowerProcessed(roomUnit, item, moveStatusTimestamp);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item.getBaseItem().getStateCount() > 0) {
|
for (HabboItem item : items) {
|
||||||
error = WiredMoveCarryHelper.moveFurni(room, this, item, targetTile, item.getRotation(), item.getZ(), null, false, ctx);
|
if (item == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasActiveMoveStatus && WiredMoveCarryHelper.isUserFollowerProcessed(roomUnit, item, moveStatusTimestamp)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Double targetZ = WiredMoveCarryHelper.resolveFollowerStackZ(room, item, targetTile, item.getRotation());
|
||||||
|
FurnitureMovementError error = WiredMoveCarryHelper.moveFurni(room, this, item, targetTile, item.getRotation(), targetZ, null, false, ctx, animationDurationOverride, null, anchorType, anchorId);
|
||||||
if (error == FurnitureMovementError.NONE) {
|
if (error == FurnitureMovementError.NONE) {
|
||||||
return;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Double fallbackZ = followerZOverrides.get(item.getId());
|
||||||
|
|
||||||
|
if (fallbackZ != null) {
|
||||||
|
WiredMoveCarryHelper.moveFurni(room, this, item, targetTile, item.getRotation(), fallbackZ, null, false, ctx, animationDurationOverride, null, anchorType, anchorId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+67
-1
@@ -7,15 +7,19 @@ import com.eu.habbo.habbohotel.items.interactions.InteractionWiredEffect;
|
|||||||
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;
|
||||||
import com.eu.habbo.habbohotel.rooms.Room;
|
import com.eu.habbo.habbohotel.rooms.Room;
|
||||||
|
import com.eu.habbo.habbohotel.rooms.RoomTile;
|
||||||
import com.eu.habbo.habbohotel.rooms.RoomUnit;
|
import com.eu.habbo.habbohotel.rooms.RoomUnit;
|
||||||
|
import com.eu.habbo.habbohotel.rooms.RoomUnitStatus;
|
||||||
import com.eu.habbo.habbohotel.users.Habbo;
|
import com.eu.habbo.habbohotel.users.Habbo;
|
||||||
import com.eu.habbo.habbohotel.users.HabboItem;
|
import com.eu.habbo.habbohotel.users.HabboItem;
|
||||||
import com.eu.habbo.habbohotel.wired.WiredEffectType;
|
import com.eu.habbo.habbohotel.wired.WiredEffectType;
|
||||||
import com.eu.habbo.habbohotel.wired.core.WiredContext;
|
import com.eu.habbo.habbohotel.wired.core.WiredContext;
|
||||||
import com.eu.habbo.habbohotel.wired.core.WiredManager;
|
import com.eu.habbo.habbohotel.wired.core.WiredManager;
|
||||||
|
import com.eu.habbo.habbohotel.wired.core.WiredMoveCarryHelper;
|
||||||
import com.eu.habbo.habbohotel.wired.core.WiredSourceUtil;
|
import com.eu.habbo.habbohotel.wired.core.WiredSourceUtil;
|
||||||
import com.eu.habbo.messages.ServerMessage;
|
import com.eu.habbo.messages.ServerMessage;
|
||||||
import com.eu.habbo.messages.incoming.wired.WiredSaveException;
|
import com.eu.habbo.messages.incoming.wired.WiredSaveException;
|
||||||
|
import com.eu.habbo.messages.outgoing.rooms.WiredMovementsComposer;
|
||||||
import gnu.trove.procedure.TObjectProcedure;
|
import gnu.trove.procedure.TObjectProcedure;
|
||||||
|
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
@@ -37,7 +41,7 @@ public abstract class WiredEffectUserFurniBase extends InteractionWiredEffect {
|
|||||||
super(id, userId, item, extradata, limitedStack, limitedSells);
|
super(id, userId, item, extradata, limitedStack, limitedSells);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected HabboItem resolveLastItem(WiredContext ctx) {
|
protected List<HabboItem> resolveItems(WiredContext ctx) {
|
||||||
Room room = ctx.room();
|
Room room = ctx.room();
|
||||||
List<HabboItem> effectiveItems = WiredSourceUtil.resolveItems(ctx, this.furniSource, this.items);
|
List<HabboItem> effectiveItems = WiredSourceUtil.resolveItems(ctx, this.furniSource, this.items);
|
||||||
|
|
||||||
@@ -47,6 +51,12 @@ public abstract class WiredEffectUserFurniBase extends InteractionWiredEffect {
|
|||||||
|| room.getHabboItem(item.getId()) == null);
|
|| room.getHabboItem(item.getId()) == null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return effectiveItems;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected HabboItem resolveLastItem(WiredContext ctx) {
|
||||||
|
List<HabboItem> effectiveItems = this.resolveItems(ctx);
|
||||||
|
|
||||||
if (effectiveItems.isEmpty()) {
|
if (effectiveItems.isEmpty()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -90,6 +100,62 @@ public abstract class WiredEffectUserFurniBase extends InteractionWiredEffect {
|
|||||||
return habbos;
|
return habbos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected RoomTile resolveTargetTile(Habbo habbo) {
|
||||||
|
if (habbo == null || habbo.getRoomUnit() == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
RoomUnit roomUnit = habbo.getRoomUnit();
|
||||||
|
RoomTile movingTile = this.resolveActiveMoveTile(roomUnit);
|
||||||
|
|
||||||
|
if (movingTile != null) {
|
||||||
|
return movingTile;
|
||||||
|
}
|
||||||
|
|
||||||
|
return roomUnit.getCurrentLocation();
|
||||||
|
}
|
||||||
|
|
||||||
|
private RoomTile resolveActiveMoveTile(RoomUnit roomUnit) {
|
||||||
|
if (roomUnit == null || roomUnit.getRoom() == null || roomUnit.getRoom().getLayout() == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
String moveStatus = roomUnit.getStatus(RoomUnitStatus.MOVE);
|
||||||
|
if (moveStatus != null && !moveStatus.isEmpty()) {
|
||||||
|
String[] parts = moveStatus.split(",");
|
||||||
|
if (parts.length >= 2) {
|
||||||
|
try {
|
||||||
|
return roomUnit.getRoom().getLayout().getTile(
|
||||||
|
Short.parseShort(parts[0]),
|
||||||
|
Short.parseShort(parts[1]));
|
||||||
|
} catch (NumberFormatException ignored) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Integer resolveFollowAnimationDuration(Room room, Habbo habbo, HabboItem stackItem) {
|
||||||
|
if (room == null || habbo == null || habbo.getRoomUnit() == null || stackItem == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
RoomUnit roomUnit = habbo.getRoomUnit();
|
||||||
|
if (this.resolveActiveMoveTile(roomUnit) == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
long moveStatusTimestamp = roomUnit.getMoveStatusTimestamp();
|
||||||
|
if (moveStatusTimestamp <= 0L) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
int configuredDuration = WiredMoveCarryHelper.getAnimationDuration(room, stackItem, WiredMovementsComposer.DEFAULT_DURATION);
|
||||||
|
int remainingStepDuration = (int) Math.max(50L, WiredMovementsComposer.DEFAULT_DURATION - Math.max(0L, System.currentTimeMillis() - moveStatusTimestamp));
|
||||||
|
return Math.min(configuredDuration, remainingStepDuration);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getWiredData() {
|
public String getWiredData() {
|
||||||
return WiredManager.getGson().toJson(new JsonData(
|
return WiredManager.getGson().toJson(new JsonData(
|
||||||
|
|||||||
+78
@@ -0,0 +1,78 @@
|
|||||||
|
package com.eu.habbo.habbohotel.items.interactions.wired.extra;
|
||||||
|
|
||||||
|
import com.eu.habbo.habbohotel.gameclients.GameClient;
|
||||||
|
import com.eu.habbo.habbohotel.items.Item;
|
||||||
|
import com.eu.habbo.habbohotel.items.interactions.InteractionWiredExtra;
|
||||||
|
import com.eu.habbo.habbohotel.items.interactions.wired.WiredSettings;
|
||||||
|
import com.eu.habbo.habbohotel.rooms.Room;
|
||||||
|
import com.eu.habbo.habbohotel.rooms.RoomUnit;
|
||||||
|
import com.eu.habbo.habbohotel.wired.core.WiredManager;
|
||||||
|
import com.eu.habbo.messages.ServerMessage;
|
||||||
|
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
|
||||||
|
public class WiredExtraExecuteInOrder extends InteractionWiredExtra {
|
||||||
|
public static final int CODE = 64;
|
||||||
|
|
||||||
|
public WiredExtraExecuteInOrder(ResultSet set, Item baseItem) throws SQLException {
|
||||||
|
super(set, baseItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
public WiredExtraExecuteInOrder(int id, int userId, Item item, String extradata, int limitedStack, int limitedSells) {
|
||||||
|
super(id, userId, item, extradata, limitedStack, limitedSells);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean execute(RoomUnit roomUnit, Room room, Object[] stuff) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean saveData(WiredSettings settings, GameClient gameClient) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getWiredData() {
|
||||||
|
return WiredManager.getGson().toJson(new JsonData());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void serializeWiredData(ServerMessage message, Room room) {
|
||||||
|
message.appendBoolean(false);
|
||||||
|
message.appendInt(0);
|
||||||
|
message.appendInt(0);
|
||||||
|
message.appendInt(this.getBaseItem().getSpriteId());
|
||||||
|
message.appendInt(this.getId());
|
||||||
|
message.appendString("");
|
||||||
|
message.appendInt(0);
|
||||||
|
message.appendInt(0);
|
||||||
|
message.appendInt(CODE);
|
||||||
|
message.appendInt(0);
|
||||||
|
message.appendInt(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void loadWiredData(ResultSet set, Room room) throws SQLException {
|
||||||
|
this.onPickUp();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPickUp() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onWalk(RoomUnit roomUnit, Room room, Object[] objects) throws Exception {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasConfiguration() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static class JsonData {
|
||||||
|
}
|
||||||
|
}
|
||||||
+204
@@ -0,0 +1,204 @@
|
|||||||
|
package com.eu.habbo.habbohotel.items.interactions.wired.extra;
|
||||||
|
|
||||||
|
import com.eu.habbo.habbohotel.gameclients.GameClient;
|
||||||
|
import com.eu.habbo.habbohotel.items.Item;
|
||||||
|
import com.eu.habbo.habbohotel.items.interactions.InteractionWiredExtra;
|
||||||
|
import com.eu.habbo.habbohotel.items.interactions.wired.WiredSettings;
|
||||||
|
import com.eu.habbo.habbohotel.rooms.Room;
|
||||||
|
import com.eu.habbo.habbohotel.rooms.RoomTile;
|
||||||
|
import com.eu.habbo.habbohotel.rooms.RoomUnit;
|
||||||
|
import com.eu.habbo.habbohotel.wired.core.WiredManager;
|
||||||
|
import com.eu.habbo.messages.ServerMessage;
|
||||||
|
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.ArrayDeque;
|
||||||
|
import java.util.Deque;
|
||||||
|
|
||||||
|
public class WiredExtraExecutionLimit extends InteractionWiredExtra {
|
||||||
|
public static final int CODE = 65;
|
||||||
|
public static final int MIN_EXECUTIONS = 1;
|
||||||
|
public static final int MAX_EXECUTIONS = 100;
|
||||||
|
public static final int DEFAULT_EXECUTIONS = 1;
|
||||||
|
public static final int MIN_TIME_WINDOW_MS = 1000;
|
||||||
|
public static final int MAX_TIME_WINDOW_MS = 10000;
|
||||||
|
public static final int DEFAULT_TIME_WINDOW_MS = 1000;
|
||||||
|
public static final int TIME_WINDOW_STEP_MS = 500;
|
||||||
|
|
||||||
|
private final Deque<Long> recentExecutionTimestamps = new ArrayDeque<>();
|
||||||
|
private int maxExecutions = DEFAULT_EXECUTIONS;
|
||||||
|
private int timeWindowMs = DEFAULT_TIME_WINDOW_MS;
|
||||||
|
|
||||||
|
public WiredExtraExecutionLimit(ResultSet set, Item baseItem) throws SQLException {
|
||||||
|
super(set, baseItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
public WiredExtraExecutionLimit(int id, int userId, Item item, String extradata, int limitedStack, int limitedSells) {
|
||||||
|
super(id, userId, item, extradata, limitedStack, limitedSells);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean execute(RoomUnit roomUnit, Room room, Object[] stuff) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean saveData(WiredSettings settings, GameClient gameClient) {
|
||||||
|
int[] intParams = settings.getIntParams();
|
||||||
|
int nextExecutions = (intParams.length > 0) ? intParams[0] : this.maxExecutions;
|
||||||
|
int nextTimeWindowMs = (intParams.length > 1) ? intParams[1] : this.timeWindowMs;
|
||||||
|
|
||||||
|
this.maxExecutions = normalizeExecutions(nextExecutions);
|
||||||
|
this.timeWindowMs = normalizeTimeWindowMs(nextTimeWindowMs);
|
||||||
|
clearRuntimeState();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getWiredData() {
|
||||||
|
return WiredManager.getGson().toJson(new JsonData(this.maxExecutions, this.timeWindowMs));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void serializeWiredData(ServerMessage message, Room room) {
|
||||||
|
message.appendBoolean(false);
|
||||||
|
message.appendInt(0);
|
||||||
|
message.appendInt(0);
|
||||||
|
message.appendInt(this.getBaseItem().getSpriteId());
|
||||||
|
message.appendInt(this.getId());
|
||||||
|
message.appendString("");
|
||||||
|
message.appendInt(2);
|
||||||
|
message.appendInt(this.maxExecutions);
|
||||||
|
message.appendInt(this.timeWindowMs);
|
||||||
|
message.appendInt(0);
|
||||||
|
message.appendInt(CODE);
|
||||||
|
message.appendInt(0);
|
||||||
|
message.appendInt(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@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);
|
||||||
|
|
||||||
|
if (data != null) {
|
||||||
|
this.maxExecutions = normalizeExecutions(data.maxExecutions);
|
||||||
|
this.timeWindowMs = normalizeTimeWindowMs(data.timeWindowMs);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String[] legacyData = wiredData.split(";");
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (legacyData.length > 0) {
|
||||||
|
this.maxExecutions = normalizeExecutions(Integer.parseInt(legacyData[0]));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (legacyData.length > 1) {
|
||||||
|
this.timeWindowMs = normalizeTimeWindowMs(Integer.parseInt(legacyData[1]));
|
||||||
|
}
|
||||||
|
} catch (NumberFormatException ignored) {
|
||||||
|
this.maxExecutions = DEFAULT_EXECUTIONS;
|
||||||
|
this.timeWindowMs = DEFAULT_TIME_WINDOW_MS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onPickUp() {
|
||||||
|
this.maxExecutions = DEFAULT_EXECUTIONS;
|
||||||
|
this.timeWindowMs = DEFAULT_TIME_WINDOW_MS;
|
||||||
|
clearRuntimeState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onWalk(RoomUnit roomUnit, Room room, Object[] objects) throws Exception {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onMove(Room room, RoomTile oldLocation, RoomTile newLocation) {
|
||||||
|
super.onMove(room, oldLocation, newLocation);
|
||||||
|
clearRuntimeState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasConfiguration() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean tryAcquireExecutionSlot(long timestamp) {
|
||||||
|
synchronized (this.recentExecutionTimestamps) {
|
||||||
|
pruneExpiredTimestamps(timestamp);
|
||||||
|
|
||||||
|
if (this.recentExecutionTimestamps.size() >= this.maxExecutions) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.recentExecutionTimestamps.addLast(timestamp);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean canExecuteAt(long timestamp) {
|
||||||
|
synchronized (this.recentExecutionTimestamps) {
|
||||||
|
pruneExpiredTimestamps(timestamp);
|
||||||
|
return this.recentExecutionTimestamps.size() < this.maxExecutions;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMaxExecutions() {
|
||||||
|
return this.maxExecutions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getTimeWindowMs() {
|
||||||
|
return this.timeWindowMs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clearRuntimeState() {
|
||||||
|
synchronized (this.recentExecutionTimestamps) {
|
||||||
|
this.recentExecutionTimestamps.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void pruneExpiredTimestamps(long timestamp) {
|
||||||
|
while (!this.recentExecutionTimestamps.isEmpty()
|
||||||
|
&& (timestamp - this.recentExecutionTimestamps.peekFirst()) >= this.timeWindowMs) {
|
||||||
|
this.recentExecutionTimestamps.removeFirst();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int normalizeExecutions(int value) {
|
||||||
|
return Math.max(MIN_EXECUTIONS, Math.min(MAX_EXECUTIONS, value));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int normalizeTimeWindowMs(int value) {
|
||||||
|
if (value < MIN_TIME_WINDOW_MS) {
|
||||||
|
return MIN_TIME_WINDOW_MS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value > MAX_TIME_WINDOW_MS) {
|
||||||
|
return MAX_TIME_WINDOW_MS;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Math.round(value / (float) TIME_WINDOW_STEP_MS) * TIME_WINDOW_STEP_MS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static class JsonData {
|
||||||
|
int maxExecutions;
|
||||||
|
int timeWindowMs;
|
||||||
|
|
||||||
|
JsonData(int maxExecutions, int timeWindowMs) {
|
||||||
|
this.maxExecutions = maxExecutions;
|
||||||
|
this.timeWindowMs = timeWindowMs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+12
-4
@@ -155,12 +155,20 @@ public class WiredTriggerAtSetTime extends InteractionWiredTrigger implements Wi
|
|||||||
|
|
||||||
// Check if enough time has passed
|
// Check if enough time has passed
|
||||||
if (this.accumulatedTime >= this.executeTime) {
|
if (this.accumulatedTime >= this.executeTime) {
|
||||||
|
if (this.getRoomId() != 0 && room.isLoaded()) {
|
||||||
|
long currentTime = System.currentTimeMillis();
|
||||||
|
if (!WiredManager.isTriggerExecutionAllowed(room, this, currentTime)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.hasFired = true;
|
||||||
|
this.accumulatedTime = 0;
|
||||||
|
WiredManager.triggerTimerTick(room, this);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this.hasFired = true;
|
this.hasFired = true;
|
||||||
this.accumulatedTime = 0;
|
this.accumulatedTime = 0;
|
||||||
|
|
||||||
if (this.getRoomId() != 0 && room.isLoaded()) {
|
|
||||||
WiredManager.triggerTimerTick(room, this);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+12
-4
@@ -155,12 +155,20 @@ public class WiredTriggerAtTimeLong extends InteractionWiredTrigger implements W
|
|||||||
|
|
||||||
// Check if enough time has passed
|
// Check if enough time has passed
|
||||||
if (this.accumulatedTime >= this.executeTime) {
|
if (this.accumulatedTime >= this.executeTime) {
|
||||||
|
if (this.getRoomId() != 0 && room.isLoaded()) {
|
||||||
|
long currentTime = System.currentTimeMillis();
|
||||||
|
if (!WiredManager.isTriggerExecutionAllowed(room, this, currentTime)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.hasFired = true;
|
||||||
|
this.accumulatedTime = 0;
|
||||||
|
WiredManager.triggerTimerTick(room, this);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this.hasFired = true;
|
this.hasFired = true;
|
||||||
this.accumulatedTime = 0;
|
this.accumulatedTime = 0;
|
||||||
|
|
||||||
if (this.getRoomId() != 0 && room.isLoaded()) {
|
|
||||||
WiredManager.triggerTimerTick(room, this);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
-1
@@ -144,7 +144,9 @@ public class WiredTriggerRepeater extends InteractionWiredTrigger implements Wir
|
|||||||
|
|
||||||
// Fire when elapsed time is a multiple of repeatTime
|
// Fire when elapsed time is a multiple of repeatTime
|
||||||
if (elapsedMs % this.repeatTime == 0) {
|
if (elapsedMs % this.repeatTime == 0) {
|
||||||
if (this.getRoomId() != 0 && room.isLoaded()) {
|
long currentTime = System.currentTimeMillis();
|
||||||
|
if (this.getRoomId() != 0 && room.isLoaded()
|
||||||
|
&& WiredManager.isTriggerExecutionAllowed(room, this, currentTime)) {
|
||||||
WiredManager.triggerTimerRepeat(room, this);
|
WiredManager.triggerTimerRepeat(room, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-1
@@ -138,7 +138,9 @@ public class WiredTriggerRepeaterLong extends InteractionWiredTrigger implements
|
|||||||
|
|
||||||
// Fire when elapsed time is a multiple of repeat time
|
// Fire when elapsed time is a multiple of repeat time
|
||||||
if (elapsedMs % this.repeatTime == 0) {
|
if (elapsedMs % this.repeatTime == 0) {
|
||||||
if (this.getRoomId() != 0 && room.isLoaded()) {
|
long currentTime = System.currentTimeMillis();
|
||||||
|
if (this.getRoomId() != 0 && room.isLoaded()
|
||||||
|
&& WiredManager.isTriggerExecutionAllowed(room, this, currentTime)) {
|
||||||
WiredManager.triggerTimerRepeatLong(room, this);
|
WiredManager.triggerTimerRepeatLong(room, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-1
@@ -105,7 +105,9 @@ public class WiredTriggerRepeaterShort extends WiredTriggerRepeater {
|
|||||||
long elapsedMs = tickCount * tickIntervalMs;
|
long elapsedMs = tickCount * tickIntervalMs;
|
||||||
|
|
||||||
if (elapsedMs % this.repeatTime == 0) {
|
if (elapsedMs % this.repeatTime == 0) {
|
||||||
if (this.getRoomId() != 0 && room.isLoaded()) {
|
long currentTime = System.currentTimeMillis();
|
||||||
|
if (this.getRoomId() != 0 && room.isLoaded()
|
||||||
|
&& WiredManager.isTriggerExecutionAllowed(room, this, currentTime)) {
|
||||||
WiredManager.triggerTimerRepeatShort(room, this);
|
WiredManager.triggerTimerRepeatShort(room, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2032,6 +2032,10 @@ public class Room implements Comparable<Room>, ISerialize, Runnable {
|
|||||||
this.messagingManager.sendComposer(message);
|
this.messagingManager.sendComposer(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void sendComposers(Collection<ServerMessage> messages) {
|
||||||
|
this.messagingManager.sendComposers(messages);
|
||||||
|
}
|
||||||
|
|
||||||
public void sendComposerToHabbosWithRights(ServerMessage message) {
|
public void sendComposerToHabbosWithRights(ServerMessage message) {
|
||||||
this.messagingManager.sendComposerToHabbosWithRights(message);
|
this.messagingManager.sendComposerToHabbosWithRights(message);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import com.eu.habbo.habbohotel.users.DanceType;
|
|||||||
import com.eu.habbo.habbohotel.users.Habbo;
|
import com.eu.habbo.habbohotel.users.Habbo;
|
||||||
import com.eu.habbo.habbohotel.users.HabboItem;
|
import com.eu.habbo.habbohotel.users.HabboItem;
|
||||||
import com.eu.habbo.habbohotel.wired.core.WiredManager;
|
import com.eu.habbo.habbohotel.wired.core.WiredManager;
|
||||||
|
import com.eu.habbo.habbohotel.wired.core.WiredMoveCarryHelper;
|
||||||
import com.eu.habbo.messages.ServerMessage;
|
import com.eu.habbo.messages.ServerMessage;
|
||||||
import com.eu.habbo.messages.outgoing.rooms.RoomAccessDeniedComposer;
|
import com.eu.habbo.messages.outgoing.rooms.RoomAccessDeniedComposer;
|
||||||
import com.eu.habbo.messages.outgoing.rooms.users.RoomUnitIdleComposer;
|
import com.eu.habbo.messages.outgoing.rooms.users.RoomUnitIdleComposer;
|
||||||
@@ -123,7 +124,19 @@ public class RoomCycleManager {
|
|||||||
|
|
||||||
// Send status updates
|
// Send status updates
|
||||||
if (!updatedUnit.isEmpty()) {
|
if (!updatedUnit.isEmpty()) {
|
||||||
this.room.sendComposer(new RoomUserStatusComposer(updatedUnit, true).compose());
|
ServerMessage statusComposer = new RoomUserStatusComposer(updatedUnit, true).compose();
|
||||||
|
WiredMoveCarryHelper.beginMovementCollection();
|
||||||
|
WiredMoveCarryHelper.processUserFollowers(this.room, updatedUnit);
|
||||||
|
ServerMessage wiredMovementsComposer = WiredMoveCarryHelper.finishMovementCollection();
|
||||||
|
|
||||||
|
if (wiredMovementsComposer != null) {
|
||||||
|
ArrayList<ServerMessage> batchedMessages = new ArrayList<>(2);
|
||||||
|
batchedMessages.add(statusComposer);
|
||||||
|
batchedMessages.add(wiredMovementsComposer);
|
||||||
|
this.room.sendComposers(batchedMessages);
|
||||||
|
} else {
|
||||||
|
this.room.sendComposer(statusComposer);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cycle trax manager
|
// Cycle trax manager
|
||||||
|
|||||||
@@ -4,6 +4,9 @@ import com.eu.habbo.habbohotel.users.Habbo;
|
|||||||
import com.eu.habbo.messages.ServerMessage;
|
import com.eu.habbo.messages.ServerMessage;
|
||||||
import com.eu.habbo.messages.outgoing.generic.alerts.GenericAlertComposer;
|
import com.eu.habbo.messages.outgoing.generic.alerts.GenericAlertComposer;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manages all messaging and communication within a room.
|
* Manages all messaging and communication within a room.
|
||||||
* Handles sending messages to Habbos, pet/bot chat, and alerts.
|
* Handles sending messages to Habbos, pet/bot chat, and alerts.
|
||||||
@@ -30,6 +33,34 @@ public class RoomMessagingManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void sendComposers(Collection<ServerMessage> messages) {
|
||||||
|
if (messages == null || messages.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ArrayList<ServerMessage> responses = new ArrayList<>();
|
||||||
|
|
||||||
|
for (ServerMessage message : messages) {
|
||||||
|
if (message == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
responses.add(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (responses.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Habbo habbo : this.room.getHabbos()) {
|
||||||
|
if (habbo.getClient() == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
habbo.getClient().sendResponses(new ArrayList<>(responses));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends a message to all Habbos with rights in the room.
|
* Sends a message to all Habbos with rights in the room.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -74,6 +74,7 @@ public class RoomUnit {
|
|||||||
private int handItem;
|
private int handItem;
|
||||||
private long handItemTimestamp;
|
private long handItemTimestamp;
|
||||||
private long lastRollerTime;
|
private long lastRollerTime;
|
||||||
|
private long moveStatusTimestamp;
|
||||||
private int walkTimeOut;
|
private int walkTimeOut;
|
||||||
private int effectId;
|
private int effectId;
|
||||||
private int effectEndTimestamp;
|
private int effectEndTimestamp;
|
||||||
@@ -104,6 +105,7 @@ public class RoomUnit {
|
|||||||
this.goalLocation = null;
|
this.goalLocation = null;
|
||||||
this.startLocation = this.currentLocation;
|
this.startLocation = this.currentLocation;
|
||||||
this.inRoom = false;
|
this.inRoom = false;
|
||||||
|
this.moveStatusTimestamp = 0L;
|
||||||
|
|
||||||
this.status.clear();
|
this.status.clear();
|
||||||
|
|
||||||
@@ -611,12 +613,16 @@ public class RoomUnit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void removeStatus(RoomUnitStatus key) {
|
public void removeStatus(RoomUnitStatus key) {
|
||||||
|
if (key == RoomUnitStatus.MOVE) {
|
||||||
|
this.moveStatusTimestamp = 0L;
|
||||||
|
}
|
||||||
this.status.remove(key);
|
this.status.remove(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setStatus(RoomUnitStatus key, String value) {
|
public void setStatus(RoomUnitStatus key, String value) {
|
||||||
if (key != null && value != null) {
|
if (key != null && value != null) {
|
||||||
if (key == RoomUnitStatus.MOVE) {
|
if (key == RoomUnitStatus.MOVE) {
|
||||||
|
this.moveStatusTimestamp = System.currentTimeMillis();
|
||||||
WiredMoveCarryHelper.clearStatusComposerSuppression(this);
|
WiredMoveCarryHelper.clearStatusComposerSuppression(this);
|
||||||
WiredUserMovementHelper.clearStatusComposerSuppression(this);
|
WiredUserMovementHelper.clearStatusComposerSuppression(this);
|
||||||
}
|
}
|
||||||
@@ -630,6 +636,7 @@ public class RoomUnit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void clearStatus() {
|
public void clearStatus() {
|
||||||
|
this.moveStatusTimestamp = 0L;
|
||||||
this.status.clear();
|
this.status.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -657,6 +664,10 @@ public class RoomUnit {
|
|||||||
this.lastRollerTime = lastRollerTime;
|
this.lastRollerTime = lastRollerTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public long getMoveStatusTimestamp() {
|
||||||
|
return this.moveStatusTimestamp;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if enough time has passed since the last roller movement to allow rolling again.
|
* Checks if enough time has passed since the last roller movement to allow rolling again.
|
||||||
* This prevents desync issues where the client hasn't finished the roller animation.
|
* This prevents desync issues where the client hasn't finished the roller animation.
|
||||||
|
|||||||
@@ -10,6 +10,8 @@ import com.eu.habbo.habbohotel.items.interactions.InteractionWiredTrigger;
|
|||||||
import com.eu.habbo.habbohotel.items.interactions.wired.WiredTriggerReset;
|
import com.eu.habbo.habbohotel.items.interactions.wired.WiredTriggerReset;
|
||||||
import com.eu.habbo.habbohotel.items.interactions.wired.effects.WiredEffectGiveReward;
|
import com.eu.habbo.habbohotel.items.interactions.wired.effects.WiredEffectGiveReward;
|
||||||
import com.eu.habbo.habbohotel.items.interactions.wired.effects.WiredEffectTriggerStacks;
|
import com.eu.habbo.habbohotel.items.interactions.wired.effects.WiredEffectTriggerStacks;
|
||||||
|
import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredExtraExecuteInOrder;
|
||||||
|
import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredExtraExecutionLimit;
|
||||||
import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredExtraRandom;
|
import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredExtraRandom;
|
||||||
import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredExtraUnseen;
|
import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredExtraUnseen;
|
||||||
import com.eu.habbo.habbohotel.rooms.Room;
|
import com.eu.habbo.habbohotel.rooms.Room;
|
||||||
@@ -27,6 +29,7 @@ import com.eu.habbo.plugin.events.furniture.wired.WiredConditionFailedEvent;
|
|||||||
import com.eu.habbo.plugin.events.furniture.wired.WiredStackExecutedEvent;
|
import com.eu.habbo.plugin.events.furniture.wired.WiredStackExecutedEvent;
|
||||||
import com.eu.habbo.plugin.events.furniture.wired.WiredStackTriggeredEvent;
|
import com.eu.habbo.plugin.events.furniture.wired.WiredStackTriggeredEvent;
|
||||||
import com.eu.habbo.plugin.events.users.UserWiredRewardReceived;
|
import com.eu.habbo.plugin.events.users.UserWiredRewardReceived;
|
||||||
|
import com.eu.habbo.habbohotel.wired.core.WiredExecutionOrderUtil;
|
||||||
import com.google.gson.GsonBuilder;
|
import com.google.gson.GsonBuilder;
|
||||||
import gnu.trove.set.hash.THashSet;
|
import gnu.trove.set.hash.THashSet;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
@@ -37,7 +40,7 @@ import java.sql.PreparedStatement;
|
|||||||
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.Collections;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
public class WiredHandler {
|
public class WiredHandler {
|
||||||
@@ -49,6 +52,11 @@ public class WiredHandler {
|
|||||||
|
|
||||||
private static GsonBuilder gsonBuilder = null;
|
private static GsonBuilder gsonBuilder = null;
|
||||||
|
|
||||||
|
private static final class LegacyExecutionPlan {
|
||||||
|
private final LinkedHashSet<InteractionWiredEffect> effects = new LinkedHashSet<>();
|
||||||
|
private boolean executeInOrder = false;
|
||||||
|
}
|
||||||
|
|
||||||
public static boolean handle(WiredTriggerType triggerType, RoomUnit roomUnit, Room room, Object[] stuff) {
|
public static boolean handle(WiredTriggerType triggerType, RoomUnit roomUnit, Room room, Object[] stuff) {
|
||||||
if (triggerType == WiredTriggerType.CUSTOM) return false;
|
if (triggerType == WiredTriggerType.CUSTOM) return false;
|
||||||
|
|
||||||
@@ -72,7 +80,7 @@ public class WiredHandler {
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
long millis = System.currentTimeMillis();
|
long millis = System.currentTimeMillis();
|
||||||
THashSet<InteractionWiredEffect> effectsToExecute = new THashSet<InteractionWiredEffect>();
|
List<LegacyExecutionPlan> executionPlans = new ArrayList<>();
|
||||||
|
|
||||||
List<RoomTile> triggeredTiles = new ArrayList<>();
|
List<RoomTile> triggeredTiles = new ArrayList<>();
|
||||||
for (InteractionWiredTrigger trigger : triggers) {
|
for (InteractionWiredTrigger trigger : triggers) {
|
||||||
@@ -81,10 +89,10 @@ public class WiredHandler {
|
|||||||
if (triggeredTiles.contains(tile))
|
if (triggeredTiles.contains(tile))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
THashSet<InteractionWiredEffect> tEffectsToExecute = new THashSet<InteractionWiredEffect>();
|
LegacyExecutionPlan executionPlan = new LegacyExecutionPlan();
|
||||||
|
|
||||||
if (handle(trigger, roomUnit, room, stuff, tEffectsToExecute)) {
|
if (handle(trigger, roomUnit, room, stuff, executionPlan)) {
|
||||||
effectsToExecute.addAll(tEffectsToExecute);
|
executionPlans.add(executionPlan);
|
||||||
|
|
||||||
if (triggerType.equals(WiredTriggerType.SAY_SOMETHING))
|
if (triggerType.equals(WiredTriggerType.SAY_SOMETHING))
|
||||||
talked = true;
|
talked = true;
|
||||||
@@ -93,8 +101,8 @@ public class WiredHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (InteractionWiredEffect effect : effectsToExecute) {
|
for (LegacyExecutionPlan executionPlan : executionPlans) {
|
||||||
triggerEffect(effect, roomUnit, room, stuff, millis);
|
triggerEffects(executionPlan.effects, roomUnit, room, stuff, millis, executionPlan.executeInOrder);
|
||||||
}
|
}
|
||||||
|
|
||||||
return talked;
|
return talked;
|
||||||
@@ -119,7 +127,7 @@ public class WiredHandler {
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
long millis = System.currentTimeMillis();
|
long millis = System.currentTimeMillis();
|
||||||
THashSet<InteractionWiredEffect> effectsToExecute = new THashSet<InteractionWiredEffect>();
|
List<LegacyExecutionPlan> executionPlans = new ArrayList<>();
|
||||||
|
|
||||||
List<RoomTile> triggeredTiles = new ArrayList<>();
|
List<RoomTile> triggeredTiles = new ArrayList<>();
|
||||||
for (InteractionWiredTrigger trigger : triggers) {
|
for (InteractionWiredTrigger trigger : triggers) {
|
||||||
@@ -130,44 +138,51 @@ public class WiredHandler {
|
|||||||
if (triggeredTiles.contains(tile))
|
if (triggeredTiles.contains(tile))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
THashSet<InteractionWiredEffect> tEffectsToExecute = new THashSet<InteractionWiredEffect>();
|
LegacyExecutionPlan executionPlan = new LegacyExecutionPlan();
|
||||||
|
|
||||||
if (handle(trigger, roomUnit, room, stuff, tEffectsToExecute)) {
|
if (handle(trigger, roomUnit, room, stuff, executionPlan)) {
|
||||||
effectsToExecute.addAll(tEffectsToExecute);
|
executionPlans.add(executionPlan);
|
||||||
triggeredTiles.add(tile);
|
triggeredTiles.add(tile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (InteractionWiredEffect effect : effectsToExecute) {
|
for (LegacyExecutionPlan executionPlan : executionPlans) {
|
||||||
triggerEffect(effect, roomUnit, room, stuff, millis);
|
triggerEffects(executionPlan.effects, roomUnit, room, stuff, millis, executionPlan.executeInOrder);
|
||||||
}
|
}
|
||||||
|
|
||||||
return effectsToExecute.size() > 0;
|
return !executionPlans.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean handle(InteractionWiredTrigger trigger, final RoomUnit roomUnit, final Room room, final Object[] stuff) {
|
public static boolean handle(InteractionWiredTrigger trigger, final RoomUnit roomUnit, final Room room, final Object[] stuff) {
|
||||||
long millis = System.currentTimeMillis();
|
long millis = System.currentTimeMillis();
|
||||||
THashSet<InteractionWiredEffect> effectsToExecute = new THashSet<InteractionWiredEffect>();
|
LegacyExecutionPlan executionPlan = new LegacyExecutionPlan();
|
||||||
|
|
||||||
if(handle(trigger, roomUnit, room, stuff, effectsToExecute)) {
|
if(handle(trigger, roomUnit, room, stuff, executionPlan)) {
|
||||||
for (InteractionWiredEffect effect : effectsToExecute) {
|
triggerEffects(executionPlan.effects, roomUnit, room, stuff, millis, executionPlan.executeInOrder);
|
||||||
triggerEffect(effect, roomUnit, room, stuff, millis);
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean handle(InteractionWiredTrigger trigger, final RoomUnit roomUnit, final Room room, final Object[] stuff, final THashSet<InteractionWiredEffect> effectsToExecute) {
|
private static boolean handle(InteractionWiredTrigger trigger, final RoomUnit roomUnit, final Room room, final Object[] stuff, final LegacyExecutionPlan executionPlan) {
|
||||||
long millis = System.currentTimeMillis();
|
long millis = System.currentTimeMillis();
|
||||||
int roomUnitId = roomUnit != null ? roomUnit.getId() : -1;
|
int roomUnitId = roomUnit != null ? roomUnit.getId() : -1;
|
||||||
if (Emulator.isReady && ((Emulator.getConfig().getBoolean("wired.custom.enabled", false) && (trigger.canExecute(millis) || roomUnitId > -1) && trigger.userCanExecute(roomUnitId, millis)) || (!Emulator.getConfig().getBoolean("wired.custom.enabled", false) && trigger.canExecute(millis))) && trigger.execute(roomUnit, room, stuff)) {
|
if (Emulator.isReady && ((Emulator.getConfig().getBoolean("wired.custom.enabled", false) && (trigger.canExecute(millis) || roomUnitId > -1) && trigger.userCanExecute(roomUnitId, millis)) || (!Emulator.getConfig().getBoolean("wired.custom.enabled", false) && trigger.canExecute(millis))) && trigger.execute(roomUnit, room, stuff)) {
|
||||||
trigger.activateBox(room, roomUnit, millis);
|
|
||||||
|
|
||||||
THashSet<InteractionWiredCondition> conditions = room.getRoomSpecialTypes().getConditions(trigger.getX(), trigger.getY());
|
THashSet<InteractionWiredCondition> conditions = room.getRoomSpecialTypes().getConditions(trigger.getX(), trigger.getY());
|
||||||
THashSet<InteractionWiredEffect> effects = room.getRoomSpecialTypes().getEffects(trigger.getX(), trigger.getY());
|
THashSet<InteractionWiredEffect> effects = room.getRoomSpecialTypes().getEffects(trigger.getX(), trigger.getY());
|
||||||
if (Emulator.getPluginManager().fireEvent(new WiredStackTriggeredEvent(room, roomUnit, trigger, effects, conditions)).isCancelled())
|
THashSet<InteractionWiredExtra> extras = room.getRoomSpecialTypes().getExtras(trigger.getX(), trigger.getY());
|
||||||
return false;
|
WiredExtraExecutionLimit executionLimitExtra = null;
|
||||||
|
WiredExtraRandom randomExtra = null;
|
||||||
|
|
||||||
|
for (InteractionWiredExtra extra : extras) {
|
||||||
|
if (executionLimitExtra == null && extra instanceof WiredExtraExecutionLimit) {
|
||||||
|
executionLimitExtra = (WiredExtraExecutionLimit) extra;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (randomExtra == null && extra instanceof WiredExtraRandom) {
|
||||||
|
randomExtra = (WiredExtraRandom) extra;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!conditions.isEmpty()) {
|
if (!conditions.isEmpty()) {
|
||||||
ArrayList<WiredConditionType> matchedConditions = new ArrayList<>(conditions.size());
|
ArrayList<WiredConditionType> matchedConditions = new ArrayList<>(conditions.size());
|
||||||
@@ -187,39 +202,48 @@ public class WiredHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (executionLimitExtra != null && !executionLimitExtra.tryAcquireExecutionSlot(millis)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Emulator.getPluginManager().fireEvent(new WiredStackTriggeredEvent(room, roomUnit, trigger, effects, conditions)).isCancelled())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
trigger.activateBox(room, roomUnit, millis);
|
||||||
|
|
||||||
trigger.setCooldown(millis);
|
trigger.setCooldown(millis);
|
||||||
|
|
||||||
boolean hasExtraUnseen = room.getRoomSpecialTypes().hasExtraType(trigger.getX(), trigger.getY(), WiredExtraUnseen.class);
|
boolean hasExtraUnseen = room.getRoomSpecialTypes().hasExtraType(trigger.getX(), trigger.getY(), WiredExtraUnseen.class);
|
||||||
THashSet<InteractionWiredExtra> extras = room.getRoomSpecialTypes().getExtras(trigger.getX(), trigger.getY());
|
boolean hasExtraExecuteInOrder = room.getRoomSpecialTypes().hasExtraType(trigger.getX(), trigger.getY(), WiredExtraExecuteInOrder.class);
|
||||||
WiredExtraRandom randomExtra = null;
|
|
||||||
|
|
||||||
for (InteractionWiredExtra extra : extras) {
|
for (InteractionWiredExtra extra : extras) {
|
||||||
extra.activateBox(room, roomUnit, millis);
|
extra.activateBox(room, roomUnit, millis);
|
||||||
if (randomExtra == null && extra instanceof WiredExtraRandom) {
|
|
||||||
randomExtra = (WiredExtraRandom) extra;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
List<InteractionWiredEffect> effectList = new ArrayList<>(effects);
|
List<InteractionWiredEffect> effectList = (hasExtraUnseen || hasExtraExecuteInOrder)
|
||||||
|
? WiredExecutionOrderUtil.sort(effects)
|
||||||
|
: new ArrayList<>(effects);
|
||||||
|
|
||||||
if (randomExtra != null || hasExtraUnseen) {
|
executionPlan.executeInOrder = hasExtraExecuteInOrder;
|
||||||
Collections.shuffle(effectList);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hasExtraUnseen) {
|
if (hasExtraUnseen) {
|
||||||
for (InteractionWiredExtra extra : room.getRoomSpecialTypes().getExtras(trigger.getX(), trigger.getY())) {
|
for (InteractionWiredExtra extra : room.getRoomSpecialTypes().getExtras(trigger.getX(), trigger.getY())) {
|
||||||
if (extra instanceof WiredExtraUnseen) {
|
if (extra instanceof WiredExtraUnseen) {
|
||||||
extra.setExtradata(extra.getExtradata().equals("1") ? "0" : "1");
|
extra.setExtradata(extra.getExtradata().equals("1") ? "0" : "1");
|
||||||
InteractionWiredEffect effect = ((WiredExtraUnseen) extra).getUnseenEffect(effectList);
|
InteractionWiredEffect effect = ((WiredExtraUnseen) extra).getUnseenEffect(effectList);
|
||||||
effectsToExecute.add(effect); // triggerEffect(effect, roomUnit, room, stuff, millis);
|
if (effect != null) {
|
||||||
|
executionPlan.effects.add(effect);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (randomExtra != null) {
|
} else if (randomExtra != null) {
|
||||||
effectsToExecute.addAll(randomExtra.selectEffects(effectList));
|
executionPlan.effects.addAll(randomExtra.selectEffects(effectList));
|
||||||
|
} else if (hasExtraExecuteInOrder) {
|
||||||
|
executionPlan.effects.addAll(effectList);
|
||||||
} else {
|
} else {
|
||||||
for (final InteractionWiredEffect effect : effectList) {
|
for (final InteractionWiredEffect effect : effectList) {
|
||||||
effectsToExecute.add(effect); //triggerEffect(effect, roomUnit, room, stuff, millis);
|
executionPlan.effects.add(effect);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -234,7 +258,7 @@ public class WiredHandler {
|
|||||||
if (effect != null && (effect.canExecute(millis) || (roomUnit != null && effect.requiresTriggeringUser() && Emulator.getConfig().getBoolean("wired.custom.enabled", false) && effect.userCanExecute(roomUnit.getId(), millis)))) {
|
if (effect != null && (effect.canExecute(millis) || (roomUnit != null && effect.requiresTriggeringUser() && Emulator.getConfig().getBoolean("wired.custom.enabled", false) && effect.userCanExecute(roomUnit.getId(), millis)))) {
|
||||||
executed = true;
|
executed = true;
|
||||||
if (!effect.requiresTriggeringUser() || (roomUnit != null && effect.requiresTriggeringUser())) {
|
if (!effect.requiresTriggeringUser() || (roomUnit != null && effect.requiresTriggeringUser())) {
|
||||||
Emulator.getThreading().run(() -> {
|
Runnable execution = () -> {
|
||||||
if (room.isLoaded() && room.getHabbos().size() > 0) {
|
if (room.isLoaded() && room.getHabbos().size() > 0) {
|
||||||
try {
|
try {
|
||||||
if (!effect.execute(roomUnit, room, stuff)) return;
|
if (!effect.execute(roomUnit, room, stuff)) return;
|
||||||
@@ -245,13 +269,108 @@ public class WiredHandler {
|
|||||||
|
|
||||||
effect.activateBox(room, roomUnit, millis);
|
effect.activateBox(room, roomUnit, millis);
|
||||||
}
|
}
|
||||||
}, effect.getDelay() * 500L);
|
};
|
||||||
|
|
||||||
|
long delayMs = effect.getDelay() * 500L;
|
||||||
|
long elapsedSinceTrigger = Math.max(0L, System.currentTimeMillis() - millis);
|
||||||
|
long remainingDelayMs = Math.max(0L, delayMs - elapsedSinceTrigger);
|
||||||
|
|
||||||
|
if (delayMs <= 0) {
|
||||||
|
execution.run();
|
||||||
|
} else {
|
||||||
|
Emulator.getThreading().run(execution, remainingDelayMs);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return executed;
|
return executed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void triggerEffects(LinkedHashSet<InteractionWiredEffect> effects, RoomUnit roomUnit, Room room, Object[] stuff, long millis, boolean executeInOrder) {
|
||||||
|
if (effects == null || effects.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!executeInOrder) {
|
||||||
|
for (InteractionWiredEffect effect : effects) {
|
||||||
|
triggerEffect(effect, roomUnit, room, stuff, millis);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LinkedHashSet<InteractionWiredEffect> queueableEffects = new LinkedHashSet<>();
|
||||||
|
|
||||||
|
for (InteractionWiredEffect effect : effects) {
|
||||||
|
if (canQueueEffect(effect, roomUnit, millis)) {
|
||||||
|
queueableEffects.add(effect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LinkedHashSet<Integer> delays = new LinkedHashSet<>();
|
||||||
|
for (InteractionWiredEffect effect : queueableEffects) {
|
||||||
|
delays.add(effect.getDelay());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Integer delay : delays) {
|
||||||
|
List<InteractionWiredEffect> delayBatch = new ArrayList<>();
|
||||||
|
|
||||||
|
for (InteractionWiredEffect effect : queueableEffects) {
|
||||||
|
if (effect.getDelay() == delay) {
|
||||||
|
delayBatch.add(effect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (delayBatch.isEmpty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (delay > 0) {
|
||||||
|
long delayMs = delay * 500L;
|
||||||
|
long elapsedSinceTrigger = Math.max(0L, System.currentTimeMillis() - millis);
|
||||||
|
long remainingDelayMs = Math.max(0L, delayMs - elapsedSinceTrigger);
|
||||||
|
Emulator.getThreading().run(() -> executeOrderedEffectBatch(delayBatch, roomUnit, room, stuff, millis), remainingDelayMs);
|
||||||
|
} else {
|
||||||
|
executeOrderedEffectBatch(delayBatch, roomUnit, room, stuff, millis);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean canQueueEffect(InteractionWiredEffect effect, RoomUnit roomUnit, long millis) {
|
||||||
|
if (effect == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean canExecute = effect.canExecute(millis)
|
||||||
|
|| (roomUnit != null && effect.requiresTriggeringUser()
|
||||||
|
&& Emulator.getConfig().getBoolean("wired.custom.enabled", false)
|
||||||
|
&& effect.userCanExecute(roomUnit.getId(), millis));
|
||||||
|
|
||||||
|
if (!canExecute) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return !effect.requiresTriggeringUser() || roomUnit != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void executeOrderedEffectBatch(List<InteractionWiredEffect> effects, RoomUnit roomUnit, Room room, Object[] stuff, long millis) {
|
||||||
|
if (!room.isLoaded() || room.getHabbos().size() <= 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (InteractionWiredEffect effect : effects) {
|
||||||
|
try {
|
||||||
|
if (!effect.execute(roomUnit, room, stuff)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
effect.setCooldown(millis);
|
||||||
|
effect.activateBox(room, roomUnit, millis);
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOGGER.error("Caught exception", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static GsonBuilder getGsonBuilder() {
|
public static GsonBuilder getGsonBuilder() {
|
||||||
if(gsonBuilder == null) {
|
if(gsonBuilder == null) {
|
||||||
gsonBuilder = new GsonBuilder();
|
gsonBuilder = new GsonBuilder();
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ public final class WiredStack {
|
|||||||
private final boolean useOrMode; // WiredExtraOrEval present
|
private final boolean useOrMode; // WiredExtraOrEval present
|
||||||
private final boolean useRandom; // WiredExtraRandom present
|
private final boolean useRandom; // WiredExtraRandom present
|
||||||
private final boolean useUnseen; // WiredExtraUnseen present
|
private final boolean useUnseen; // WiredExtraUnseen present
|
||||||
|
private final boolean executeInOrder; // WiredExtraExecuteInOrder present
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new wired stack.
|
* Create a new wired stack.
|
||||||
@@ -52,7 +53,7 @@ public final class WiredStack {
|
|||||||
IWiredTrigger trigger,
|
IWiredTrigger trigger,
|
||||||
List<IWiredCondition> conditions,
|
List<IWiredCondition> conditions,
|
||||||
List<IWiredEffect> effects) {
|
List<IWiredEffect> effects) {
|
||||||
this(triggerItem, trigger, conditions, effects, false, false, false);
|
this(triggerItem, trigger, conditions, effects, false, false, false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -65,6 +66,7 @@ public final class WiredStack {
|
|||||||
* @param useOrMode if true, conditions use OR logic (any pass = success)
|
* @param useOrMode if true, conditions use OR logic (any pass = success)
|
||||||
* @param useRandom if true, select one random effect instead of all
|
* @param useRandom if true, select one random effect instead of all
|
||||||
* @param useUnseen if true, execute effects in "unseen" order (round-robin)
|
* @param useUnseen if true, execute effects in "unseen" order (round-robin)
|
||||||
|
* @param executeInOrder if true, execute all regular effects in stable stack order
|
||||||
*/
|
*/
|
||||||
public WiredStack(HabboItem triggerItem,
|
public WiredStack(HabboItem triggerItem,
|
||||||
IWiredTrigger trigger,
|
IWiredTrigger trigger,
|
||||||
@@ -72,7 +74,8 @@ public final class WiredStack {
|
|||||||
List<IWiredEffect> effects,
|
List<IWiredEffect> effects,
|
||||||
boolean useOrMode,
|
boolean useOrMode,
|
||||||
boolean useRandom,
|
boolean useRandom,
|
||||||
boolean useUnseen) {
|
boolean useUnseen,
|
||||||
|
boolean executeInOrder) {
|
||||||
this.triggerItem = triggerItem;
|
this.triggerItem = triggerItem;
|
||||||
this.trigger = trigger;
|
this.trigger = trigger;
|
||||||
this.conditions = conditions != null ? Collections.unmodifiableList(conditions) : Collections.emptyList();
|
this.conditions = conditions != null ? Collections.unmodifiableList(conditions) : Collections.emptyList();
|
||||||
@@ -80,6 +83,7 @@ public final class WiredStack {
|
|||||||
this.useOrMode = useOrMode;
|
this.useOrMode = useOrMode;
|
||||||
this.useRandom = useRandom;
|
this.useRandom = useRandom;
|
||||||
this.useUnseen = useUnseen;
|
this.useUnseen = useUnseen;
|
||||||
|
this.executeInOrder = executeInOrder;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -157,6 +161,15 @@ public final class WiredStack {
|
|||||||
return useUnseen;
|
return useUnseen;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if ordered execution mode is enabled (WiredExtraExecuteInOrder).
|
||||||
|
* When true, all regular effects execute in stable stack order.
|
||||||
|
* @return true if ordered execution is enabled
|
||||||
|
*/
|
||||||
|
public boolean executeInOrder() {
|
||||||
|
return executeInOrder;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the number of conditions.
|
* Get the number of conditions.
|
||||||
* @return condition count
|
* @return condition count
|
||||||
@@ -183,6 +196,7 @@ public final class WiredStack {
|
|||||||
", orMode=" + useOrMode +
|
", orMode=" + useOrMode +
|
||||||
", random=" + useRandom +
|
", random=" + useRandom +
|
||||||
", unseen=" + useUnseen +
|
", unseen=" + useUnseen +
|
||||||
|
", executeInOrder=" + executeInOrder +
|
||||||
'}';
|
'}';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package com.eu.habbo.habbohotel.wired.core;
|
|||||||
import com.eu.habbo.habbohotel.items.interactions.InteractionWiredCondition;
|
import com.eu.habbo.habbohotel.items.interactions.InteractionWiredCondition;
|
||||||
import com.eu.habbo.habbohotel.items.interactions.InteractionWiredEffect;
|
import com.eu.habbo.habbohotel.items.interactions.InteractionWiredEffect;
|
||||||
import com.eu.habbo.habbohotel.items.interactions.InteractionWiredTrigger;
|
import com.eu.habbo.habbohotel.items.interactions.InteractionWiredTrigger;
|
||||||
|
import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredExtraExecuteInOrder;
|
||||||
import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredExtraOrEval;
|
import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredExtraOrEval;
|
||||||
import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredExtraRandom;
|
import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredExtraRandom;
|
||||||
import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredExtraUnseen;
|
import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredExtraUnseen;
|
||||||
@@ -176,6 +177,7 @@ public final class RoomWiredStackIndex implements WiredStackIndex {
|
|||||||
boolean useOrMode = specialTypes.hasExtraType(x, y, WiredExtraOrEval.class);
|
boolean useOrMode = specialTypes.hasExtraType(x, y, WiredExtraOrEval.class);
|
||||||
boolean useRandom = specialTypes.hasExtraType(x, y, WiredExtraRandom.class);
|
boolean useRandom = specialTypes.hasExtraType(x, y, WiredExtraRandom.class);
|
||||||
boolean useUnseen = specialTypes.hasExtraType(x, y, WiredExtraUnseen.class);
|
boolean useUnseen = specialTypes.hasExtraType(x, y, WiredExtraUnseen.class);
|
||||||
|
boolean executeInOrder = specialTypes.hasExtraType(x, y, WiredExtraExecuteInOrder.class);
|
||||||
|
|
||||||
return new WiredStack(
|
return new WiredStack(
|
||||||
trigger,
|
trigger,
|
||||||
@@ -184,7 +186,8 @@ public final class RoomWiredStackIndex implements WiredStackIndex {
|
|||||||
effects,
|
effects,
|
||||||
useOrMode,
|
useOrMode,
|
||||||
useRandom,
|
useRandom,
|
||||||
useUnseen
|
useUnseen,
|
||||||
|
executeInOrder
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import com.eu.habbo.habbohotel.items.interactions.InteractionWiredEffect;
|
|||||||
import com.eu.habbo.habbohotel.items.interactions.InteractionWiredExtra;
|
import com.eu.habbo.habbohotel.items.interactions.InteractionWiredExtra;
|
||||||
import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredExtraFilterFurni;
|
import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredExtraFilterFurni;
|
||||||
import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredExtraFilterUser;
|
import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredExtraFilterUser;
|
||||||
|
import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredExtraExecutionLimit;
|
||||||
import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredExtraRandom;
|
import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredExtraRandom;
|
||||||
import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredExtraUnseen;
|
import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredExtraUnseen;
|
||||||
import com.eu.habbo.habbohotel.items.interactions.InteractionWiredTrigger;
|
import com.eu.habbo.habbohotel.items.interactions.InteractionWiredTrigger;
|
||||||
@@ -179,11 +180,11 @@ public final class WiredEngine {
|
|||||||
|
|
||||||
boolean anyTriggered = false;
|
boolean anyTriggered = false;
|
||||||
boolean suppressSaysOutput = false;
|
boolean suppressSaysOutput = false;
|
||||||
long currentTime = System.currentTimeMillis();
|
long triggerTime = event.getCreatedAtMs();
|
||||||
|
|
||||||
for (WiredStack stack : stacks) {
|
for (WiredStack stack : stacks) {
|
||||||
try {
|
try {
|
||||||
boolean triggered = processStack(stack, event, currentTime);
|
boolean triggered = processStack(stack, event, triggerTime);
|
||||||
if (triggered) {
|
if (triggered) {
|
||||||
anyTriggered = true;
|
anyTriggered = true;
|
||||||
|
|
||||||
@@ -257,6 +258,15 @@ public final class WiredEngine {
|
|||||||
debug(room, "No conditions in stack, proceeding to effects");
|
debug(room, "No conditions in stack, proceeding to effects");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WiredExtraExecutionLimit executionLimitExtra = getExecutionLimitExtra(room, stack);
|
||||||
|
if (executionLimitExtra != null && !executionLimitExtra.tryAcquireExecutionSlot(currentTime)) {
|
||||||
|
debug(room, "Execution limit blocked stack {} (max {} in {} ms)",
|
||||||
|
stack.triggerItem() != null ? stack.triggerItem().getId() : "null",
|
||||||
|
executionLimitExtra.getMaxExecutions(),
|
||||||
|
executionLimitExtra.getTimeWindowMs());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Fire plugin event (WiredStackTriggeredEvent)
|
// Fire plugin event (WiredStackTriggeredEvent)
|
||||||
if (!fireTriggeredEvent(stack, event)) {
|
if (!fireTriggeredEvent(stack, event)) {
|
||||||
debug(room, "Stack cancelled by plugin");
|
debug(room, "Stack cancelled by plugin");
|
||||||
@@ -427,6 +437,10 @@ public final class WiredEngine {
|
|||||||
debug(ctx.room(), "Unseen mode fallback: selected effect {}/{}", index + 1, regulars.size());
|
debug(ctx.room(), "Unseen mode fallback: selected effect {}/{}", index + 1, regulars.size());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if (stack.executeInOrder()) {
|
||||||
|
debug(ctx.room(), "Ordered mode: executing effect batches in stack order by delay");
|
||||||
|
executeOrderedEffects(regulars, ctx, currentTime);
|
||||||
|
return;
|
||||||
} else {
|
} else {
|
||||||
// Normal mode: regular effects in random order
|
// Normal mode: regular effects in random order
|
||||||
toExecute = new ArrayList<>(regulars);
|
toExecute = new ArrayList<>(regulars);
|
||||||
@@ -569,9 +583,11 @@ public final class WiredEngine {
|
|||||||
/**
|
/**
|
||||||
* Schedule a delayed effect execution.
|
* Schedule a delayed effect execution.
|
||||||
*/
|
*/
|
||||||
private void scheduleDelayedEffect(IWiredEffect effect, WiredContext ctx, int delay, long currentTime) {
|
private void scheduleDelayedEffect(IWiredEffect effect, WiredContext ctx, int delay, long triggerTime) {
|
||||||
// Delay is in 500ms ticks
|
// Delay is in 500ms ticks
|
||||||
long delayMs = delay * 500L;
|
long delayMs = delay * 500L;
|
||||||
|
long elapsedSinceTrigger = Math.max(0L, System.currentTimeMillis() - triggerTime);
|
||||||
|
long remainingDelayMs = Math.max(0L, delayMs - elapsedSinceTrigger);
|
||||||
Room room = ctx.room();
|
Room room = ctx.room();
|
||||||
RoomUnit actor = ctx.actor().orElse(null);
|
RoomUnit actor = ctx.actor().orElse(null);
|
||||||
|
|
||||||
@@ -592,7 +608,80 @@ public final class WiredEngine {
|
|||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LOGGER.warn("Error executing delayed effect: {}", e.getMessage());
|
LOGGER.warn("Error executing delayed effect: {}", e.getMessage());
|
||||||
}
|
}
|
||||||
}, delayMs);
|
}, remainingDelayMs);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void executeOrderedEffects(List<IWiredEffect> effects, WiredContext ctx, long currentTime) {
|
||||||
|
if (effects == null || effects.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<Integer, List<IWiredEffect>> effectsByDelay = new LinkedHashMap<>();
|
||||||
|
|
||||||
|
for (IWiredEffect effect : effects) {
|
||||||
|
if (effect == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (effect.requiresActor() && !ctx.hasActor()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
effectsByDelay.computeIfAbsent(effect.getDelay(), key -> new ArrayList<>()).add(effect);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Map.Entry<Integer, List<IWiredEffect>> entry : effectsByDelay.entrySet()) {
|
||||||
|
int delay = entry.getKey();
|
||||||
|
List<IWiredEffect> batch = entry.getValue();
|
||||||
|
|
||||||
|
if (batch.isEmpty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (delay > 0) {
|
||||||
|
scheduleOrderedEffectBatch(batch, ctx, delay, currentTime);
|
||||||
|
} else {
|
||||||
|
executeOrderedEffectBatch(batch, ctx, currentTime, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void scheduleOrderedEffectBatch(List<IWiredEffect> batch, WiredContext ctx, int delay, long triggerTime) {
|
||||||
|
long delayMs = delay * 500L;
|
||||||
|
long elapsedSinceTrigger = Math.max(0L, System.currentTimeMillis() - triggerTime);
|
||||||
|
long remainingDelayMs = Math.max(0L, delayMs - elapsedSinceTrigger);
|
||||||
|
Room room = ctx.room();
|
||||||
|
|
||||||
|
Emulator.getThreading().run(() -> {
|
||||||
|
if (!room.isLoaded() || room.getHabbos().isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
executeOrderedEffectBatch(batch, ctx, System.currentTimeMillis(), true);
|
||||||
|
}, remainingDelayMs);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void executeOrderedEffectBatch(List<IWiredEffect> batch, WiredContext ctx, long executionTime, boolean useExecutionTimeForCooldown) {
|
||||||
|
Room room = ctx.room();
|
||||||
|
RoomUnit actor = ctx.actor().orElse(null);
|
||||||
|
|
||||||
|
for (IWiredEffect effect : batch) {
|
||||||
|
try {
|
||||||
|
if (!useExecutionTimeForCooldown) {
|
||||||
|
ctx.state().step();
|
||||||
|
}
|
||||||
|
|
||||||
|
effect.execute(ctx);
|
||||||
|
|
||||||
|
if (effect instanceof InteractionWiredEffect) {
|
||||||
|
InteractionWiredEffect wiredEffect = (InteractionWiredEffect) effect;
|
||||||
|
wiredEffect.setCooldown(executionTime);
|
||||||
|
wiredEffect.activateBox(room, actor, executionTime);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOGGER.warn("Error executing ordered effect batch item: {}", e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -714,6 +803,12 @@ public final class WiredEngine {
|
|||||||
return (extra instanceof WiredExtraUnseen) ? (WiredExtraUnseen) extra : null;
|
return (extra instanceof WiredExtraUnseen) ? (WiredExtraUnseen) extra : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private WiredExtraExecutionLimit getExecutionLimitExtra(Room room, WiredStack stack) {
|
||||||
|
InteractionWiredExtra extra = getStackExtra(room, stack, WiredExtraExecutionLimit.class);
|
||||||
|
|
||||||
|
return (extra instanceof WiredExtraExecutionLimit) ? (WiredExtraExecutionLimit) extra : null;
|
||||||
|
}
|
||||||
|
|
||||||
private <T extends InteractionWiredExtra> InteractionWiredExtra getStackExtra(Room room, WiredStack stack, Class<T> extraClass) {
|
private <T extends InteractionWiredExtra> InteractionWiredExtra getStackExtra(Room room, WiredStack stack, Class<T> extraClass) {
|
||||||
if (room == null || stack == null || stack.triggerItem() == null || room.getRoomSpecialTypes() == null) {
|
if (room == null || stack == null || stack.triggerItem() == null || room.getRoomSpecialTypes() == null) {
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -4,8 +4,10 @@ import com.eu.habbo.Emulator;
|
|||||||
import com.eu.habbo.habbohotel.catalog.CatalogItem;
|
import com.eu.habbo.habbohotel.catalog.CatalogItem;
|
||||||
import com.eu.habbo.habbohotel.items.Item;
|
import com.eu.habbo.habbohotel.items.Item;
|
||||||
import com.eu.habbo.habbohotel.items.interactions.InteractionWiredEffect;
|
import com.eu.habbo.habbohotel.items.interactions.InteractionWiredEffect;
|
||||||
|
import com.eu.habbo.habbohotel.items.interactions.InteractionWiredExtra;
|
||||||
import com.eu.habbo.habbohotel.items.interactions.wired.effects.WiredEffectGiveReward;
|
import com.eu.habbo.habbohotel.items.interactions.wired.effects.WiredEffectGiveReward;
|
||||||
import com.eu.habbo.habbohotel.items.interactions.wired.effects.WiredEffectTriggerStacks;
|
import com.eu.habbo.habbohotel.items.interactions.wired.effects.WiredEffectTriggerStacks;
|
||||||
|
import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredExtraExecutionLimit;
|
||||||
import com.eu.habbo.habbohotel.items.interactions.wired.triggers.WiredTriggerHabboClicksUser;
|
import com.eu.habbo.habbohotel.items.interactions.wired.triggers.WiredTriggerHabboClicksUser;
|
||||||
import com.eu.habbo.habbohotel.rooms.Room;
|
import com.eu.habbo.habbohotel.rooms.Room;
|
||||||
import com.eu.habbo.habbohotel.rooms.RoomTile;
|
import com.eu.habbo.habbohotel.rooms.RoomTile;
|
||||||
@@ -725,6 +727,34 @@ public final class WiredManager {
|
|||||||
return WiredTickService.getInstance();
|
return WiredTickService.getInstance();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean isTriggerExecutionAllowed(Room room, HabboItem triggerItem, long timestamp) {
|
||||||
|
WiredExtraExecutionLimit executionLimit = getExecutionLimitExtra(room, triggerItem);
|
||||||
|
|
||||||
|
return executionLimit == null || executionLimit.canExecuteAt(timestamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static WiredExtraExecutionLimit getExecutionLimitExtra(Room room, HabboItem triggerItem) {
|
||||||
|
if (room == null || triggerItem == null || room.getRoomSpecialTypes() == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
THashSet<InteractionWiredExtra> extras = room.getRoomSpecialTypes().getExtras(
|
||||||
|
triggerItem.getX(),
|
||||||
|
triggerItem.getY());
|
||||||
|
|
||||||
|
if (extras == null || extras.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (InteractionWiredExtra extra : extras) {
|
||||||
|
if (extra instanceof WiredExtraExecutionLimit) {
|
||||||
|
return (WiredExtraExecutionLimit) extra;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
// ========== Timer Management ==========
|
// ========== Timer Management ==========
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+357
-6
@@ -14,6 +14,7 @@ import com.eu.habbo.habbohotel.rooms.RoomUnitStatus;
|
|||||||
import com.eu.habbo.habbohotel.rooms.RoomUnitType;
|
import com.eu.habbo.habbohotel.rooms.RoomUnitType;
|
||||||
import com.eu.habbo.habbohotel.users.Habbo;
|
import com.eu.habbo.habbohotel.users.Habbo;
|
||||||
import com.eu.habbo.habbohotel.users.HabboItem;
|
import com.eu.habbo.habbohotel.users.HabboItem;
|
||||||
|
import com.eu.habbo.messages.ServerMessage;
|
||||||
import com.eu.habbo.messages.outgoing.rooms.WiredMovementsComposer;
|
import com.eu.habbo.messages.outgoing.rooms.WiredMovementsComposer;
|
||||||
import com.eu.habbo.messages.outgoing.rooms.items.FloorItemOnRollerComposer;
|
import com.eu.habbo.messages.outgoing.rooms.items.FloorItemOnRollerComposer;
|
||||||
import com.eu.habbo.messages.outgoing.rooms.users.RoomUserStatusComposer;
|
import com.eu.habbo.messages.outgoing.rooms.users.RoomUserStatusComposer;
|
||||||
@@ -21,16 +22,21 @@ import gnu.trove.set.hash.THashSet;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Comparator;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
public final class WiredMoveCarryHelper {
|
public final class WiredMoveCarryHelper {
|
||||||
private static final double DIRECT_HEIGHT_TOLERANCE = 0.1D;
|
private static final double DIRECT_HEIGHT_TOLERANCE = 0.1D;
|
||||||
private static final int STATUS_SUPPRESSION_GRACE_MS = 250;
|
private static final int STATUS_SUPPRESSION_GRACE_MS = 250;
|
||||||
|
private static final long USER_FOLLOWER_TTL_MS = 10000L;
|
||||||
private static final ThreadLocal<Set<Integer>> SUPPRESSED_STATUS_ROOM_UNIT_IDS = new ThreadLocal<>();
|
private static final ThreadLocal<Set<Integer>> SUPPRESSED_STATUS_ROOM_UNIT_IDS = new ThreadLocal<>();
|
||||||
|
private static final ThreadLocal<List<WiredMovementsComposer.MovementData>> COLLECTED_MOVEMENTS = new ThreadLocal<>();
|
||||||
private static final ConcurrentHashMap<Integer, Long> SUPPRESSED_STATUS_COMPOSER_UNTIL = new ConcurrentHashMap<>();
|
private static final ConcurrentHashMap<Integer, Long> SUPPRESSED_STATUS_COMPOSER_UNTIL = new ConcurrentHashMap<>();
|
||||||
|
private static final ConcurrentHashMap<Integer, ConcurrentHashMap<Integer, UserFollowEntry>> ACTIVE_USER_FOLLOWERS = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
private WiredMoveCarryHelper() {
|
private WiredMoveCarryHelper() {
|
||||||
}
|
}
|
||||||
@@ -60,10 +66,22 @@ public final class WiredMoveCarryHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static FurnitureMovementError moveFurni(Room room, HabboItem stackItem, HabboItem movingItem, RoomTile targetTile, int rotation, Habbo actor, boolean sendUpdates, WiredContext ctx) {
|
public static FurnitureMovementError moveFurni(Room room, HabboItem stackItem, HabboItem movingItem, RoomTile targetTile, int rotation, Habbo actor, boolean sendUpdates, WiredContext ctx) {
|
||||||
return moveFurni(room, stackItem, movingItem, targetTile, rotation, null, actor, sendUpdates, ctx);
|
return moveFurni(room, stackItem, movingItem, targetTile, rotation, null, actor, sendUpdates, ctx, null, null, WiredMovementsComposer.FURNI_ANCHOR_NONE, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static FurnitureMovementError moveFurni(Room room, HabboItem stackItem, HabboItem movingItem, RoomTile targetTile, int rotation, Double z, Habbo actor, boolean sendUpdates, WiredContext ctx) {
|
public static FurnitureMovementError moveFurni(Room room, HabboItem stackItem, HabboItem movingItem, RoomTile targetTile, int rotation, Double z, Habbo actor, boolean sendUpdates, WiredContext ctx) {
|
||||||
|
return moveFurni(room, stackItem, movingItem, targetTile, rotation, z, actor, sendUpdates, ctx, null, null, WiredMovementsComposer.FURNI_ANCHOR_NONE, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static FurnitureMovementError moveFurni(Room room, HabboItem stackItem, HabboItem movingItem, RoomTile targetTile, int rotation, Double z, Habbo actor, boolean sendUpdates, WiredContext ctx, Integer animationDurationOverride) {
|
||||||
|
return moveFurni(room, stackItem, movingItem, targetTile, rotation, z, actor, sendUpdates, ctx, animationDurationOverride, null, WiredMovementsComposer.FURNI_ANCHOR_NONE, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static FurnitureMovementError moveFurni(Room room, HabboItem stackItem, HabboItem movingItem, RoomTile targetTile, int rotation, Double z, Habbo actor, boolean sendUpdates, WiredContext ctx, Integer animationDurationOverride, Integer animationElapsedOverride) {
|
||||||
|
return moveFurni(room, stackItem, movingItem, targetTile, rotation, z, actor, sendUpdates, ctx, animationDurationOverride, animationElapsedOverride, WiredMovementsComposer.FURNI_ANCHOR_NONE, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static FurnitureMovementError moveFurni(Room room, HabboItem stackItem, HabboItem movingItem, RoomTile targetTile, int rotation, Double z, Habbo actor, boolean sendUpdates, WiredContext ctx, Integer animationDurationOverride, Integer animationElapsedOverride, int anchorType, int anchorId) {
|
||||||
if (room == null || movingItem == null || targetTile == null) {
|
if (room == null || movingItem == null || targetTile == null) {
|
||||||
return FurnitureMovementError.INVALID_MOVE;
|
return FurnitureMovementError.INVALID_MOVE;
|
||||||
}
|
}
|
||||||
@@ -97,7 +115,9 @@ public final class WiredMoveCarryHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
boolean useWiredMovements = !hasNoAnimationExtra(room, stackItem);
|
boolean useWiredMovements = !hasNoAnimationExtra(room, stackItem);
|
||||||
int animationDuration = getAnimationDuration(room, stackItem, WiredMovementsComposer.DEFAULT_DURATION);
|
int animationDuration = animationDurationOverride != null
|
||||||
|
? Math.max(50, animationDurationOverride)
|
||||||
|
: getAnimationDuration(room, stackItem, WiredMovementsComposer.DEFAULT_DURATION);
|
||||||
Set<Integer> previousSuppressedRoomUnitIds = SUPPRESSED_STATUS_ROOM_UNIT_IDS.get();
|
Set<Integer> previousSuppressedRoomUnitIds = SUPPRESSED_STATUS_ROOM_UNIT_IDS.get();
|
||||||
|
|
||||||
if (carryContext.active) {
|
if (carryContext.active) {
|
||||||
@@ -133,7 +153,7 @@ public final class WiredMoveCarryHelper {
|
|||||||
if (!useWiredMovements) {
|
if (!useWiredMovements) {
|
||||||
applyInstantCarryState(room, movingItem, targetTile, rotation, carryContext);
|
applyInstantCarryState(room, movingItem, targetTile, rotation, carryContext);
|
||||||
} else if (oldLocation != null) {
|
} else if (oldLocation != null) {
|
||||||
sendAnimatedMove(room, movingItem, oldLocation, oldZ, targetTile, rotation, carryContext, animationDuration);
|
sendAnimatedMove(room, movingItem, oldLocation, oldZ, targetTile, rotation, carryContext, animationDuration, (animationElapsedOverride != null) ? Math.max(0, animationElapsedOverride) : 0, anchorType, anchorId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -198,6 +218,165 @@ public final class WiredMoveCarryHelper {
|
|||||||
SUPPRESSED_STATUS_COMPOSER_UNTIL.remove(roomUnit.getId());
|
SUPPRESSED_STATUS_COMPOSER_UNTIL.remove(roomUnit.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void beginMovementCollection() {
|
||||||
|
COLLECTED_MOVEMENTS.set(new ArrayList<>());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ServerMessage finishMovementCollection() {
|
||||||
|
List<WiredMovementsComposer.MovementData> movements = COLLECTED_MOVEMENTS.get();
|
||||||
|
COLLECTED_MOVEMENTS.remove();
|
||||||
|
|
||||||
|
if (movements == null || movements.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new WiredMovementsComposer(movements).compose();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void registerUserFollower(Room room, HabboItem stackItem, HabboItem movingItem, RoomUnit targetUnit, Double zOverride, WiredContext ctx) {
|
||||||
|
if (room == null || stackItem == null || movingItem == null || targetUnit == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ACTIVE_USER_FOLLOWERS
|
||||||
|
.computeIfAbsent(targetUnit.getId(), key -> new ConcurrentHashMap<>())
|
||||||
|
.compute(movingItem.getId(), (key, existing) -> {
|
||||||
|
if (existing != null
|
||||||
|
&& existing.roomId == room.getId()
|
||||||
|
&& existing.stackItemId == stackItem.getId()) {
|
||||||
|
if (existing.zOverride == null && zOverride != null) {
|
||||||
|
existing.zOverride = zOverride;
|
||||||
|
}
|
||||||
|
existing.ctx = ctx;
|
||||||
|
existing.touch();
|
||||||
|
return existing;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new UserFollowEntry(
|
||||||
|
room.getId(),
|
||||||
|
stackItem.getId(),
|
||||||
|
movingItem.getId(),
|
||||||
|
zOverride,
|
||||||
|
ctx);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void markUserFollowerProcessed(RoomUnit targetUnit, HabboItem movingItem, long moveStatusTimestamp) {
|
||||||
|
if (targetUnit == null || movingItem == null || moveStatusTimestamp <= 0L) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ConcurrentHashMap<Integer, UserFollowEntry> followers = ACTIVE_USER_FOLLOWERS.get(targetUnit.getId());
|
||||||
|
if (followers == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
UserFollowEntry entry = followers.get(movingItem.getId());
|
||||||
|
if (entry == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
entry.markProcessed(moveStatusTimestamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isUserFollowerProcessed(RoomUnit targetUnit, HabboItem movingItem, long moveStatusTimestamp) {
|
||||||
|
if (targetUnit == null || movingItem == null || moveStatusTimestamp <= 0L) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ConcurrentHashMap<Integer, UserFollowEntry> followers = ACTIVE_USER_FOLLOWERS.get(targetUnit.getId());
|
||||||
|
if (followers == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
UserFollowEntry entry = followers.get(movingItem.getId());
|
||||||
|
if (entry == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return entry.lastProcessedMoveTimestamp == moveStatusTimestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void processUserFollowers(Room room, Collection<RoomUnit> roomUnits) {
|
||||||
|
if (room == null || roomUnits == null || roomUnits.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (RoomUnit roomUnit : roomUnits) {
|
||||||
|
if (roomUnit == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
ConcurrentHashMap<Integer, UserFollowEntry> followers = ACTIVE_USER_FOLLOWERS.get(roomUnit.getId());
|
||||||
|
if (followers == null || followers.isEmpty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!roomUnit.hasStatus(RoomUnitStatus.MOVE) || roomUnit.getCurrentLocation() == null) {
|
||||||
|
ACTIVE_USER_FOLLOWERS.remove(roomUnit.getId(), followers);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
long moveStatusTimestamp = roomUnit.getMoveStatusTimestamp();
|
||||||
|
List<Integer> toRemove = new ArrayList<>();
|
||||||
|
|
||||||
|
if (shouldSettleFollowersForNewStep(followers, moveStatusTimestamp)) {
|
||||||
|
settleUserFollowers(room, followers);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Map.Entry<Integer, UserFollowEntry>> orderedFollowers = new ArrayList<>(followers.entrySet());
|
||||||
|
orderedFollowers.sort(Comparator
|
||||||
|
.comparingDouble((Map.Entry<Integer, UserFollowEntry> followerEntry) -> {
|
||||||
|
UserFollowEntry entry = followerEntry.getValue();
|
||||||
|
return (entry != null && entry.zOverride != null) ? entry.zOverride : Double.MAX_VALUE;
|
||||||
|
})
|
||||||
|
.thenComparingInt(Map.Entry::getKey));
|
||||||
|
|
||||||
|
for (Map.Entry<Integer, UserFollowEntry> followerEntry : orderedFollowers) {
|
||||||
|
UserFollowEntry entry = followerEntry.getValue();
|
||||||
|
|
||||||
|
if (entry == null || entry.roomId != room.getId() || entry.expiresAt < System.currentTimeMillis()) {
|
||||||
|
toRemove.add(followerEntry.getKey());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
HabboItem stackItem = room.getHabboItem(entry.stackItemId);
|
||||||
|
HabboItem movingItem = room.getHabboItem(entry.movingItemId);
|
||||||
|
|
||||||
|
if (stackItem == null || movingItem == null) {
|
||||||
|
toRemove.add(followerEntry.getKey());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (moveStatusTimestamp <= 0L || moveStatusTimestamp == entry.lastProcessedMoveTimestamp) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int animationElapsed = resolveMoveStepElapsed(roomUnit);
|
||||||
|
int animationDuration = resolveMoveStepDuration(roomUnit);
|
||||||
|
Double targetZ = resolveFollowerStackZ(room, movingItem, roomUnit.getCurrentLocation(), movingItem.getRotation());
|
||||||
|
FurnitureMovementError error = moveFurni(room, stackItem, movingItem, roomUnit.getCurrentLocation(), movingItem.getRotation(), targetZ, null, false, entry.ctx, animationDuration, animationElapsed, WiredMovementsComposer.FURNI_ANCHOR_USER, roomUnit.getId());
|
||||||
|
|
||||||
|
if (error != FurnitureMovementError.NONE && entry.zOverride != null) {
|
||||||
|
error = moveFurni(room, stackItem, movingItem, roomUnit.getCurrentLocation(), movingItem.getRotation(), entry.zOverride, null, false, entry.ctx, animationDuration, animationElapsed, WiredMovementsComposer.FURNI_ANCHOR_USER, roomUnit.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error == FurnitureMovementError.INVALID_MOVE) {
|
||||||
|
toRemove.add(followerEntry.getKey());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
entry.markProcessed(moveStatusTimestamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Integer movingItemId : toRemove) {
|
||||||
|
followers.remove(movingItemId);
|
||||||
|
}
|
||||||
|
|
||||||
|
purgeExpiredFollowers(roomUnit.getId(), followers, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static boolean hasNoAnimationExtra(Room room, HabboItem stackItem) {
|
public static boolean hasNoAnimationExtra(Room room, HabboItem stackItem) {
|
||||||
return getNoAnimationExtra(room, stackItem) != null;
|
return getNoAnimationExtra(room, stackItem) != null;
|
||||||
}
|
}
|
||||||
@@ -207,6 +386,141 @@ public final class WiredMoveCarryHelper {
|
|||||||
return (extra != null) ? extra.getDurationMs() : fallbackDuration;
|
return (extra != null) ? extra.getDurationMs() : fallbackDuration;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static int resolveMoveStepElapsed(RoomUnit roomUnit) {
|
||||||
|
if (roomUnit == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
long moveStatusTimestamp = roomUnit.getMoveStatusTimestamp();
|
||||||
|
if (moveStatusTimestamp <= 0L) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (int) Math.max(0L, Math.min(WiredMovementsComposer.DEFAULT_DURATION, System.currentTimeMillis() - moveStatusTimestamp));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int resolveMoveStepDuration(RoomUnit roomUnit) {
|
||||||
|
return WiredMovementsComposer.DEFAULT_DURATION;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Double resolveFollowerStackZ(Room room, HabboItem movingItem, RoomTile targetTile, int rotation) {
|
||||||
|
if (room == null || movingItem == null || targetTile == null || room.getLayout() == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
double targetZ = room.getStackHeight(targetTile.x, targetTile.y, false, movingItem);
|
||||||
|
THashSet<RoomTile> occupiedTiles = room.getLayout().getTilesAt(
|
||||||
|
targetTile,
|
||||||
|
movingItem.getBaseItem().getWidth(),
|
||||||
|
movingItem.getBaseItem().getLength(),
|
||||||
|
rotation);
|
||||||
|
|
||||||
|
if (occupiedTiles == null || occupiedTiles.isEmpty()) {
|
||||||
|
return targetZ;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (RoomTile occupiedTile : occupiedTiles) {
|
||||||
|
if (occupiedTile == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
targetZ = Math.max(targetZ, room.getStackHeight(occupiedTile.x, occupiedTile.y, false, movingItem));
|
||||||
|
}
|
||||||
|
|
||||||
|
return targetZ;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Integer resolveRemainingMoveDuration(RoomUnit roomUnit, HabboItem stackItem, Room room) {
|
||||||
|
if (roomUnit == null || stackItem == null || room == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
long moveStatusTimestamp = roomUnit.getMoveStatusTimestamp();
|
||||||
|
if (moveStatusTimestamp <= 0L) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
int configuredDuration = getAnimationDuration(room, stackItem, WiredMovementsComposer.DEFAULT_DURATION);
|
||||||
|
int remainingStepDuration = (int) Math.max(50L, WiredMovementsComposer.DEFAULT_DURATION - Math.max(0L, System.currentTimeMillis() - moveStatusTimestamp));
|
||||||
|
return Math.min(configuredDuration, remainingStepDuration);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean shouldSettleFollowersForNewStep(ConcurrentHashMap<Integer, UserFollowEntry> followers, long moveStatusTimestamp) {
|
||||||
|
if (followers == null || followers.isEmpty() || moveStatusTimestamp <= 0L) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (UserFollowEntry entry : followers.values()) {
|
||||||
|
if (entry != null && entry.lastProcessedMoveTimestamp > 0L && entry.lastProcessedMoveTimestamp != moveStatusTimestamp) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void settleUserFollowers(Room room, ConcurrentHashMap<Integer, UserFollowEntry> followers) {
|
||||||
|
if (room == null || followers == null || followers.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Map.Entry<Integer, UserFollowEntry>> entriesToSettle = new ArrayList<>(followers.entrySet());
|
||||||
|
entriesToSettle.sort(Comparator
|
||||||
|
.comparingDouble((Map.Entry<Integer, UserFollowEntry> followerEntry) -> {
|
||||||
|
UserFollowEntry entry = followerEntry.getValue();
|
||||||
|
return (entry != null && entry.zOverride != null) ? -entry.zOverride : Double.POSITIVE_INFINITY;
|
||||||
|
})
|
||||||
|
.thenComparingInt(Map.Entry::getKey));
|
||||||
|
|
||||||
|
for (Map.Entry<Integer, UserFollowEntry> followerEntry : entriesToSettle) {
|
||||||
|
UserFollowEntry entry = followerEntry.getValue();
|
||||||
|
|
||||||
|
if (entry == null || entry.roomId != room.getId()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
HabboItem movingItem = room.getHabboItem(entry.movingItemId);
|
||||||
|
HabboItem stackItem = room.getHabboItem(entry.stackItemId);
|
||||||
|
if (movingItem == null || room.getLayout() == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
RoomTile currentTile = room.getLayout().getTile(movingItem.getX(), movingItem.getY());
|
||||||
|
if (currentTile == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Double targetZ = (double) room.getLayout().getHeightAtSquare(currentTile.x, currentTile.y);
|
||||||
|
|
||||||
|
if (stackItem != null) {
|
||||||
|
FurnitureMovementError error = moveFurni(room, stackItem, movingItem, currentTile, movingItem.getRotation(), targetZ, null, false, entry.ctx, WiredMovementsComposer.DEFAULT_DURATION, 0, WiredMovementsComposer.FURNI_ANCHOR_NONE, 0);
|
||||||
|
|
||||||
|
if (error == FurnitureMovementError.NONE) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FurnitureMovementError error = room.moveFurniTo(movingItem, currentTile, movingItem.getRotation(), targetZ, null, true, false);
|
||||||
|
|
||||||
|
if (error != FurnitureMovementError.NONE) {
|
||||||
|
room.moveFurniTo(movingItem, currentTile, movingItem.getRotation(), null, true, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void purgeExpiredFollowers(int roomUnitId, ConcurrentHashMap<Integer, UserFollowEntry> followers, boolean removeEmpty) {
|
||||||
|
if (followers == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
long now = System.currentTimeMillis();
|
||||||
|
followers.entrySet().removeIf(entry -> entry.getValue() == null || entry.getValue().expiresAt < now);
|
||||||
|
|
||||||
|
if (removeEmpty && followers.isEmpty()) {
|
||||||
|
ACTIVE_USER_FOLLOWERS.remove(roomUnitId, followers);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static boolean hasMovementBehaviorExtra(Room room, HabboItem stackItem) {
|
private static boolean hasMovementBehaviorExtra(Room room, HabboItem stackItem) {
|
||||||
THashSet<InteractionWiredExtra> extras = getMovementExtras(room, stackItem);
|
THashSet<InteractionWiredExtra> extras = getMovementExtras(room, stackItem);
|
||||||
if (extras == null || extras.isEmpty()) {
|
if (extras == null || extras.isEmpty()) {
|
||||||
@@ -370,7 +684,7 @@ public final class WiredMoveCarryHelper {
|
|||||||
return FurnitureMovementError.NONE;
|
return FurnitureMovementError.NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void sendAnimatedMove(Room room, HabboItem movingItem, RoomTile oldLocation, double oldZ, RoomTile targetTile, int rotation, CarryContext carryContext, int animationDuration) {
|
private static void sendAnimatedMove(Room room, HabboItem movingItem, RoomTile oldLocation, double oldZ, RoomTile targetTile, int rotation, CarryContext carryContext, int animationDuration, int animationElapsed, int anchorType, int anchorId) {
|
||||||
List<CarriedUnitMove> carriedMoves = getCarriedUnitMoves(room, movingItem, targetTile, rotation, carryContext);
|
List<CarriedUnitMove> carriedMoves = getCarriedUnitMoves(room, movingItem, targetTile, rotation, carryContext);
|
||||||
List<WiredMovementsComposer.MovementData> movements = new ArrayList<>();
|
List<WiredMovementsComposer.MovementData> movements = new ArrayList<>();
|
||||||
movements.add(WiredMovementsComposer.furniMovement(
|
movements.add(WiredMovementsComposer.furniMovement(
|
||||||
@@ -382,7 +696,10 @@ public final class WiredMoveCarryHelper {
|
|||||||
oldZ,
|
oldZ,
|
||||||
movingItem.getZ(),
|
movingItem.getZ(),
|
||||||
movingItem.getRotation(),
|
movingItem.getRotation(),
|
||||||
animationDuration));
|
animationDuration,
|
||||||
|
animationElapsed,
|
||||||
|
anchorType,
|
||||||
|
anchorId));
|
||||||
|
|
||||||
for (CarriedUnitMove carriedMove : carriedMoves) {
|
for (CarriedUnitMove carriedMove : carriedMoves) {
|
||||||
suppressStatusComposer(carriedMove.roomUnit, animationDuration);
|
suppressStatusComposer(carriedMove.roomUnit, animationDuration);
|
||||||
@@ -399,7 +716,13 @@ public final class WiredMoveCarryHelper {
|
|||||||
animationDuration));
|
animationDuration));
|
||||||
}
|
}
|
||||||
|
|
||||||
room.sendComposer(new WiredMovementsComposer(movements).compose());
|
List<WiredMovementsComposer.MovementData> collectedMovements = COLLECTED_MOVEMENTS.get();
|
||||||
|
|
||||||
|
if (collectedMovements != null) {
|
||||||
|
collectedMovements.addAll(movements);
|
||||||
|
} else {
|
||||||
|
room.sendComposer(new WiredMovementsComposer(movements).compose());
|
||||||
|
}
|
||||||
|
|
||||||
for (CarriedUnitMove carriedMove : carriedMoves) {
|
for (CarriedUnitMove carriedMove : carriedMoves) {
|
||||||
updateCarriedUnitState(carriedMove);
|
updateCarriedUnitState(carriedMove);
|
||||||
@@ -711,4 +1034,32 @@ public final class WiredMoveCarryHelper {
|
|||||||
this.newZ = newZ;
|
this.newZ = newZ;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final class UserFollowEntry {
|
||||||
|
private final int roomId;
|
||||||
|
private final int stackItemId;
|
||||||
|
private final int movingItemId;
|
||||||
|
private Double zOverride;
|
||||||
|
private WiredContext ctx;
|
||||||
|
private long expiresAt;
|
||||||
|
private long lastProcessedMoveTimestamp;
|
||||||
|
|
||||||
|
private UserFollowEntry(int roomId, int stackItemId, int movingItemId, Double zOverride, WiredContext ctx) {
|
||||||
|
this.roomId = roomId;
|
||||||
|
this.stackItemId = stackItemId;
|
||||||
|
this.movingItemId = movingItemId;
|
||||||
|
this.zOverride = zOverride;
|
||||||
|
this.ctx = ctx;
|
||||||
|
this.touch();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void markProcessed(long moveStatusTimestamp) {
|
||||||
|
this.lastProcessedMoveTimestamp = moveStatusTimestamp;
|
||||||
|
this.touch();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void touch() {
|
||||||
|
this.expiresAt = System.currentTimeMillis() + USER_FOLLOWER_TTL_MS;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import java.util.List;
|
|||||||
|
|
||||||
public final class WiredSourceUtil {
|
public final class WiredSourceUtil {
|
||||||
public static final int SOURCE_TRIGGER = 0;
|
public static final int SOURCE_TRIGGER = 0;
|
||||||
|
public static final int SOURCE_CLICKED_USER = 11;
|
||||||
public static final int SOURCE_SELECTED = 100;
|
public static final int SOURCE_SELECTED = 100;
|
||||||
public static final int SOURCE_SELECTOR = 200;
|
public static final int SOURCE_SELECTOR = 200;
|
||||||
public static final int SOURCE_SIGNAL = 201;
|
public static final int SOURCE_SIGNAL = 201;
|
||||||
@@ -54,6 +55,11 @@ public final class WiredSourceUtil {
|
|||||||
switch (sourceType) {
|
switch (sourceType) {
|
||||||
case SOURCE_TRIGGER:
|
case SOURCE_TRIGGER:
|
||||||
return ctx.actor().map(Collections::singletonList).orElse(Collections.emptyList());
|
return ctx.actor().map(Collections::singletonList).orElse(Collections.emptyList());
|
||||||
|
case SOURCE_CLICKED_USER:
|
||||||
|
if (ctx.eventType() == WiredEvent.Type.USER_CLICKS_USER) {
|
||||||
|
return ctx.event().getTargetUnit().map(Collections::singletonList).orElse(Collections.emptyList());
|
||||||
|
}
|
||||||
|
return Collections.emptyList();
|
||||||
case SOURCE_SELECTED:
|
case SOURCE_SELECTED:
|
||||||
return (selectedUsers != null) ? new ArrayList<>(selectedUsers) : Collections.emptyList();
|
return (selectedUsers != null) ? new ArrayList<>(selectedUsers) : Collections.emptyList();
|
||||||
case SOURCE_SELECTOR:
|
case SOURCE_SELECTOR:
|
||||||
@@ -71,6 +77,22 @@ public final class WiredSourceUtil {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean isDefaultUserSource(int value) {
|
||||||
|
switch (value) {
|
||||||
|
case SOURCE_TRIGGER:
|
||||||
|
case SOURCE_CLICKED_USER:
|
||||||
|
case SOURCE_SELECTOR:
|
||||||
|
case SOURCE_SIGNAL:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean isSelectableUserSource(int value) {
|
||||||
|
return value == SOURCE_SELECTED || isDefaultUserSource(value);
|
||||||
|
}
|
||||||
|
|
||||||
private static WiredTargets getSelectorTargets(WiredContext ctx) {
|
private static WiredTargets getSelectorTargets(WiredContext ctx) {
|
||||||
if (ctx == null) {
|
if (ctx == null) {
|
||||||
return new WiredTargets();
|
return new WiredTargets();
|
||||||
|
|||||||
+24
-3
@@ -13,6 +13,10 @@ public class WiredMovementsComposer extends MessageComposer {
|
|||||||
public static final int TYPE_WALL_ITEM_MOVE = 2;
|
public static final int TYPE_WALL_ITEM_MOVE = 2;
|
||||||
public static final int TYPE_USER_DIRECTION = 3;
|
public static final int TYPE_USER_DIRECTION = 3;
|
||||||
|
|
||||||
|
public static final int FURNI_ANCHOR_NONE = 0;
|
||||||
|
public static final int FURNI_ANCHOR_USER = 1;
|
||||||
|
public static final int FURNI_ANCHOR_FURNI = 2;
|
||||||
|
|
||||||
public static final int USER_MOVEMENT_WALK = 0;
|
public static final int USER_MOVEMENT_WALK = 0;
|
||||||
public static final int USER_MOVEMENT_SLIDE = 1;
|
public static final int USER_MOVEMENT_SLIDE = 1;
|
||||||
public static final int DEFAULT_DURATION = 500;
|
public static final int DEFAULT_DURATION = 500;
|
||||||
@@ -37,11 +41,19 @@ public class WiredMovementsComposer extends MessageComposer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static MovementData furniMovement(int id, int fromX, int fromY, int toX, int toY, double fromZ, double toZ) {
|
public static MovementData furniMovement(int id, int fromX, int fromY, int toX, int toY, double fromZ, double toZ) {
|
||||||
return furniMovement(id, fromX, fromY, toX, toY, fromZ, toZ, 0, DEFAULT_DURATION);
|
return furniMovement(id, fromX, fromY, toX, toY, fromZ, toZ, 0, DEFAULT_DURATION, 0, FURNI_ANCHOR_NONE, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static MovementData furniMovement(int id, int fromX, int fromY, int toX, int toY, double fromZ, double toZ, int rotation, int duration) {
|
public static MovementData furniMovement(int id, int fromX, int fromY, int toX, int toY, double fromZ, double toZ, int rotation, int duration) {
|
||||||
return new FurniMovementData(id, fromX, fromY, toX, toY, fromZ, toZ, rotation, duration);
|
return furniMovement(id, fromX, fromY, toX, toY, fromZ, toZ, rotation, duration, 0, FURNI_ANCHOR_NONE, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MovementData furniMovement(int id, int fromX, int fromY, int toX, int toY, double fromZ, double toZ, int rotation, int duration, int elapsed) {
|
||||||
|
return furniMovement(id, fromX, fromY, toX, toY, fromZ, toZ, rotation, duration, elapsed, FURNI_ANCHOR_NONE, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static MovementData furniMovement(int id, int fromX, int fromY, int toX, int toY, double fromZ, double toZ, int rotation, int duration, int elapsed, int anchorType, int anchorId) {
|
||||||
|
return new FurniMovementData(id, fromX, fromY, toX, toY, fromZ, toZ, rotation, duration, elapsed, anchorType, anchorId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static MovementData userWalkMovement(int id, int fromX, int fromY, int toX, int toY, double fromZ, double toZ, int bodyDirection, int headDirection, int duration) {
|
public static MovementData userWalkMovement(int id, int fromX, int fromY, int toX, int toY, double fromZ, double toZ, int bodyDirection, int headDirection, int duration) {
|
||||||
@@ -133,8 +145,11 @@ public class WiredMovementsComposer extends MessageComposer {
|
|||||||
private final int id;
|
private final int id;
|
||||||
private final int rotation;
|
private final int rotation;
|
||||||
private final int duration;
|
private final int duration;
|
||||||
|
private final int elapsed;
|
||||||
|
private final int anchorType;
|
||||||
|
private final int anchorId;
|
||||||
|
|
||||||
private FurniMovementData(int id, int fromX, int fromY, int toX, int toY, double fromZ, double toZ, int rotation, int duration) {
|
private FurniMovementData(int id, int fromX, int fromY, int toX, int toY, double fromZ, double toZ, int rotation, int duration, int elapsed, int anchorType, int anchorId) {
|
||||||
super(TYPE_FURNI_MOVE);
|
super(TYPE_FURNI_MOVE);
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.fromX = fromX;
|
this.fromX = fromX;
|
||||||
@@ -145,6 +160,9 @@ public class WiredMovementsComposer extends MessageComposer {
|
|||||||
this.toZ = toZ;
|
this.toZ = toZ;
|
||||||
this.rotation = rotation;
|
this.rotation = rotation;
|
||||||
this.duration = duration;
|
this.duration = duration;
|
||||||
|
this.elapsed = elapsed;
|
||||||
|
this.anchorType = anchorType;
|
||||||
|
this.anchorId = anchorId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -158,6 +176,9 @@ public class WiredMovementsComposer extends MessageComposer {
|
|||||||
response.appendInt(this.id);
|
response.appendInt(this.id);
|
||||||
response.appendInt(this.rotation);
|
response.appendInt(this.rotation);
|
||||||
response.appendInt(this.duration);
|
response.appendInt(this.duration);
|
||||||
|
response.appendInt(this.elapsed);
|
||||||
|
response.appendInt(this.anchorType);
|
||||||
|
response.appendInt(this.anchorId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user