From 5172a74f61cc3e414e68e611d2831f30b6ed1c35 Mon Sep 17 00:00:00 2001 From: duckietm Date: Thu, 9 Apr 2026 11:47:53 +0200 Subject: [PATCH 1/3] =?UTF-8?q?=F0=9F=86=99=20Logic=20for=20the=20Youtube?= =?UTF-8?q?=20Broadcast?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/eu/habbo/habbohotel/rooms/Room.java | 25 +++++++++++- .../habbo/habbohotel/rooms/RoomManager.java | 11 ++++++ .../com/eu/habbo/messages/PacketManager.java | 4 ++ .../eu/habbo/messages/incoming/Incoming.java | 4 ++ .../rooms/youtube/YouTubeRoomPlayEvent.java | 39 +++++++++++++++++++ .../youtube/YouTubeRoomWatchingEvent.java | 30 ++++++++++++++ .../eu/habbo/messages/outgoing/Outgoing.java | 4 ++ .../youtube/YouTubeRoomBroadcastComposer.java | 31 +++++++++++++++ .../youtube/YouTubeRoomWatchersComposer.java | 25 ++++++++++++ 9 files changed, 172 insertions(+), 1 deletion(-) create mode 100644 Emulator/src/main/java/com/eu/habbo/messages/incoming/rooms/youtube/YouTubeRoomPlayEvent.java create mode 100644 Emulator/src/main/java/com/eu/habbo/messages/incoming/rooms/youtube/YouTubeRoomWatchingEvent.java create mode 100644 Emulator/src/main/java/com/eu/habbo/messages/outgoing/rooms/youtube/YouTubeRoomBroadcastComposer.java create mode 100644 Emulator/src/main/java/com/eu/habbo/messages/outgoing/rooms/youtube/YouTubeRoomWatchersComposer.java diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/rooms/Room.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/rooms/Room.java index b361a1c3..010cd15d 100644 --- a/Emulator/src/main/java/com/eu/habbo/habbohotel/rooms/Room.java +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/rooms/Room.java @@ -175,7 +175,30 @@ public class Room implements Comparable, ISerialize, Runnable { private volatile boolean muted; private RoomSpecialTypes roomSpecialTypes; private TraxManager traxManager; - + + private String youtubeCurrentVideo = ""; + private String youtubeSenderName = ""; + private final java.util.List youtubePlaylist = new java.util.concurrent.CopyOnWriteArrayList<>(); + private final java.util.Set youtubeWatchers = java.util.concurrent.ConcurrentHashMap.newKeySet(); + + public String getYoutubeCurrentVideo() { return this.youtubeCurrentVideo; } + public String getYoutubeSenderName() { return this.youtubeSenderName; } + public java.util.List getYoutubePlaylist() { return this.youtubePlaylist; } + public java.util.Set getYoutubeWatchers() { return this.youtubeWatchers; } + + public void setYoutubeVideo(String videoId, String senderName, java.util.List playlist) { + this.youtubeCurrentVideo = videoId; + this.youtubeSenderName = senderName; + this.youtubePlaylist.clear(); + if (playlist != null) this.youtubePlaylist.addAll(playlist); + } + + public void clearYoutubeVideo() { + this.youtubeCurrentVideo = ""; + this.youtubeSenderName = ""; + this.youtubePlaylist.clear(); + } + public final THashMap cache; public Room(ResultSet set) throws SQLException { diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/rooms/RoomManager.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/rooms/RoomManager.java index 2c92c4c3..527cb759 100644 --- a/Emulator/src/main/java/com/eu/habbo/habbohotel/rooms/RoomManager.java +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/rooms/RoomManager.java @@ -987,6 +987,17 @@ public class RoomManager { } } + if (!room.getYoutubeCurrentVideo().isEmpty()) { + habbo.getClient().sendResponse(new com.eu.habbo.messages.outgoing.rooms.youtube.YouTubeRoomBroadcastComposer( + room.getYoutubeCurrentVideo(), + room.getYoutubeSenderName(), + room.getYoutubePlaylist()).compose()); + } + if (!room.getYoutubeWatchers().isEmpty()) { + habbo.getClient().sendResponse(new com.eu.habbo.messages.outgoing.rooms.youtube.YouTubeRoomWatchersComposer( + room.getYoutubeWatchers()).compose()); + } + WiredManager.triggerUserEntersRoom(room, habbo.getRoomUnit()); room.habboEntered(habbo); diff --git a/Emulator/src/main/java/com/eu/habbo/messages/PacketManager.java b/Emulator/src/main/java/com/eu/habbo/messages/PacketManager.java index 18163a51..5d6296dc 100644 --- a/Emulator/src/main/java/com/eu/habbo/messages/PacketManager.java +++ b/Emulator/src/main/java/com/eu/habbo/messages/PacketManager.java @@ -677,5 +677,9 @@ public class PacketManager { this.registerHandler(Incoming.GameCenterLeaveGameEvent, GameCenterLeaveGameEvent.class); this.registerHandler(Incoming.GameCenterEvent, GameCenterEvent.class); this.registerHandler(Incoming.GameCenterRequestGameStatusEvent, GameCenterRequestGameStatusEvent.class); + + // YouTube Room Broadcast + this.registerHandler(Incoming.YouTubeRoomPlayEvent, com.eu.habbo.messages.incoming.rooms.youtube.YouTubeRoomPlayEvent.class); + this.registerHandler(Incoming.YouTubeRoomWatchingEvent, com.eu.habbo.messages.incoming.rooms.youtube.YouTubeRoomWatchingEvent.class); } } diff --git a/Emulator/src/main/java/com/eu/habbo/messages/incoming/Incoming.java b/Emulator/src/main/java/com/eu/habbo/messages/incoming/Incoming.java index 9b99e7ab..5324b750 100644 --- a/Emulator/src/main/java/com/eu/habbo/messages/incoming/Incoming.java +++ b/Emulator/src/main/java/com/eu/habbo/messages/incoming/Incoming.java @@ -436,4 +436,8 @@ public class Incoming { public static final int SetActivePrefixEvent = 7012; public static final int DeletePrefixEvent = 7013; public static final int PurchasePrefixEvent = 7014; + + // YouTube Room Broadcast + public static final int YouTubeRoomPlayEvent = 8001; + public static final int YouTubeRoomWatchingEvent = 8002; } diff --git a/Emulator/src/main/java/com/eu/habbo/messages/incoming/rooms/youtube/YouTubeRoomPlayEvent.java b/Emulator/src/main/java/com/eu/habbo/messages/incoming/rooms/youtube/YouTubeRoomPlayEvent.java new file mode 100644 index 00000000..892d68ff --- /dev/null +++ b/Emulator/src/main/java/com/eu/habbo/messages/incoming/rooms/youtube/YouTubeRoomPlayEvent.java @@ -0,0 +1,39 @@ +package com.eu.habbo.messages.incoming.rooms.youtube; + +import com.eu.habbo.habbohotel.rooms.Room; +import com.eu.habbo.habbohotel.users.Habbo; +import com.eu.habbo.messages.incoming.MessageHandler; +import com.eu.habbo.messages.outgoing.rooms.youtube.YouTubeRoomBroadcastComposer; + +import java.util.ArrayList; +import java.util.List; + +public class YouTubeRoomPlayEvent extends MessageHandler { + @Override + public void handle() throws Exception { + Habbo habbo = this.client.getHabbo(); + if (habbo == null) return; + + Room room = habbo.getHabboInfo().getCurrentRoom(); + if (room == null) return; + + // Only the room owner or users with rights can broadcast + if (!room.isOwner(habbo) && !room.hasRights(habbo)) return; + + String videoId = this.packet.readString(); + + int playlistCount = this.packet.readInt(); + List playlist = new ArrayList<>(); + for (int i = 0; i < playlistCount && i < 50; i++) { + playlist.add(this.packet.readString()); + } + + // Store the current video + playlist on the room + room.setYoutubeVideo(videoId, habbo.getHabboInfo().getUsername(), playlist); + + // Broadcast to everyone in the room + room.sendComposer( + new YouTubeRoomBroadcastComposer(videoId, habbo.getHabboInfo().getUsername(), playlist).compose() + ); + } +} diff --git a/Emulator/src/main/java/com/eu/habbo/messages/incoming/rooms/youtube/YouTubeRoomWatchingEvent.java b/Emulator/src/main/java/com/eu/habbo/messages/incoming/rooms/youtube/YouTubeRoomWatchingEvent.java new file mode 100644 index 00000000..670d9497 --- /dev/null +++ b/Emulator/src/main/java/com/eu/habbo/messages/incoming/rooms/youtube/YouTubeRoomWatchingEvent.java @@ -0,0 +1,30 @@ +package com.eu.habbo.messages.incoming.rooms.youtube; + +import com.eu.habbo.habbohotel.rooms.Room; +import com.eu.habbo.habbohotel.users.Habbo; +import com.eu.habbo.messages.incoming.MessageHandler; +import com.eu.habbo.messages.outgoing.rooms.youtube.YouTubeRoomWatchersComposer; + +public class YouTubeRoomWatchingEvent extends MessageHandler { + @Override + public void handle() throws Exception { + Habbo habbo = this.client.getHabbo(); + if (habbo == null) return; + + Room room = habbo.getHabboInfo().getCurrentRoom(); + if (room == null) return; + + boolean watching = this.packet.readBoolean(); + int userId = habbo.getHabboInfo().getId(); + + if (watching) { + room.getYoutubeWatchers().add(userId); + } else { + room.getYoutubeWatchers().remove(userId); + } + + room.sendComposer( + new YouTubeRoomWatchersComposer(room.getYoutubeWatchers()).compose() + ); + } +} diff --git a/Emulator/src/main/java/com/eu/habbo/messages/outgoing/Outgoing.java b/Emulator/src/main/java/com/eu/habbo/messages/outgoing/Outgoing.java index f354973e..bce53254 100644 --- a/Emulator/src/main/java/com/eu/habbo/messages/outgoing/Outgoing.java +++ b/Emulator/src/main/java/com/eu/habbo/messages/outgoing/Outgoing.java @@ -571,4 +571,8 @@ public class Outgoing { public static final int ActivePrefixUpdatedComposer = 7003; public static final int AvailableCommandsComposer = 4050; + // YouTube Room Broadcast + public static final int YouTubeRoomBroadcastComposer = 8001; + public static final int YouTubeRoomWatchersComposer = 8002; + } diff --git a/Emulator/src/main/java/com/eu/habbo/messages/outgoing/rooms/youtube/YouTubeRoomBroadcastComposer.java b/Emulator/src/main/java/com/eu/habbo/messages/outgoing/rooms/youtube/YouTubeRoomBroadcastComposer.java new file mode 100644 index 00000000..7f8680b3 --- /dev/null +++ b/Emulator/src/main/java/com/eu/habbo/messages/outgoing/rooms/youtube/YouTubeRoomBroadcastComposer.java @@ -0,0 +1,31 @@ +package com.eu.habbo.messages.outgoing.rooms.youtube; + +import com.eu.habbo.messages.ServerMessage; +import com.eu.habbo.messages.outgoing.MessageComposer; +import com.eu.habbo.messages.outgoing.Outgoing; + +import java.util.List; + +public class YouTubeRoomBroadcastComposer extends MessageComposer { + private final String videoId; + private final String senderName; + private final List playlist; + + public YouTubeRoomBroadcastComposer(String videoId, String senderName, List playlist) { + this.videoId = videoId; + this.senderName = senderName; + this.playlist = playlist; + } + + @Override + protected ServerMessage composeInternal() { + this.response.init(Outgoing.YouTubeRoomBroadcastComposer); + this.response.appendString(this.videoId); + this.response.appendString(this.senderName); + this.response.appendInt(this.playlist.size()); + for (String id : this.playlist) { + this.response.appendString(id); + } + return this.response; + } +} diff --git a/Emulator/src/main/java/com/eu/habbo/messages/outgoing/rooms/youtube/YouTubeRoomWatchersComposer.java b/Emulator/src/main/java/com/eu/habbo/messages/outgoing/rooms/youtube/YouTubeRoomWatchersComposer.java new file mode 100644 index 00000000..d57a3463 --- /dev/null +++ b/Emulator/src/main/java/com/eu/habbo/messages/outgoing/rooms/youtube/YouTubeRoomWatchersComposer.java @@ -0,0 +1,25 @@ +package com.eu.habbo.messages.outgoing.rooms.youtube; + +import com.eu.habbo.messages.ServerMessage; +import com.eu.habbo.messages.outgoing.MessageComposer; +import com.eu.habbo.messages.outgoing.Outgoing; + +import java.util.Set; + +public class YouTubeRoomWatchersComposer extends MessageComposer { + private final Set watcherIds; + + public YouTubeRoomWatchersComposer(Set watcherIds) { + this.watcherIds = watcherIds; + } + + @Override + protected ServerMessage composeInternal() { + this.response.init(Outgoing.YouTubeRoomWatchersComposer); + this.response.appendInt(this.watcherIds.size()); + for (int id : this.watcherIds) { + this.response.appendInt(id); + } + return this.response; + } +} From c5609ed00bdf656c3567e189c563701ee90fff18 Mon Sep 17 00:00:00 2001 From: duckietm Date: Thu, 9 Apr 2026 15:20:31 +0200 Subject: [PATCH 2/3] =?UTF-8?q?=F0=9F=86=99=20Added=20packet=20rate=20limi?= =?UTF-8?q?t=20=3D=3D>=2050=20p/s=20&=20youtube=20fixes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Database Updates/007_PackageRateLimit.sql | 1 + .../com/eu/habbo/habbohotel/rooms/Room.java | 136 ++++++++++-------- .../rooms/youtube/YouTubeRoomPlayEvent.java | 43 ++++-- .../youtube/YouTubeRoomWatchingEvent.java | 21 ++- .../decoders/GameMessageRateLimit.java | 25 +++- 5 files changed, 143 insertions(+), 83 deletions(-) create mode 100644 Database Updates/007_PackageRateLimit.sql diff --git a/Database Updates/007_PackageRateLimit.sql b/Database Updates/007_PackageRateLimit.sql new file mode 100644 index 00000000..00ca631d --- /dev/null +++ b/Database Updates/007_PackageRateLimit.sql @@ -0,0 +1 @@ +INSERT INTO emulator_settings (`key`, `value`) VALUES ('packet.global.rate.limit', '50'); \ No newline at end of file diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/rooms/Room.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/rooms/Room.java index 010cd15d..ac11d120 100644 --- a/Emulator/src/main/java/com/eu/habbo/habbohotel/rooms/Room.java +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/rooms/Room.java @@ -176,6 +176,8 @@ public class Room implements Comparable, ISerialize, Runnable { private RoomSpecialTypes roomSpecialTypes; private TraxManager traxManager; + // YouTube room broadcast state: tracks the current video being broadcast + // by the room owner, the owner's playlist, and which users have the player open. private String youtubeCurrentVideo = ""; private String youtubeSenderName = ""; private final java.util.List youtubePlaylist = new java.util.concurrent.CopyOnWriteArrayList<>(); @@ -187,16 +189,16 @@ public class Room implements Comparable, ISerialize, Runnable { public java.util.Set getYoutubeWatchers() { return this.youtubeWatchers; } public void setYoutubeVideo(String videoId, String senderName, java.util.List playlist) { - this.youtubeCurrentVideo = videoId; - this.youtubeSenderName = senderName; - this.youtubePlaylist.clear(); - if (playlist != null) this.youtubePlaylist.addAll(playlist); + this.youtubeCurrentVideo = videoId; + this.youtubeSenderName = senderName; + this.youtubePlaylist.clear(); + if (playlist != null) this.youtubePlaylist.addAll(playlist); } public void clearYoutubeVideo() { - this.youtubeCurrentVideo = ""; - this.youtubeSenderName = ""; - this.youtubePlaylist.clear(); + this.youtubeCurrentVideo = ""; + this.youtubeSenderName = ""; + this.youtubePlaylist.clear(); } public final THashMap cache; @@ -408,7 +410,7 @@ public class Room implements Comparable, ISerialize, Runnable { if (this.loaded || this.loadingInProgress || !this.preLoaded) { return; } - + this.loadingInProgress = true; this.loadingFuture = CompletableFuture.runAsync(() -> { this.loadDataInternal(); @@ -428,7 +430,7 @@ public class Room implements Comparable, ISerialize, Runnable { } future = this.loadingFuture; } - + if (future != null) { try { future.join(); @@ -443,7 +445,7 @@ public class Room implements Comparable, ISerialize, Runnable { public void loadData() { CompletableFuture futureToWait = null; boolean shouldLoad = false; - + synchronized (this.loadLock) { if (this.loadingInProgress) { // Get the future to wait on outside the lock @@ -453,7 +455,7 @@ public class Room implements Comparable, ISerialize, Runnable { shouldLoad = true; } } - + // Wait for existing load outside the lock if (futureToWait != null) { try { @@ -463,7 +465,7 @@ public class Room implements Comparable, ISerialize, Runnable { } return; } - + // Load if needed if (shouldLoad) { this.loadDataInternal(); @@ -503,7 +505,7 @@ public class Room implements Comparable, ISerialize, Runnable { CompletableFuture.runAsync(() -> { try (Connection promoConnection = Emulator.getDatabase().getDataSource().getConnection(); PreparedStatement stmt = promoConnection.prepareStatement( - "SELECT * FROM room_promotions WHERE room_id = ? AND end_timestamp > ? LIMIT 1")) { + "SELECT * FROM room_promotions WHERE room_id = ? AND end_timestamp > ? LIMIT 1")) { stmt.setInt(1, this.id); stmt.setInt(2, Emulator.getIntUnixTimestamp()); try (ResultSet promoSet = stmt.executeQuery()) { @@ -598,7 +600,7 @@ public class Room implements Comparable, ISerialize, Runnable { } this.roomCycleTask = Emulator.getThreading().getService() - .scheduleAtFixedRate(this, 500, 500, TimeUnit.MILLISECONDS); + .scheduleAtFixedRate(this, 500, 500, TimeUnit.MILLISECONDS); } catch (Exception e) { LOGGER.error("Caught exception during room load", e); } @@ -617,7 +619,7 @@ public class Room implements Comparable, ISerialize, Runnable { item.setExtradata("1"); this.updateItem(item); } - + // Set loaded flag with lock synchronized (this.loadLock) { this.loaded = true; @@ -634,7 +636,7 @@ public class Room implements Comparable, ISerialize, Runnable { this.layout = Emulator.getGameEnvironment().getRoomManager().loadCustomLayout(this); } else { this.layout = Emulator.getGameEnvironment().getRoomManager() - .loadLayout(this.layoutName, this); + .loadLayout(this.layoutName, this); } } } @@ -666,7 +668,7 @@ public class Room implements Comparable, ISerialize, Runnable { this.unitManager.clearBots(); try (PreparedStatement statement = connection.prepareStatement( - "SELECT users.username AS owner_name, bots.* FROM bots INNER JOIN users ON bots.user_id = users.id WHERE room_id = ?")) { + "SELECT users.username AS owner_name, bots.* FROM bots INNER JOIN users ON bots.user_id = users.id WHERE room_id = ?")) { statement.setInt(1, this.id); try (ResultSet set = statement.executeQuery()) { while (set.next()) { @@ -677,11 +679,11 @@ public class Room implements Comparable, ISerialize, Runnable { b.setRoomUnit(new RoomUnit()); b.getRoomUnit().setPathFinderRoom(this); b.getRoomUnit() - .setLocation(this.layout.getTile((short) set.getInt("x"), (short) set.getInt("y"))); + .setLocation(this.layout.getTile((short) set.getInt("x"), (short) set.getInt("y"))); if (b.getRoomUnit().getCurrentLocation() == null) { b.getRoomUnit().setLocation(this.getLayout().getDoorTile()); b.getRoomUnit() - .setRotation(RoomUserRotation.fromValue(this.getLayout().getDoorDirection())); + .setRotation(RoomUserRotation.fromValue(this.getLayout().getDoorDirection())); } else { b.getRoomUnit().setZ(set.getDouble("z")); b.getRoomUnit().setPreviousLocationZ(set.getDouble("z")); @@ -705,7 +707,7 @@ public class Room implements Comparable, ISerialize, Runnable { this.unitManager.clearPets(); try (PreparedStatement statement = connection.prepareStatement( - "SELECT users.username as pet_owner_name, users_pets.* FROM users_pets INNER JOIN users ON users_pets.user_id = users.id WHERE room_id = ?")) { + "SELECT users.username as pet_owner_name, users_pets.* FROM users_pets INNER JOIN users ON users_pets.user_id = users.id WHERE room_id = ?")) { statement.setInt(1, this.id); try (ResultSet set = statement.executeQuery()) { while (set.next()) { @@ -715,11 +717,11 @@ public class Room implements Comparable, ISerialize, Runnable { pet.setRoomUnit(new RoomUnit()); pet.getRoomUnit().setPathFinderRoom(this); pet.getRoomUnit() - .setLocation(this.layout.getTile((short) set.getInt("x"), (short) set.getInt("y"))); + .setLocation(this.layout.getTile((short) set.getInt("x"), (short) set.getInt("y"))); if (pet.getRoomUnit().getCurrentLocation() == null) { pet.getRoomUnit().setLocation(this.getLayout().getDoorTile()); pet.getRoomUnit() - .setRotation(RoomUserRotation.fromValue(this.getLayout().getDoorDirection())); + .setRotation(RoomUserRotation.fromValue(this.getLayout().getDoorDirection())); } else { pet.getRoomUnit().setZ(set.getDouble("z")); pet.getRoomUnit().setRotation(RoomUserRotation.values()[set.getInt("rot")]); @@ -791,7 +793,7 @@ public class Room implements Comparable, ISerialize, Runnable { THashSet updatedTiles = new THashSet<>(); Rectangle rectangle = RoomLayout.getRectangle(item.getX(), item.getY(), - item.getBaseItem().getWidth(), item.getBaseItem().getLength(), item.getRotation()); + item.getBaseItem().getWidth(), item.getBaseItem().getLength(), item.getRotation()); for (short x = (short) rectangle.x; x < rectangle.x + rectangle.getWidth(); x++) { for (short y = (short) rectangle.y; y < rectangle.y + rectangle.getHeight(); y++) { @@ -815,7 +817,7 @@ public class Room implements Comparable, ISerialize, Runnable { } Habbo habbo = (picker != null && picker.getHabboInfo().getId() == item.getId() ? picker - : Emulator.getGameServer().getGameClientManager().getHabbo(item.getUserId())); + : Emulator.getGameServer().getGameClientManager().getHabbo(item.getUserId())); if (habbo != null) { habbo.getInventory().getItemsComponent().addItem(item); habbo.getClient().sendResponse(new AddHabboItemComposer(item)); @@ -1053,7 +1055,7 @@ public class Room implements Comparable, ISerialize, Runnable { message.appendInt(this.category); String[] tags = Arrays.stream(this.tags.split(";")).filter(t -> !t.isEmpty()) - .toArray(String[]::new); + .toArray(String[]::new); message.appendInt(tags.length); for (String s : tags) { message.appendString(s); @@ -1117,8 +1119,8 @@ public class Room implements Comparable, ISerialize, Runnable { public void save() { if (this.needsUpdate) { try (Connection connection = Emulator.getDatabase().getDataSource() - .getConnection(); PreparedStatement statement = connection.prepareStatement( - "UPDATE rooms SET name = ?, description = ?, password = ?, state = ?, users_max = ?, category = ?, score = ?, paper_floor = ?, paper_wall = ?, paper_landscape = ?, thickness_wall = ?, wall_height = ?, thickness_floor = ?, moodlight_data = ?, tags = ?, allow_other_pets = ?, allow_other_pets_eat = ?, allow_walkthrough = ?, allow_hidewall = ?, chat_mode = ?, chat_weight = ?, chat_speed = ?, chat_hearing_distance = ?, chat_protection =?, who_can_mute = ?, who_can_kick = ?, who_can_ban = ?, poll_id = ?, guild_id = ?, roller_speed = ?, override_model = ?, is_staff_picked = ?, promoted = ?, trade_mode = ?, move_diagonally = ?, owner_id = ?, owner_name = ?, jukebox_active = ?, hidewired = ?, allow_underpass = ? WHERE id = ?")) { + .getConnection(); PreparedStatement statement = connection.prepareStatement( + "UPDATE rooms SET name = ?, description = ?, password = ?, state = ?, users_max = ?, category = ?, score = ?, paper_floor = ?, paper_wall = ?, paper_landscape = ?, thickness_wall = ?, wall_height = ?, thickness_floor = ?, moodlight_data = ?, tags = ?, allow_other_pets = ?, allow_other_pets_eat = ?, allow_walkthrough = ?, allow_hidewall = ?, chat_mode = ?, chat_weight = ?, chat_speed = ?, chat_hearing_distance = ?, chat_protection =?, who_can_mute = ?, who_can_kick = ?, who_can_ban = ?, poll_id = ?, guild_id = ?, roller_speed = ?, override_model = ?, is_staff_picked = ?, promoted = ?, trade_mode = ?, move_diagonally = ?, owner_id = ?, owner_name = ?, jukebox_active = ?, hidewired = ?, allow_underpass = ? WHERE id = ?")) { statement.setString(1, this.name); statement.setString(2, this.description); statement.setString(3, this.password); @@ -1183,8 +1185,8 @@ public class Room implements Comparable, ISerialize, Runnable { */ public void updateDatabaseUserCount() { try (Connection connection = Emulator.getDatabase().getDataSource() - .getConnection(); PreparedStatement statement = connection.prepareStatement( - "UPDATE rooms SET users = ? WHERE id = ? LIMIT 1")) { + .getConnection(); PreparedStatement statement = connection.prepareStatement( + "UPDATE rooms SET users = ? WHERE id = ? LIMIT 1")) { statement.setInt(1, this.getUserCount()); statement.setInt(2, this.id); statement.executeUpdate(); @@ -1498,7 +1500,7 @@ public class Room implements Comparable, ISerialize, Runnable { if (extraData.length == 4) { if (extraData[0].equalsIgnoreCase("1")) { return Color.getHSBColor(Integer.parseInt(extraData[1]), - Integer.parseInt(extraData[2]), Integer.parseInt(extraData[3])); + Integer.parseInt(extraData[2]), Integer.parseInt(extraData[3])); } } } @@ -1605,7 +1607,7 @@ public class Room implements Comparable, ISerialize, Runnable { public String[] filterAnything() { return new String[]{this.getOwnerName(), this.getGuildName(), this.getDescription(), - this.getPromotionDesc()}; + this.getPromotionDesc()}; } public long getCycleTimestamp() { @@ -1797,13 +1799,21 @@ public class Room implements Comparable, ISerialize, Runnable { } public void removeHabbo(Habbo habbo) { + this.cleanupYoutubeWatcher(habbo); this.unitManager.removeHabbo(habbo); } public void removeHabbo(Habbo habbo, boolean sendRemovePacket) { + this.cleanupYoutubeWatcher(habbo); this.unitManager.removeHabbo(habbo, sendRemovePacket); } + private void cleanupYoutubeWatcher(Habbo habbo) { + if (habbo != null && this.youtubeWatchers.remove(habbo.getHabboInfo().getId())) { + this.sendComposer(new com.eu.habbo.messages.outgoing.rooms.youtube.YouTubeRoomWatchersComposer(this.youtubeWatchers).compose()); + } + } + public void addBot(Bot bot) { this.unitManager.addBot(bot); } @@ -1939,7 +1949,7 @@ public class Room implements Comparable, ISerialize, Runnable { } public void talk(final Habbo habbo, final RoomChatMessage roomChatMessage, RoomChatType chatType, - boolean ignoreWired) { + boolean ignoreWired) { this.chatManager.talk(habbo, roomChatMessage, chatType, ignoreWired); } @@ -2084,7 +2094,7 @@ public class Room implements Comparable, ISerialize, Runnable { private void loadRights(Connection connection) { this.rights.clear(); try (PreparedStatement statement = connection.prepareStatement( - "SELECT user_id FROM room_rights WHERE room_id = ?")) { + "SELECT user_id FROM room_rights WHERE room_id = ?")) { statement.setInt(1, this.id); try (ResultSet set = statement.executeQuery()) { while (set.next()) { @@ -2100,7 +2110,7 @@ public class Room implements Comparable, ISerialize, Runnable { this.bannedHabbos.clear(); try (PreparedStatement statement = connection.prepareStatement( - "SELECT users.username, users.id, room_bans.* FROM room_bans INNER JOIN users ON room_bans.user_id = users.id WHERE ends > ? AND room_bans.room_id = ?")) { + "SELECT users.username, users.id, room_bans.* FROM room_bans INNER JOIN users ON room_bans.user_id = users.id WHERE ends > ? AND room_bans.room_id = ?")) { statement.setInt(1, Emulator.getIntUnixTimestamp()); statement.setInt(2, this.id); try (ResultSet set = statement.executeQuery()) { @@ -2122,7 +2132,7 @@ public class Room implements Comparable, ISerialize, Runnable { Guild guild = Emulator.getGameEnvironment().getGuildManager().getGuild(this.guild); if (Emulator.getGameEnvironment().getGuildManager().getOnlyAdmins(guild) - .get(habbo.getHabboInfo().getId()) != null) { + .get(habbo.getHabboInfo().getId()) != null) { return RoomRightLevels.GUILD_ADMIN; } @@ -2200,15 +2210,15 @@ public class Room implements Comparable, ISerialize, Runnable { } if (habbo.getRoomUnit().hasStatus(RoomUnitStatus.SIT) || !habbo.getRoomUnit() - .canForcePosture()) { + .canForcePosture()) { return; } this.dance(habbo, DanceType.NONE); habbo.getRoomUnit().cmdSit = true; habbo.getRoomUnit().setBodyRotation( - RoomUserRotation.values()[habbo.getRoomUnit().getBodyRotation().getValue() - - habbo.getRoomUnit().getBodyRotation().getValue() % 2]); + RoomUserRotation.values()[habbo.getRoomUnit().getBodyRotation().getValue() + - habbo.getRoomUnit().getBodyRotation().getValue() % 2]); habbo.getRoomUnit().setStatus(RoomUnitStatus.SIT, 0.5 + ""); this.sendComposer(new RoomUserStatusComposer(habbo.getRoomUnit()).compose()); WiredManager.triggerUserPerformsAction(this, habbo.getRoomUnit(), WiredUserActionType.SIT, -1); @@ -2222,11 +2232,11 @@ public class Room implements Comparable, ISerialize, Runnable { HabboItem item = this.getTopItemAt(habbo.getRoomUnit().getX(), habbo.getRoomUnit().getY()); if (item == null || !item.getBaseItem().allowSit() || !item.getBaseItem().allowLay()) { boolean wasSittingOrLaying = habbo.getRoomUnit().hasStatus(RoomUnitStatus.SIT) - || habbo.getRoomUnit().hasStatus(RoomUnitStatus.LAY); + || habbo.getRoomUnit().hasStatus(RoomUnitStatus.LAY); habbo.getRoomUnit().cmdStand = true; habbo.getRoomUnit().setBodyRotation( - RoomUserRotation.values()[habbo.getRoomUnit().getBodyRotation().getValue() - - habbo.getRoomUnit().getBodyRotation().getValue() % 2]); + RoomUserRotation.values()[habbo.getRoomUnit().getBodyRotation().getValue() + - habbo.getRoomUnit().getBodyRotation().getValue() % 2]); habbo.getRoomUnit().removeStatus(RoomUnitStatus.SIT); habbo.getRoomUnit().removeStatus(RoomUnitStatus.LAY); this.sendComposer(new RoomUserStatusComposer(habbo.getRoomUnit()).compose()); @@ -2260,9 +2270,9 @@ public class Room implements Comparable, ISerialize, Runnable { if (item.getBaseItem().getType() == FurnitureType.FLOOR) { this.sendComposer(new FloorItemUpdateComposer(item).compose()); this.updateTiles(this.getLayout() - .getTilesAt(this.layout.getTile(item.getX(), item.getY()), - item.getBaseItem().getWidth(), item.getBaseItem().getLength(), - item.getRotation())); + .getTilesAt(this.layout.getTile(item.getX(), item.getY()), + item.getBaseItem().getWidth(), item.getBaseItem().getLength(), + item.getRotation())); } else if (item.getBaseItem().getType() == FurnitureType.WALL) { this.sendComposer(new WallItemUpdateComposer(item).compose()); } @@ -2284,8 +2294,8 @@ public class Room implements Comparable, ISerialize, Runnable { } this.updateTiles(this.getLayout() - .getTilesAt(this.layout.getTile(item.getX(), item.getY()), item.getBaseItem().getWidth(), - item.getBaseItem().getLength(), item.getRotation())); + .getTilesAt(this.layout.getTile(item.getX(), item.getY()), item.getBaseItem().getWidth(), + item.getBaseItem().getLength(), item.getRotation())); if (item instanceof InteractionMultiHeight) { ((InteractionMultiHeight) item).updateUnitsOnItem(this); @@ -2322,18 +2332,18 @@ public class Room implements Comparable, ISerialize, Runnable { public void refreshGuild(Guild guild) { if (guild.getRoomId() == this.id) { THashSet members = Emulator.getGameEnvironment().getGuildManager() - .getGuildMembers(guild.getId()); + .getGuildMembers(guild.getId()); for (Habbo habbo : this.getHabbos()) { Optional member = members.stream() - .filter(m -> m.getUserId() == habbo.getHabboInfo().getId()).findAny(); + .filter(m -> m.getUserId() == habbo.getHabboInfo().getId()).findAny(); if (!member.isPresent()) { continue; } habbo.getClient() - .sendResponse(new GuildInfoComposer(guild, habbo.getClient(), false, member.get())); + .sendResponse(new GuildInfoComposer(guild, habbo.getClient(), false, member.get())); } } @@ -2368,7 +2378,7 @@ public class Room implements Comparable, ISerialize, Runnable { if (habbo.getHabboInfo().getCurrentRoom() == this) { if (habbo.getHabboInfo().getId() != this.ownerId) { if (!(habbo.hasPermission(Permission.ACC_ANYROOMOWNER) || habbo.hasPermission( - Permission.ACC_MOVEROTATE))) { + Permission.ACC_MOVEROTATE))) { this.refreshRightsForHabbo(habbo); } } @@ -2454,18 +2464,18 @@ public class Room implements Comparable, ISerialize, Runnable { } } else { this.sendComposer(new RoomFloorItemsComposer(this.itemManager.getFurniOwnerNames(), - this.roomSpecialTypes.getTriggers()).compose()); + this.roomSpecialTypes.getTriggers()).compose()); this.sendComposer(new RoomFloorItemsComposer(this.itemManager.getFurniOwnerNames(), - this.roomSpecialTypes.getEffects()).compose()); + this.roomSpecialTypes.getEffects()).compose()); this.sendComposer(new RoomFloorItemsComposer(this.itemManager.getFurniOwnerNames(), - this.roomSpecialTypes.getConditions()).compose()); + this.roomSpecialTypes.getConditions()).compose()); this.sendComposer(new RoomFloorItemsComposer(this.itemManager.getFurniOwnerNames(), - this.roomSpecialTypes.getExtras()).compose()); + this.roomSpecialTypes.getExtras()).compose()); } } public FurnitureMovementError canPlaceFurnitureAt(HabboItem item, Habbo habbo, RoomTile tile, - int rotation) { + int rotation) { return this.itemManager.canPlaceFurnitureAt(item, habbo, tile, rotation); } @@ -2474,17 +2484,17 @@ public class Room implements Comparable, ISerialize, Runnable { } public FurnitureMovementError furnitureFitsAt(RoomTile tile, HabboItem item, int rotation, - boolean checkForUnits) { + boolean checkForUnits) { return this.itemManager.furnitureFitsAt(tile, item, rotation, checkForUnits); } public FurnitureMovementError furnitureFitsAtWithPhysics(RoomTile tile, HabboItem item, int rotation, - boolean checkForUnits, WiredMovementPhysics physics) { + boolean checkForUnits, WiredMovementPhysics physics) { return this.itemManager.furnitureFitsAtWithPhysics(tile, item, rotation, checkForUnits, physics); } public FurnitureMovementError placeFloorFurniAt(HabboItem item, RoomTile tile, int rotation, - Habbo owner) { + Habbo owner) { return this.itemManager.placeFloorFurniAt(item, tile, rotation, owner); } @@ -2493,17 +2503,17 @@ public class Room implements Comparable, ISerialize, Runnable { } public FurnitureMovementError moveFurniTo(HabboItem item, RoomTile tile, int rotation, - Habbo actor) { + Habbo actor) { return this.itemManager.moveFurniTo(item, tile, rotation, actor); } public FurnitureMovementError moveFurniTo(HabboItem item, RoomTile tile, int rotation, - Habbo actor, boolean sendUpdates) { + Habbo actor, boolean sendUpdates) { return this.itemManager.moveFurniTo(item, tile, rotation, actor, sendUpdates); } public FurnitureMovementError moveFurniTo(HabboItem item, RoomTile tile, int rotation, - Habbo actor, boolean sendUpdates, boolean checkForUnits) { + Habbo actor, boolean sendUpdates, boolean checkForUnits) { return this.itemManager.moveFurniTo(item, tile, rotation, actor, sendUpdates, checkForUnits); } @@ -2520,12 +2530,12 @@ public class Room implements Comparable, ISerialize, Runnable { } public FurnitureMovementError moveFurniToWithPhysics(HabboItem item, RoomTile tile, int rotation, - Habbo actor, boolean sendUpdates, boolean checkForUnits, WiredMovementPhysics physics) { + Habbo actor, boolean sendUpdates, boolean checkForUnits, WiredMovementPhysics physics) { return this.itemManager.moveFurniToWithPhysics(item, tile, rotation, actor, sendUpdates, checkForUnits, physics); } public FurnitureMovementError moveFurniToWithPhysics(HabboItem item, RoomTile tile, int rotation, double z, - Habbo actor, boolean sendUpdates, boolean checkForUnits, WiredMovementPhysics physics) { + Habbo actor, boolean sendUpdates, boolean checkForUnits, WiredMovementPhysics physics) { return this.itemManager.moveFurniToWithPhysics(item, tile, rotation, z, actor, sendUpdates, checkForUnits, physics); } diff --git a/Emulator/src/main/java/com/eu/habbo/messages/incoming/rooms/youtube/YouTubeRoomPlayEvent.java b/Emulator/src/main/java/com/eu/habbo/messages/incoming/rooms/youtube/YouTubeRoomPlayEvent.java index 892d68ff..d5c5edf1 100644 --- a/Emulator/src/main/java/com/eu/habbo/messages/incoming/rooms/youtube/YouTubeRoomPlayEvent.java +++ b/Emulator/src/main/java/com/eu/habbo/messages/incoming/rooms/youtube/YouTubeRoomPlayEvent.java @@ -9,6 +9,17 @@ import java.util.ArrayList; import java.util.List; public class YouTubeRoomPlayEvent extends MessageHandler { + + private static final int MAX_VIDEO_ID_LENGTH = 100; + private static final int MAX_PLAYLIST_ITEM_LENGTH = 200; + private static final int MAX_PLAYLIST_SIZE = 50; + + @Override + public int getRatelimit() { + // Max 1 broadcast every 2 seconds per client + return 2000; + } + @Override public void handle() throws Exception { Habbo habbo = this.client.getHabbo(); @@ -21,19 +32,33 @@ public class YouTubeRoomPlayEvent extends MessageHandler { if (!room.isOwner(habbo) && !room.hasRights(habbo)) return; String videoId = this.packet.readString(); - - int playlistCount = this.packet.readInt(); - List playlist = new ArrayList<>(); - for (int i = 0; i < playlistCount && i < 50; i++) { - playlist.add(this.packet.readString()); + if (videoId.length() > MAX_VIDEO_ID_LENGTH) { + videoId = videoId.substring(0, MAX_VIDEO_ID_LENGTH); } - // Store the current video + playlist on the room - room.setYoutubeVideo(videoId, habbo.getHabboInfo().getUsername(), playlist); + int playlistCount = this.packet.readInt(); + if (playlistCount > MAX_PLAYLIST_SIZE) playlistCount = MAX_PLAYLIST_SIZE; + if (playlistCount < 0) playlistCount = 0; - // Broadcast to everyone in the room + List playlist = new ArrayList<>(); + for (int i = 0; i < playlistCount; i++) { + String item = this.packet.readString(); + if (item.length() > MAX_PLAYLIST_ITEM_LENGTH) { + item = item.substring(0, MAX_PLAYLIST_ITEM_LENGTH); + } + playlist.add(item); + } + + // Store the current video + playlist on the room, or clear if empty + if (videoId.isEmpty()) { + room.clearYoutubeVideo(); + } else { + room.setYoutubeVideo(videoId, habbo.getHabboInfo().getUsername(), playlist); + } + + // Broadcast to everyone in the room (empty videoId = stop) room.sendComposer( - new YouTubeRoomBroadcastComposer(videoId, habbo.getHabboInfo().getUsername(), playlist).compose() + new YouTubeRoomBroadcastComposer(videoId, habbo.getHabboInfo().getUsername(), playlist).compose() ); } } diff --git a/Emulator/src/main/java/com/eu/habbo/messages/incoming/rooms/youtube/YouTubeRoomWatchingEvent.java b/Emulator/src/main/java/com/eu/habbo/messages/incoming/rooms/youtube/YouTubeRoomWatchingEvent.java index 670d9497..3de11651 100644 --- a/Emulator/src/main/java/com/eu/habbo/messages/incoming/rooms/youtube/YouTubeRoomWatchingEvent.java +++ b/Emulator/src/main/java/com/eu/habbo/messages/incoming/rooms/youtube/YouTubeRoomWatchingEvent.java @@ -6,6 +6,12 @@ import com.eu.habbo.messages.incoming.MessageHandler; import com.eu.habbo.messages.outgoing.rooms.youtube.YouTubeRoomWatchersComposer; public class YouTubeRoomWatchingEvent extends MessageHandler { + + @Override + public int getRatelimit() { + return 500; + } + @Override public void handle() throws Exception { Habbo habbo = this.client.getHabbo(); @@ -14,17 +20,20 @@ public class YouTubeRoomWatchingEvent extends MessageHandler { Room room = habbo.getHabboInfo().getCurrentRoom(); if (room == null) return; - boolean watching = this.packet.readBoolean(); + boolean watching = this.packet.readInt() == 1; int userId = habbo.getHabboInfo().getId(); + boolean changed; if (watching) { - room.getYoutubeWatchers().add(userId); + changed = room.getYoutubeWatchers().add(userId); } else { - room.getYoutubeWatchers().remove(userId); + changed = room.getYoutubeWatchers().remove(userId); } - room.sendComposer( - new YouTubeRoomWatchersComposer(room.getYoutubeWatchers()).compose() - ); + if (changed) { + room.sendComposer( + new YouTubeRoomWatchersComposer(room.getYoutubeWatchers()).compose() + ); + } } } diff --git a/Emulator/src/main/java/com/eu/habbo/networking/gameserver/decoders/GameMessageRateLimit.java b/Emulator/src/main/java/com/eu/habbo/networking/gameserver/decoders/GameMessageRateLimit.java index 7a4c8de2..1b83a3ee 100644 --- a/Emulator/src/main/java/com/eu/habbo/networking/gameserver/decoders/GameMessageRateLimit.java +++ b/Emulator/src/main/java/com/eu/habbo/networking/gameserver/decoders/GameMessageRateLimit.java @@ -6,13 +6,18 @@ import com.eu.habbo.messages.ClientMessage; import com.eu.habbo.networking.gameserver.GameServerAttributes; import io.netty.channel.ChannelHandlerContext; import io.netty.handler.codec.MessageToMessageDecoder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.util.List; public class GameMessageRateLimit extends MessageToMessageDecoder { + private static final Logger LOGGER = LoggerFactory.getLogger(GameMessageRateLimit.class); + private static final int RESET_TIME = 1; private static final int MAX_COUNTER = 10; + private static final int DEFAULT_GLOBAL_MAX = 50; @Override protected void decode(ChannelHandlerContext ctx, ClientMessage message, List out) throws Exception { @@ -23,26 +28,36 @@ public class GameMessageRateLimit extends MessageToMessageDecoder } int count = 0; + int globalCount = 0; - // Check if reset time has passed. int timestamp = Emulator.getIntUnixTimestamp(); if (timestamp - client.lastPacketCounterCleared > RESET_TIME) { - // Reset counter. client.incomingPacketCounter.clear(); client.lastPacketCounterCleared = timestamp; } else { - // Get stored count for message id. count = client.incomingPacketCounter.getOrDefault(message.getMessageId(), 0); + for (int c : client.incomingPacketCounter.values()) { + globalCount += c; + } } - // If we exceeded the counter, drop the packet. if (count > MAX_COUNTER) { return; } + int globalMax = Emulator.getConfig().getInt("packet.global.rate.limit", DEFAULT_GLOBAL_MAX); + if (globalCount > globalMax) { + if (globalCount == globalMax + 1) { + String username = (client.getHabbo() != null && client.getHabbo().getHabboInfo() != null) + ? client.getHabbo().getHabboInfo().getUsername() : "unauthenticated"; + LOGGER.warn("Global packet rate limit exceeded for {} ({} packets/sec) — dropping excess packets", + username, globalCount); + } + return; + } + client.incomingPacketCounter.put(message.getMessageId(), ++count); - // Continue processing. out.add(message); } From 263408dbedf46b136ee69d1447c6654eda3a68a5 Mon Sep 17 00:00:00 2001 From: duckietm Date: Fri, 10 Apr 2026 09:05:21 +0200 Subject: [PATCH 3/3] =?UTF-8?q?=F0=9F=86=95=20YoutubeTV=20broadcasting?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Database Updates/007_PackageRateLimit.sql | 4 +- .../com/eu/habbo/habbohotel/rooms/Room.java | 145 ++++++++++-------- .../habbo/habbohotel/rooms/RoomManager.java | 4 +- .../com/eu/habbo/messages/PacketManager.java | 1 + .../eu/habbo/messages/incoming/Incoming.java | 1 + .../rooms/youtube/YouTubeRoomPlayEvent.java | 5 +- .../youtube/YouTubeRoomSettingsEvent.java | 35 +++++ .../eu/habbo/messages/outgoing/Outgoing.java | 1 + .../youtube/YouTubeRoomSettingsComposer.java | 20 +++ 9 files changed, 146 insertions(+), 70 deletions(-) create mode 100644 Emulator/src/main/java/com/eu/habbo/messages/incoming/rooms/youtube/YouTubeRoomSettingsEvent.java create mode 100644 Emulator/src/main/java/com/eu/habbo/messages/outgoing/rooms/youtube/YouTubeRoomSettingsComposer.java diff --git a/Database Updates/007_PackageRateLimit.sql b/Database Updates/007_PackageRateLimit.sql index 00ca631d..0e6ffbc8 100644 --- a/Database Updates/007_PackageRateLimit.sql +++ b/Database Updates/007_PackageRateLimit.sql @@ -1 +1,3 @@ -INSERT INTO emulator_settings (`key`, `value`) VALUES ('packet.global.rate.limit', '50'); \ No newline at end of file +INSERT INTO emulator_settings (`key`, `value`) VALUES ('packet.global.rate.limit', '50'); + +ALTER TABLE `rooms` ADD COLUMN IF NOT EXISTS `youtube_enabled` TINYINT(1) NOT NULL DEFAULT 0; \ No newline at end of file diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/rooms/Room.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/rooms/Room.java index ac11d120..af8c9b29 100644 --- a/Emulator/src/main/java/com/eu/habbo/habbohotel/rooms/Room.java +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/rooms/Room.java @@ -178,27 +178,30 @@ public class Room implements Comparable, ISerialize, Runnable { // YouTube room broadcast state: tracks the current video being broadcast // by the room owner, the owner's playlist, and which users have the player open. + private boolean youtubeEnabled = false; private String youtubeCurrentVideo = ""; private String youtubeSenderName = ""; private final java.util.List youtubePlaylist = new java.util.concurrent.CopyOnWriteArrayList<>(); private final java.util.Set youtubeWatchers = java.util.concurrent.ConcurrentHashMap.newKeySet(); + public boolean isYoutubeEnabled() { return this.youtubeEnabled; } + public void setYoutubeEnabled(boolean enabled) { this.youtubeEnabled = enabled; } public String getYoutubeCurrentVideo() { return this.youtubeCurrentVideo; } public String getYoutubeSenderName() { return this.youtubeSenderName; } public java.util.List getYoutubePlaylist() { return this.youtubePlaylist; } public java.util.Set getYoutubeWatchers() { return this.youtubeWatchers; } public void setYoutubeVideo(String videoId, String senderName, java.util.List playlist) { - this.youtubeCurrentVideo = videoId; - this.youtubeSenderName = senderName; - this.youtubePlaylist.clear(); - if (playlist != null) this.youtubePlaylist.addAll(playlist); + this.youtubeCurrentVideo = videoId; + this.youtubeSenderName = senderName; + this.youtubePlaylist.clear(); + if (playlist != null) this.youtubePlaylist.addAll(playlist); } public void clearYoutubeVideo() { - this.youtubeCurrentVideo = ""; - this.youtubeSenderName = ""; - this.youtubePlaylist.clear(); + this.youtubeCurrentVideo = ""; + this.youtubeSenderName = ""; + this.youtubePlaylist.clear(); } public final THashMap cache; @@ -228,6 +231,7 @@ public class Room implements Comparable, ISerialize, Runnable { this.allowPetsEat = set.getBoolean("allow_other_pets_eat"); this.allowWalkthrough = set.getBoolean("allow_walkthrough"); this.hideWall = set.getBoolean("allow_hidewall"); + try { this.youtubeEnabled = set.getBoolean("youtube_enabled"); } catch (Exception e) { this.youtubeEnabled = false; } this.chatMode = set.getInt("chat_mode"); this.chatWeight = set.getInt("chat_weight"); this.chatSpeed = set.getInt("chat_speed"); @@ -410,7 +414,7 @@ public class Room implements Comparable, ISerialize, Runnable { if (this.loaded || this.loadingInProgress || !this.preLoaded) { return; } - + this.loadingInProgress = true; this.loadingFuture = CompletableFuture.runAsync(() -> { this.loadDataInternal(); @@ -430,7 +434,7 @@ public class Room implements Comparable, ISerialize, Runnable { } future = this.loadingFuture; } - + if (future != null) { try { future.join(); @@ -445,7 +449,7 @@ public class Room implements Comparable, ISerialize, Runnable { public void loadData() { CompletableFuture futureToWait = null; boolean shouldLoad = false; - + synchronized (this.loadLock) { if (this.loadingInProgress) { // Get the future to wait on outside the lock @@ -455,7 +459,7 @@ public class Room implements Comparable, ISerialize, Runnable { shouldLoad = true; } } - + // Wait for existing load outside the lock if (futureToWait != null) { try { @@ -465,7 +469,7 @@ public class Room implements Comparable, ISerialize, Runnable { } return; } - + // Load if needed if (shouldLoad) { this.loadDataInternal(); @@ -505,7 +509,7 @@ public class Room implements Comparable, ISerialize, Runnable { CompletableFuture.runAsync(() -> { try (Connection promoConnection = Emulator.getDatabase().getDataSource().getConnection(); PreparedStatement stmt = promoConnection.prepareStatement( - "SELECT * FROM room_promotions WHERE room_id = ? AND end_timestamp > ? LIMIT 1")) { + "SELECT * FROM room_promotions WHERE room_id = ? AND end_timestamp > ? LIMIT 1")) { stmt.setInt(1, this.id); stmt.setInt(2, Emulator.getIntUnixTimestamp()); try (ResultSet promoSet = stmt.executeQuery()) { @@ -600,7 +604,7 @@ public class Room implements Comparable, ISerialize, Runnable { } this.roomCycleTask = Emulator.getThreading().getService() - .scheduleAtFixedRate(this, 500, 500, TimeUnit.MILLISECONDS); + .scheduleAtFixedRate(this, 500, 500, TimeUnit.MILLISECONDS); } catch (Exception e) { LOGGER.error("Caught exception during room load", e); } @@ -619,7 +623,7 @@ public class Room implements Comparable, ISerialize, Runnable { item.setExtradata("1"); this.updateItem(item); } - + // Set loaded flag with lock synchronized (this.loadLock) { this.loaded = true; @@ -636,7 +640,7 @@ public class Room implements Comparable, ISerialize, Runnable { this.layout = Emulator.getGameEnvironment().getRoomManager().loadCustomLayout(this); } else { this.layout = Emulator.getGameEnvironment().getRoomManager() - .loadLayout(this.layoutName, this); + .loadLayout(this.layoutName, this); } } } @@ -668,7 +672,7 @@ public class Room implements Comparable, ISerialize, Runnable { this.unitManager.clearBots(); try (PreparedStatement statement = connection.prepareStatement( - "SELECT users.username AS owner_name, bots.* FROM bots INNER JOIN users ON bots.user_id = users.id WHERE room_id = ?")) { + "SELECT users.username AS owner_name, bots.* FROM bots INNER JOIN users ON bots.user_id = users.id WHERE room_id = ?")) { statement.setInt(1, this.id); try (ResultSet set = statement.executeQuery()) { while (set.next()) { @@ -679,11 +683,11 @@ public class Room implements Comparable, ISerialize, Runnable { b.setRoomUnit(new RoomUnit()); b.getRoomUnit().setPathFinderRoom(this); b.getRoomUnit() - .setLocation(this.layout.getTile((short) set.getInt("x"), (short) set.getInt("y"))); + .setLocation(this.layout.getTile((short) set.getInt("x"), (short) set.getInt("y"))); if (b.getRoomUnit().getCurrentLocation() == null) { b.getRoomUnit().setLocation(this.getLayout().getDoorTile()); b.getRoomUnit() - .setRotation(RoomUserRotation.fromValue(this.getLayout().getDoorDirection())); + .setRotation(RoomUserRotation.fromValue(this.getLayout().getDoorDirection())); } else { b.getRoomUnit().setZ(set.getDouble("z")); b.getRoomUnit().setPreviousLocationZ(set.getDouble("z")); @@ -707,7 +711,7 @@ public class Room implements Comparable, ISerialize, Runnable { this.unitManager.clearPets(); try (PreparedStatement statement = connection.prepareStatement( - "SELECT users.username as pet_owner_name, users_pets.* FROM users_pets INNER JOIN users ON users_pets.user_id = users.id WHERE room_id = ?")) { + "SELECT users.username as pet_owner_name, users_pets.* FROM users_pets INNER JOIN users ON users_pets.user_id = users.id WHERE room_id = ?")) { statement.setInt(1, this.id); try (ResultSet set = statement.executeQuery()) { while (set.next()) { @@ -717,11 +721,11 @@ public class Room implements Comparable, ISerialize, Runnable { pet.setRoomUnit(new RoomUnit()); pet.getRoomUnit().setPathFinderRoom(this); pet.getRoomUnit() - .setLocation(this.layout.getTile((short) set.getInt("x"), (short) set.getInt("y"))); + .setLocation(this.layout.getTile((short) set.getInt("x"), (short) set.getInt("y"))); if (pet.getRoomUnit().getCurrentLocation() == null) { pet.getRoomUnit().setLocation(this.getLayout().getDoorTile()); pet.getRoomUnit() - .setRotation(RoomUserRotation.fromValue(this.getLayout().getDoorDirection())); + .setRotation(RoomUserRotation.fromValue(this.getLayout().getDoorDirection())); } else { pet.getRoomUnit().setZ(set.getDouble("z")); pet.getRoomUnit().setRotation(RoomUserRotation.values()[set.getInt("rot")]); @@ -793,7 +797,7 @@ public class Room implements Comparable, ISerialize, Runnable { THashSet updatedTiles = new THashSet<>(); Rectangle rectangle = RoomLayout.getRectangle(item.getX(), item.getY(), - item.getBaseItem().getWidth(), item.getBaseItem().getLength(), item.getRotation()); + item.getBaseItem().getWidth(), item.getBaseItem().getLength(), item.getRotation()); for (short x = (short) rectangle.x; x < rectangle.x + rectangle.getWidth(); x++) { for (short y = (short) rectangle.y; y < rectangle.y + rectangle.getHeight(); y++) { @@ -817,7 +821,7 @@ public class Room implements Comparable, ISerialize, Runnable { } Habbo habbo = (picker != null && picker.getHabboInfo().getId() == item.getId() ? picker - : Emulator.getGameServer().getGameClientManager().getHabbo(item.getUserId())); + : Emulator.getGameServer().getGameClientManager().getHabbo(item.getUserId())); if (habbo != null) { habbo.getInventory().getItemsComponent().addItem(item); habbo.getClient().sendResponse(new AddHabboItemComposer(item)); @@ -1055,7 +1059,7 @@ public class Room implements Comparable, ISerialize, Runnable { message.appendInt(this.category); String[] tags = Arrays.stream(this.tags.split(";")).filter(t -> !t.isEmpty()) - .toArray(String[]::new); + .toArray(String[]::new); message.appendInt(tags.length); for (String s : tags) { message.appendString(s); @@ -1119,8 +1123,8 @@ public class Room implements Comparable, ISerialize, Runnable { public void save() { if (this.needsUpdate) { try (Connection connection = Emulator.getDatabase().getDataSource() - .getConnection(); PreparedStatement statement = connection.prepareStatement( - "UPDATE rooms SET name = ?, description = ?, password = ?, state = ?, users_max = ?, category = ?, score = ?, paper_floor = ?, paper_wall = ?, paper_landscape = ?, thickness_wall = ?, wall_height = ?, thickness_floor = ?, moodlight_data = ?, tags = ?, allow_other_pets = ?, allow_other_pets_eat = ?, allow_walkthrough = ?, allow_hidewall = ?, chat_mode = ?, chat_weight = ?, chat_speed = ?, chat_hearing_distance = ?, chat_protection =?, who_can_mute = ?, who_can_kick = ?, who_can_ban = ?, poll_id = ?, guild_id = ?, roller_speed = ?, override_model = ?, is_staff_picked = ?, promoted = ?, trade_mode = ?, move_diagonally = ?, owner_id = ?, owner_name = ?, jukebox_active = ?, hidewired = ?, allow_underpass = ? WHERE id = ?")) { + .getConnection(); PreparedStatement statement = connection.prepareStatement( + "UPDATE rooms SET name = ?, description = ?, password = ?, state = ?, users_max = ?, category = ?, score = ?, paper_floor = ?, paper_wall = ?, paper_landscape = ?, thickness_wall = ?, wall_height = ?, thickness_floor = ?, moodlight_data = ?, tags = ?, allow_other_pets = ?, allow_other_pets_eat = ?, allow_walkthrough = ?, allow_hidewall = ?, chat_mode = ?, chat_weight = ?, chat_speed = ?, chat_hearing_distance = ?, chat_protection =?, who_can_mute = ?, who_can_kick = ?, who_can_ban = ?, poll_id = ?, guild_id = ?, roller_speed = ?, override_model = ?, is_staff_picked = ?, promoted = ?, trade_mode = ?, move_diagonally = ?, owner_id = ?, owner_name = ?, jukebox_active = ?, hidewired = ?, allow_underpass = ?, youtube_enabled = ? WHERE id = ?")) { statement.setString(1, this.name); statement.setString(2, this.description); statement.setString(3, this.password); @@ -1170,7 +1174,8 @@ public class Room implements Comparable, ISerialize, Runnable { statement.setString(38, this.jukeboxActive ? "1" : "0"); statement.setString(39, this.hideWired ? "1" : "0"); statement.setString(40, this.allowUnderpass ? "1" : "0"); - statement.setInt(41, this.id); + statement.setString(41, this.youtubeEnabled ? "1" : "0"); + statement.setInt(42, this.id); statement.executeUpdate(); this.needsUpdate = false; } catch (SQLException e) { @@ -1185,8 +1190,8 @@ public class Room implements Comparable, ISerialize, Runnable { */ public void updateDatabaseUserCount() { try (Connection connection = Emulator.getDatabase().getDataSource() - .getConnection(); PreparedStatement statement = connection.prepareStatement( - "UPDATE rooms SET users = ? WHERE id = ? LIMIT 1")) { + .getConnection(); PreparedStatement statement = connection.prepareStatement( + "UPDATE rooms SET users = ? WHERE id = ? LIMIT 1")) { statement.setInt(1, this.getUserCount()); statement.setInt(2, this.id); statement.executeUpdate(); @@ -1500,7 +1505,7 @@ public class Room implements Comparable, ISerialize, Runnable { if (extraData.length == 4) { if (extraData[0].equalsIgnoreCase("1")) { return Color.getHSBColor(Integer.parseInt(extraData[1]), - Integer.parseInt(extraData[2]), Integer.parseInt(extraData[3])); + Integer.parseInt(extraData[2]), Integer.parseInt(extraData[3])); } } } @@ -1607,7 +1612,7 @@ public class Room implements Comparable, ISerialize, Runnable { public String[] filterAnything() { return new String[]{this.getOwnerName(), this.getGuildName(), this.getDescription(), - this.getPromotionDesc()}; + this.getPromotionDesc()}; } public long getCycleTimestamp() { @@ -1809,7 +1814,17 @@ public class Room implements Comparable, ISerialize, Runnable { } private void cleanupYoutubeWatcher(Habbo habbo) { - if (habbo != null && this.youtubeWatchers.remove(habbo.getHabboInfo().getId())) { + if (habbo == null) return; + int userId = habbo.getHabboInfo().getId(); + + // If the broadcast sender leaves, stop the broadcast for everyone + if (!this.youtubeCurrentVideo.isEmpty() + && habbo.getHabboInfo().getUsername().equals(this.youtubeSenderName)) { + this.clearYoutubeVideo(); + this.sendComposer(new com.eu.habbo.messages.outgoing.rooms.youtube.YouTubeRoomBroadcastComposer("", "", java.util.Collections.emptyList()).compose()); + } + + if (this.youtubeWatchers.remove(userId)) { this.sendComposer(new com.eu.habbo.messages.outgoing.rooms.youtube.YouTubeRoomWatchersComposer(this.youtubeWatchers).compose()); } } @@ -1949,7 +1964,7 @@ public class Room implements Comparable, ISerialize, Runnable { } public void talk(final Habbo habbo, final RoomChatMessage roomChatMessage, RoomChatType chatType, - boolean ignoreWired) { + boolean ignoreWired) { this.chatManager.talk(habbo, roomChatMessage, chatType, ignoreWired); } @@ -2094,7 +2109,7 @@ public class Room implements Comparable, ISerialize, Runnable { private void loadRights(Connection connection) { this.rights.clear(); try (PreparedStatement statement = connection.prepareStatement( - "SELECT user_id FROM room_rights WHERE room_id = ?")) { + "SELECT user_id FROM room_rights WHERE room_id = ?")) { statement.setInt(1, this.id); try (ResultSet set = statement.executeQuery()) { while (set.next()) { @@ -2110,7 +2125,7 @@ public class Room implements Comparable, ISerialize, Runnable { this.bannedHabbos.clear(); try (PreparedStatement statement = connection.prepareStatement( - "SELECT users.username, users.id, room_bans.* FROM room_bans INNER JOIN users ON room_bans.user_id = users.id WHERE ends > ? AND room_bans.room_id = ?")) { + "SELECT users.username, users.id, room_bans.* FROM room_bans INNER JOIN users ON room_bans.user_id = users.id WHERE ends > ? AND room_bans.room_id = ?")) { statement.setInt(1, Emulator.getIntUnixTimestamp()); statement.setInt(2, this.id); try (ResultSet set = statement.executeQuery()) { @@ -2132,7 +2147,7 @@ public class Room implements Comparable, ISerialize, Runnable { Guild guild = Emulator.getGameEnvironment().getGuildManager().getGuild(this.guild); if (Emulator.getGameEnvironment().getGuildManager().getOnlyAdmins(guild) - .get(habbo.getHabboInfo().getId()) != null) { + .get(habbo.getHabboInfo().getId()) != null) { return RoomRightLevels.GUILD_ADMIN; } @@ -2210,15 +2225,15 @@ public class Room implements Comparable, ISerialize, Runnable { } if (habbo.getRoomUnit().hasStatus(RoomUnitStatus.SIT) || !habbo.getRoomUnit() - .canForcePosture()) { + .canForcePosture()) { return; } this.dance(habbo, DanceType.NONE); habbo.getRoomUnit().cmdSit = true; habbo.getRoomUnit().setBodyRotation( - RoomUserRotation.values()[habbo.getRoomUnit().getBodyRotation().getValue() - - habbo.getRoomUnit().getBodyRotation().getValue() % 2]); + RoomUserRotation.values()[habbo.getRoomUnit().getBodyRotation().getValue() + - habbo.getRoomUnit().getBodyRotation().getValue() % 2]); habbo.getRoomUnit().setStatus(RoomUnitStatus.SIT, 0.5 + ""); this.sendComposer(new RoomUserStatusComposer(habbo.getRoomUnit()).compose()); WiredManager.triggerUserPerformsAction(this, habbo.getRoomUnit(), WiredUserActionType.SIT, -1); @@ -2232,11 +2247,11 @@ public class Room implements Comparable, ISerialize, Runnable { HabboItem item = this.getTopItemAt(habbo.getRoomUnit().getX(), habbo.getRoomUnit().getY()); if (item == null || !item.getBaseItem().allowSit() || !item.getBaseItem().allowLay()) { boolean wasSittingOrLaying = habbo.getRoomUnit().hasStatus(RoomUnitStatus.SIT) - || habbo.getRoomUnit().hasStatus(RoomUnitStatus.LAY); + || habbo.getRoomUnit().hasStatus(RoomUnitStatus.LAY); habbo.getRoomUnit().cmdStand = true; habbo.getRoomUnit().setBodyRotation( - RoomUserRotation.values()[habbo.getRoomUnit().getBodyRotation().getValue() - - habbo.getRoomUnit().getBodyRotation().getValue() % 2]); + RoomUserRotation.values()[habbo.getRoomUnit().getBodyRotation().getValue() + - habbo.getRoomUnit().getBodyRotation().getValue() % 2]); habbo.getRoomUnit().removeStatus(RoomUnitStatus.SIT); habbo.getRoomUnit().removeStatus(RoomUnitStatus.LAY); this.sendComposer(new RoomUserStatusComposer(habbo.getRoomUnit()).compose()); @@ -2270,9 +2285,9 @@ public class Room implements Comparable, ISerialize, Runnable { if (item.getBaseItem().getType() == FurnitureType.FLOOR) { this.sendComposer(new FloorItemUpdateComposer(item).compose()); this.updateTiles(this.getLayout() - .getTilesAt(this.layout.getTile(item.getX(), item.getY()), - item.getBaseItem().getWidth(), item.getBaseItem().getLength(), - item.getRotation())); + .getTilesAt(this.layout.getTile(item.getX(), item.getY()), + item.getBaseItem().getWidth(), item.getBaseItem().getLength(), + item.getRotation())); } else if (item.getBaseItem().getType() == FurnitureType.WALL) { this.sendComposer(new WallItemUpdateComposer(item).compose()); } @@ -2294,8 +2309,8 @@ public class Room implements Comparable, ISerialize, Runnable { } this.updateTiles(this.getLayout() - .getTilesAt(this.layout.getTile(item.getX(), item.getY()), item.getBaseItem().getWidth(), - item.getBaseItem().getLength(), item.getRotation())); + .getTilesAt(this.layout.getTile(item.getX(), item.getY()), item.getBaseItem().getWidth(), + item.getBaseItem().getLength(), item.getRotation())); if (item instanceof InteractionMultiHeight) { ((InteractionMultiHeight) item).updateUnitsOnItem(this); @@ -2332,18 +2347,18 @@ public class Room implements Comparable, ISerialize, Runnable { public void refreshGuild(Guild guild) { if (guild.getRoomId() == this.id) { THashSet members = Emulator.getGameEnvironment().getGuildManager() - .getGuildMembers(guild.getId()); + .getGuildMembers(guild.getId()); for (Habbo habbo : this.getHabbos()) { Optional member = members.stream() - .filter(m -> m.getUserId() == habbo.getHabboInfo().getId()).findAny(); + .filter(m -> m.getUserId() == habbo.getHabboInfo().getId()).findAny(); if (!member.isPresent()) { continue; } habbo.getClient() - .sendResponse(new GuildInfoComposer(guild, habbo.getClient(), false, member.get())); + .sendResponse(new GuildInfoComposer(guild, habbo.getClient(), false, member.get())); } } @@ -2378,7 +2393,7 @@ public class Room implements Comparable, ISerialize, Runnable { if (habbo.getHabboInfo().getCurrentRoom() == this) { if (habbo.getHabboInfo().getId() != this.ownerId) { if (!(habbo.hasPermission(Permission.ACC_ANYROOMOWNER) || habbo.hasPermission( - Permission.ACC_MOVEROTATE))) { + Permission.ACC_MOVEROTATE))) { this.refreshRightsForHabbo(habbo); } } @@ -2464,18 +2479,18 @@ public class Room implements Comparable, ISerialize, Runnable { } } else { this.sendComposer(new RoomFloorItemsComposer(this.itemManager.getFurniOwnerNames(), - this.roomSpecialTypes.getTriggers()).compose()); + this.roomSpecialTypes.getTriggers()).compose()); this.sendComposer(new RoomFloorItemsComposer(this.itemManager.getFurniOwnerNames(), - this.roomSpecialTypes.getEffects()).compose()); + this.roomSpecialTypes.getEffects()).compose()); this.sendComposer(new RoomFloorItemsComposer(this.itemManager.getFurniOwnerNames(), - this.roomSpecialTypes.getConditions()).compose()); + this.roomSpecialTypes.getConditions()).compose()); this.sendComposer(new RoomFloorItemsComposer(this.itemManager.getFurniOwnerNames(), - this.roomSpecialTypes.getExtras()).compose()); + this.roomSpecialTypes.getExtras()).compose()); } } public FurnitureMovementError canPlaceFurnitureAt(HabboItem item, Habbo habbo, RoomTile tile, - int rotation) { + int rotation) { return this.itemManager.canPlaceFurnitureAt(item, habbo, tile, rotation); } @@ -2484,17 +2499,17 @@ public class Room implements Comparable, ISerialize, Runnable { } public FurnitureMovementError furnitureFitsAt(RoomTile tile, HabboItem item, int rotation, - boolean checkForUnits) { + boolean checkForUnits) { return this.itemManager.furnitureFitsAt(tile, item, rotation, checkForUnits); } public FurnitureMovementError furnitureFitsAtWithPhysics(RoomTile tile, HabboItem item, int rotation, - boolean checkForUnits, WiredMovementPhysics physics) { + boolean checkForUnits, WiredMovementPhysics physics) { return this.itemManager.furnitureFitsAtWithPhysics(tile, item, rotation, checkForUnits, physics); } public FurnitureMovementError placeFloorFurniAt(HabboItem item, RoomTile tile, int rotation, - Habbo owner) { + Habbo owner) { return this.itemManager.placeFloorFurniAt(item, tile, rotation, owner); } @@ -2503,17 +2518,17 @@ public class Room implements Comparable, ISerialize, Runnable { } public FurnitureMovementError moveFurniTo(HabboItem item, RoomTile tile, int rotation, - Habbo actor) { + Habbo actor) { return this.itemManager.moveFurniTo(item, tile, rotation, actor); } public FurnitureMovementError moveFurniTo(HabboItem item, RoomTile tile, int rotation, - Habbo actor, boolean sendUpdates) { + Habbo actor, boolean sendUpdates) { return this.itemManager.moveFurniTo(item, tile, rotation, actor, sendUpdates); } public FurnitureMovementError moveFurniTo(HabboItem item, RoomTile tile, int rotation, - Habbo actor, boolean sendUpdates, boolean checkForUnits) { + Habbo actor, boolean sendUpdates, boolean checkForUnits) { return this.itemManager.moveFurniTo(item, tile, rotation, actor, sendUpdates, checkForUnits); } @@ -2530,12 +2545,12 @@ public class Room implements Comparable, ISerialize, Runnable { } public FurnitureMovementError moveFurniToWithPhysics(HabboItem item, RoomTile tile, int rotation, - Habbo actor, boolean sendUpdates, boolean checkForUnits, WiredMovementPhysics physics) { + Habbo actor, boolean sendUpdates, boolean checkForUnits, WiredMovementPhysics physics) { return this.itemManager.moveFurniToWithPhysics(item, tile, rotation, actor, sendUpdates, checkForUnits, physics); } public FurnitureMovementError moveFurniToWithPhysics(HabboItem item, RoomTile tile, int rotation, double z, - Habbo actor, boolean sendUpdates, boolean checkForUnits, WiredMovementPhysics physics) { + Habbo actor, boolean sendUpdates, boolean checkForUnits, WiredMovementPhysics physics) { return this.itemManager.moveFurniToWithPhysics(item, tile, rotation, z, actor, sendUpdates, checkForUnits, physics); } diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/rooms/RoomManager.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/rooms/RoomManager.java index 527cb759..a65aefa2 100644 --- a/Emulator/src/main/java/com/eu/habbo/habbohotel/rooms/RoomManager.java +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/rooms/RoomManager.java @@ -790,7 +790,6 @@ public class RoomManager { habbo.getRoomUnit().setInvisible(false); room.addHabbo(habbo); - // Pre-send own wearing badges so the client cache is populated before the user clicks themselves habbo.getClient().sendResponse(new UserBadgesComposer(habbo.getInventory().getBadgesComponent().getWearingBadges(), habbo.getHabboInfo().getId())); List habbos = new ArrayList<>(); @@ -987,6 +986,9 @@ public class RoomManager { } } + habbo.getClient().sendResponse(new com.eu.habbo.messages.outgoing.rooms.youtube.YouTubeRoomSettingsComposer( + room.isYoutubeEnabled()).compose()); + if (!room.getYoutubeCurrentVideo().isEmpty()) { habbo.getClient().sendResponse(new com.eu.habbo.messages.outgoing.rooms.youtube.YouTubeRoomBroadcastComposer( room.getYoutubeCurrentVideo(), diff --git a/Emulator/src/main/java/com/eu/habbo/messages/PacketManager.java b/Emulator/src/main/java/com/eu/habbo/messages/PacketManager.java index 5d6296dc..919450b8 100644 --- a/Emulator/src/main/java/com/eu/habbo/messages/PacketManager.java +++ b/Emulator/src/main/java/com/eu/habbo/messages/PacketManager.java @@ -681,5 +681,6 @@ public class PacketManager { // YouTube Room Broadcast this.registerHandler(Incoming.YouTubeRoomPlayEvent, com.eu.habbo.messages.incoming.rooms.youtube.YouTubeRoomPlayEvent.class); this.registerHandler(Incoming.YouTubeRoomWatchingEvent, com.eu.habbo.messages.incoming.rooms.youtube.YouTubeRoomWatchingEvent.class); + this.registerHandler(Incoming.YouTubeRoomSettingsEvent, com.eu.habbo.messages.incoming.rooms.youtube.YouTubeRoomSettingsEvent.class); } } diff --git a/Emulator/src/main/java/com/eu/habbo/messages/incoming/Incoming.java b/Emulator/src/main/java/com/eu/habbo/messages/incoming/Incoming.java index 5324b750..a85d54fc 100644 --- a/Emulator/src/main/java/com/eu/habbo/messages/incoming/Incoming.java +++ b/Emulator/src/main/java/com/eu/habbo/messages/incoming/Incoming.java @@ -440,4 +440,5 @@ public class Incoming { // YouTube Room Broadcast public static final int YouTubeRoomPlayEvent = 8001; public static final int YouTubeRoomWatchingEvent = 8002; + public static final int YouTubeRoomSettingsEvent = 8003; } diff --git a/Emulator/src/main/java/com/eu/habbo/messages/incoming/rooms/youtube/YouTubeRoomPlayEvent.java b/Emulator/src/main/java/com/eu/habbo/messages/incoming/rooms/youtube/YouTubeRoomPlayEvent.java index d5c5edf1..1dec152a 100644 --- a/Emulator/src/main/java/com/eu/habbo/messages/incoming/rooms/youtube/YouTubeRoomPlayEvent.java +++ b/Emulator/src/main/java/com/eu/habbo/messages/incoming/rooms/youtube/YouTubeRoomPlayEvent.java @@ -27,8 +27,7 @@ public class YouTubeRoomPlayEvent extends MessageHandler { Room room = habbo.getHabboInfo().getCurrentRoom(); if (room == null) return; - - // Only the room owner or users with rights can broadcast + if (!room.isYoutubeEnabled()) return; if (!room.isOwner(habbo) && !room.hasRights(habbo)) return; String videoId = this.packet.readString(); @@ -58,7 +57,7 @@ public class YouTubeRoomPlayEvent extends MessageHandler { // Broadcast to everyone in the room (empty videoId = stop) room.sendComposer( - new YouTubeRoomBroadcastComposer(videoId, habbo.getHabboInfo().getUsername(), playlist).compose() + new YouTubeRoomBroadcastComposer(videoId, habbo.getHabboInfo().getUsername(), playlist).compose() ); } } diff --git a/Emulator/src/main/java/com/eu/habbo/messages/incoming/rooms/youtube/YouTubeRoomSettingsEvent.java b/Emulator/src/main/java/com/eu/habbo/messages/incoming/rooms/youtube/YouTubeRoomSettingsEvent.java new file mode 100644 index 00000000..b3f8ceb5 --- /dev/null +++ b/Emulator/src/main/java/com/eu/habbo/messages/incoming/rooms/youtube/YouTubeRoomSettingsEvent.java @@ -0,0 +1,35 @@ +package com.eu.habbo.messages.incoming.rooms.youtube; + +import com.eu.habbo.habbohotel.rooms.Room; +import com.eu.habbo.habbohotel.users.Habbo; +import com.eu.habbo.messages.incoming.MessageHandler; +import com.eu.habbo.messages.outgoing.rooms.youtube.YouTubeRoomBroadcastComposer; +import com.eu.habbo.messages.outgoing.rooms.youtube.YouTubeRoomSettingsComposer; + +public class YouTubeRoomSettingsEvent extends MessageHandler { + + @Override + public int getRatelimit() { + return 200; + } + + @Override + public void handle() throws Exception { + Habbo habbo = this.client.getHabbo(); + if (habbo == null) return; + + Room room = habbo.getHabboInfo().getCurrentRoom(); + if (room == null) return; + if (!room.isOwner(habbo)) return; + + boolean enabled = this.packet.readInt() == 1; + room.setYoutubeEnabled(enabled); + room.setNeedsUpdate(true); + room.sendComposer(new YouTubeRoomSettingsComposer(enabled).compose()); + + if (!enabled && !room.getYoutubeCurrentVideo().isEmpty()) { + room.clearYoutubeVideo(); + room.sendComposer(new YouTubeRoomBroadcastComposer("", "", java.util.Collections.emptyList()).compose()); + } + } +} diff --git a/Emulator/src/main/java/com/eu/habbo/messages/outgoing/Outgoing.java b/Emulator/src/main/java/com/eu/habbo/messages/outgoing/Outgoing.java index bce53254..386bf3b3 100644 --- a/Emulator/src/main/java/com/eu/habbo/messages/outgoing/Outgoing.java +++ b/Emulator/src/main/java/com/eu/habbo/messages/outgoing/Outgoing.java @@ -574,5 +574,6 @@ public class Outgoing { // YouTube Room Broadcast public static final int YouTubeRoomBroadcastComposer = 8001; public static final int YouTubeRoomWatchersComposer = 8002; + public static final int YouTubeRoomSettingsComposer = 8003; } diff --git a/Emulator/src/main/java/com/eu/habbo/messages/outgoing/rooms/youtube/YouTubeRoomSettingsComposer.java b/Emulator/src/main/java/com/eu/habbo/messages/outgoing/rooms/youtube/YouTubeRoomSettingsComposer.java new file mode 100644 index 00000000..64ff91cb --- /dev/null +++ b/Emulator/src/main/java/com/eu/habbo/messages/outgoing/rooms/youtube/YouTubeRoomSettingsComposer.java @@ -0,0 +1,20 @@ +package com.eu.habbo.messages.outgoing.rooms.youtube; + +import com.eu.habbo.messages.ServerMessage; +import com.eu.habbo.messages.outgoing.MessageComposer; +import com.eu.habbo.messages.outgoing.Outgoing; + +public class YouTubeRoomSettingsComposer extends MessageComposer { + private final boolean youtubeEnabled; + + public YouTubeRoomSettingsComposer(boolean youtubeEnabled) { + this.youtubeEnabled = youtubeEnabled; + } + + @Override + protected ServerMessage composeInternal() { + this.response.init(Outgoing.YouTubeRoomSettingsComposer); + this.response.appendInt(this.youtubeEnabled ? 1 : 0); + return this.response; + } +}