This does not try to auto-repair the broken room layout. A room with bad
door coordinates is a database / model-authoring issue that needs to
be fixed at the source; this patch only stops the gameserver from
crashing on every entry attempt and leaving permanent ghost units
behind. The warning log line identifies the specific room id so the
operator can investigate which rooms are broken.
- Swap mysql-connector-j → mariadb-java-client in pom.xml
- Changed JDBC URL to jdbc:mariadb://
Add all the HikariCP properties above (configurable via config.ini with sensible defaults)
- Fix the double-close in Database.dispose()
The getCloneAccounts query had an operator-precedence bug:
WHERE ip_register = ? OR ip_current = ? AND id != ?
-- parsed as:
WHERE ip_register = ? OR (ip_current = ? AND id != ?)
So a user whose ip_register matched themselves would show up in their own clone list. Added parentheses:
WHERE (ip_register = ? OR ip_current = ?) AND id != ?
So please run the 006_HabboManager_fix before you run the update Emulator !
- add wf_xtra_text_output_furni_name and expand text placeholders for furni, users, bots and pets
- include room, entry, teleport and item metadata needed by the new :wired tools flow
- animate furniture position updates through the wired movement path
- fix teleport pair persistence/lookups for items_teleports with explicit column inserts
- Layout Cache (eliminates 1 DB query per room load)
Standard room models (model_a, model_b, etc.) are loaded once at startup and cached in memory
RoomLayout gets a new constructor from cached data instead of ResultSet
~99% of rooms use standard models, so this saves a DB round-trip on nearly every room load
- Better Parallel Pipeline (reduced critical path)
Before: layout → [items|rights|wordfilter] → heightmap → [bots|pets|wired]
After: layout → [items|rights|wordfilter|bots|pets] → [heightmap|wired]
Bots and pets only need layout for positioning, not items - so they now start immediately
Wired only needs items loaded (not heightmap) - so it now runs parallel with heightmap
- Deferred Promotion Query (faster Room instantiation)
Moved room_promotions DB query from constructor to loadDataInternal() as an async task
Room constructor now only runs bans query (needed for entry check)
Saves ~20ms per Room instantiation for promoted rooms
- Smart Heightmap (reduced tile iterations by 80-95%)
Instead of updating ALL tiles (1024 for 32x32 room), only updates tiles with items on them
Uses getTilesAt() for correct rotation-aware multi-tile coverage
For a room with 100 items on a 32x32 grid: ~200 tile updates instead of 1024
se this instead of this.client.getHabbo() since giveCredits() is already called on the Habbo instance itself. No need for the round-trip through the client.
- Room Cleanup Optimization (RoomManager.java)
Added roomsByOwner ConcurrentHashMap that tracks which rooms belong to which owner
clearInactiveRooms() now iterates unique owners instead of ALL rooms
Went from O(rooms × clients) to O(unique_owners × clients) every 120s
- Volatile Fields (Room.java)
Removed volatile from 27 room config fields (score, category, chatMode, allowPets, etc.)
Kept volatile only on 8 fields that genuinely need cross-thread visibility (loaded, preLoaded, needsUpdate, muted, etc.)
Reduces CPU cache line invalidation on every room cycle tick
- Search Cache TTL (SearchUserEvent.java + CleanerThread.java)
SearchUserEvent now has 30-second TTL per entry instead of full wipe every 10s
SearchRoomsEvent already had LRU eviction (max 200) — removed redundant .clear() call
Frequently searched users stay cached, only stale entries get cleaned
- scheduledComposers/scheduledTasks — After reading the code, these are actually already handled correctly: processScheduledTasks() swaps the set with a fresh one before processing, and processScheduledComposers() calls .clear() after sending. No leak risk.
1. HabboManager - O(1) username lookup
Before: getHabbo(String) held a synchronized lock and iterated ALL online users every call
After: Secondary ConcurrentHashMap<String, Habbo> keyed by lowercase username → instant get() lookup, no lock contention
2. ItemsComponent - Batch DB saves
Before: dispose() spawned a separate thread per dirty item, each opening its own DB connection
After: Single connection, JDBC addBatch()/executeBatch() for both UPDATE and DELETE, flushed every 100 items. A user with 500 dirty items now does 5 batch executions instead of 500 thread spawns + 500 connections.
3. AcceptFriendRequestEvent - N+1 elimination
Before: For each offline user: query 1 (getOfflineHabboInfo by ID) → query 2 (load full Habbo by username) = 2 queries × up to 100 users = 200 queries
After: Single query by user ID directly = 1 query × up to 100 users = 100 queries (50% reduction)
4. RoomManager - Direct HashMap lookup
Before: getCategory(int id) iterated all categories checking getId() == id even though the map is already keyed by ID
After: Direct roomCategories.get(id) → O(1) instead of O(n)