Merge pull request #49 from duckietm/dev

Dev
This commit is contained in:
DuckieTM
2026-03-26 10:48:02 +01:00
committed by GitHub
33 changed files with 1656 additions and 1453 deletions
-38
View File
@@ -1,38 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ChangeListManager">
<list default="true" id="ccf1bd3c-cd48-45b2-9a9d-461474e2ab14" name="Changes" comment="" />
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
<option name="LAST_RESOLUTION" value="IGNORE" />
</component>
<component name="Git.Settings">
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
</component>
<component name="MarkdownSettingsMigration">
<option name="stateVersion" value="1" />
</component>
<component name="ProjectId" id="2djKOc5iV19iK1uWSJto4t3tYDy" />
<component name="ProjectViewState">
<option name="hideEmptyMiddlePackages" value="true" />
<option name="showLibraryContents" value="true" />
</component>
<component name="PropertiesComponent"><![CDATA[{
"keyToString": {
"RunOnceActivity.OpenProjectViewOnStart": "true",
"RunOnceActivity.ShowReadmeOnStart": "true"
}
}]]></component>
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" />
<component name="TaskManager">
<task active="true" id="Default" summary="Default task">
<changelist id="ccf1bd3c-cd48-45b2-9a9d-461474e2ab14" name="Changes" comment="" />
<created>1710516016645</created>
<option name="number" value="Default" />
<option name="presentableId" value="Default" />
<updated>1710516016645</updated>
</task>
<servers />
</component>
</project>
@@ -0,0 +1,415 @@
-- =============================================================================
-- Consolidated Database Updates - All-in-One
-- =============================================================================
-- This file combines ALL individual update scripts from SQL/Database Updates/
-- into a single idempotent migration. Every statement is safe to re-run:
-- - ALTER TABLE ADD COLUMN IF NOT EXISTS (MariaDB 10.0+)
-- - ALTER TABLE CHANGE/MODIFY COLUMN IF EXISTS
-- - CREATE TABLE IF NOT EXISTS
-- - INSERT IGNORE / ON DUPLICATE KEY UPDATE for settings
-- - TRUNCATE + re-insert for reference data (breeding)
--
-- Run order: This file FIRST, then 001_optimize_gameserver.sql
--
-- Source files (in applied order):
-- 1. UpdateDatabase_Allow_diagonale.sql
-- 2. UpdateDatabase_BOT.sql
-- 3. UpdateDatabase_Banners.sql
-- 4. UpdateDatabase_DanceCMD.sql
-- 5. UpdateDatabase_Happiness.sql
-- 6. UpdateDatabase_Websocket.sql
-- 7. UpdateDatabase_unignorable.sql
-- 8. Default_Camera.sql
-- 9. 07012026_UpdateDatabase_to_4-0-1.sql
-- 10. 09012026_UpdateDatabase_to_4-0-2.sql
-- 11. 12012026_Battle Banzai.sql (same as #10, deduplicated)
-- 12. 12012026_Breeding Fixes.sql
-- 13. 12012026_ChatBubbles.sql
-- 14. 16032026_updateall_command.sql
-- 15. 17032026_allow_underpass.sql
-- 16. 19032026_hotel_timezone.sql
-- 17. 21022026_user_prefixes.sql
-- =============================================================================
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
SET @OLD_SQL_MODE = @@SQL_MODE;
SET SQL_MODE = 'NO_AUTO_VALUE_ON_ZERO';
-- =============================================================================
-- From: UpdateDatabase_Allow_diagonale.sql
-- =============================================================================
INSERT IGNORE INTO `emulator_settings` (`key`, `value`)
VALUES ('pathfinder.diagonal.enabled', '1');
-- =============================================================================
-- From: UpdateDatabase_BOT.sql
-- =============================================================================
INSERT IGNORE INTO `emulator_settings` (`key`, `value`)
VALUES ('hotel.bot.limit.walking.distance', '1');
INSERT IGNORE INTO `emulator_settings` (`key`, `value`)
VALUES ('hotel.bot.limit.walking.distance.radius', '5');
-- =============================================================================
-- From: UpdateDatabase_Banners.sql
-- =============================================================================
ALTER TABLE `users`
ADD COLUMN IF NOT EXISTS `background_id` INT(11) NOT NULL DEFAULT 0 AFTER `machine_id`,
ADD COLUMN IF NOT EXISTS `background_stand_id` INT(11) NOT NULL DEFAULT 0 AFTER `background_id`,
ADD COLUMN IF NOT EXISTS `background_overlay_id` INT(11) NOT NULL DEFAULT 0 AFTER `background_stand_id`;
-- =============================================================================
-- From: UpdateDatabase_DanceCMD.sql
-- =============================================================================
ALTER TABLE `permissions`
ADD COLUMN IF NOT EXISTS `cms_dance` ENUM('0','1') NULL DEFAULT '0' AFTER `cmd_credits`;
INSERT IGNORE INTO `emulator_texts` (`key`, `value`)
VALUES ('commands.description.cmd_dance', 'dance around the world ! use 1 t/m 4 and 0 to stop');
INSERT IGNORE INTO `emulator_texts` (`key`, `value`)
VALUES ('commands.keys.cmd_dance', 'dance');
-- =============================================================================
-- From: UpdateDatabase_Happiness.sql
-- =============================================================================
-- Rename key if the old one exists
UPDATE `emulator_texts`
SET `key` = 'generic.pet.happiness', `value` = 'Happiness'
WHERE `key` = 'generic.pet.happyness';
-- Rename columns (IF EXISTS prevents error if already renamed)
ALTER TABLE `pet_commands_data`
CHANGE COLUMN IF EXISTS `cost_happyness` `cost_happiness` int(11) NOT NULL DEFAULT '0';
ALTER TABLE `users_pets`
CHANGE COLUMN IF EXISTS `happyness` `happiness` int(11) NOT NULL DEFAULT '100';
-- =============================================================================
-- From: UpdateDatabase_Websocket.sql
-- =============================================================================
INSERT IGNORE INTO `emulator_settings` (`key`, `value`)
VALUES ('websockets.whitelist', 'localhost');
INSERT IGNORE INTO `emulator_settings` (`key`, `value`)
VALUES ('ws.nitro.host', '0.0.0.0');
INSERT IGNORE INTO `emulator_settings` (`key`, `value`)
VALUES ('ws.nitro.ip.header', '');
INSERT IGNORE INTO `emulator_settings` (`key`, `value`)
VALUES ('ws.nitro.port', '2096');
-- =============================================================================
-- From: UpdateDatabase_unignorable.sql
-- =============================================================================
ALTER TABLE `permissions`
ADD COLUMN IF NOT EXISTS `acc_unignorable` ENUM('0','1') NOT NULL DEFAULT '0';
-- =============================================================================
-- From: Default_Camera.sql
-- =============================================================================
CREATE TABLE IF NOT EXISTS `camera_web` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`user_id` INT(11) NOT NULL,
`room_id` INT(11) NOT NULL DEFAULT 0,
`timestamp` INT(11) NOT NULL DEFAULT 0,
`url` VARCHAR(255) NOT NULL DEFAULT '',
PRIMARY KEY (`id`),
INDEX `idx_camera_web_user_id` (`user_id`),
INDEX `idx_camera_web_timestamp` (`timestamp`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- Camera emulator settings
INSERT IGNORE INTO `emulator_settings` (`key`, `value`) VALUES
('camera.url', 'http://localhost/camera/');
INSERT IGNORE INTO `emulator_settings` (`key`, `value`) VALUES
('imager.location.output.camera', '/path/to/www/camera/');
INSERT IGNORE INTO `emulator_settings` (`key`, `value`) VALUES
('imager.location.output.thumbnail', '/path/to/www/thumbnails/');
INSERT IGNORE INTO `emulator_settings` (`key`, `value`) VALUES
('camera.item_id', '0');
INSERT IGNORE INTO `emulator_settings` (`key`, `value`) VALUES
('camera.price.credits', '2');
INSERT IGNORE INTO `emulator_settings` (`key`, `value`) VALUES
('camera.price.points', '0');
INSERT IGNORE INTO `emulator_settings` (`key`, `value`) VALUES
('camera.price.points.publish', '1');
INSERT IGNORE INTO `emulator_settings` (`key`, `value`) VALUES
('camera.extradata', '{"t":"%timestamp%","u":"%id%","m":"","s":"%room_id%","w":"%url%"}');
-- Camera emulator texts
INSERT IGNORE INTO `emulator_texts` (`key`, `value`) VALUES
('camera.permission', 'You do not have permission to use the camera.');
INSERT IGNORE INTO `emulator_texts` (`key`, `value`) VALUES
('camera.wait', 'Please wait %seconds% more seconds before taking another photo.');
INSERT IGNORE INTO `emulator_texts` (`key`, `value`) VALUES
('camera.error.creation', 'An error occurred while processing your photo. Please try again.');
INSERT IGNORE INTO `emulator_texts` (`key`, `value`) VALUES
('camera.daily.limit', 'You have reached the daily photo limit. Try again tomorrow.');
-- =============================================================================
-- From: 07012026_UpdateDatabase_to_4-0-1.sql
-- =============================================================================
-- Wired abuse protection settings
INSERT INTO `emulator_settings` (`key`, `value`) VALUES
('wired.abuse.max.recursion.depth', '10')
ON DUPLICATE KEY UPDATE `key` = `key`;
INSERT INTO `emulator_settings` (`key`, `value`) VALUES
('wired.abuse.max.events.per.window', '100')
ON DUPLICATE KEY UPDATE `key` = `key`;
INSERT INTO `emulator_settings` (`key`, `value`) VALUES
('wired.abuse.rate.limit.window.ms', '10000')
ON DUPLICATE KEY UPDATE `key` = `key`;
INSERT INTO `emulator_settings` (`key`, `value`) VALUES
('wired.abuse.ban.duration.ms', '600000')
ON DUPLICATE KEY UPDATE `key` = `key`;
-- Wired abuse texts
INSERT INTO `emulator_texts` (`key`, `value`) VALUES
('wired.abuse.room.alert', 'Wired execution has been temporarily disabled in this room due to abuse detection. It will resume in %minutes% minutes.')
ON DUPLICATE KEY UPDATE `key` = `key`;
INSERT INTO `emulator_texts` (`key`, `value`) VALUES
('wired.abuse.staff.title', 'Wired Abuse Detected')
ON DUPLICATE KEY UPDATE `key` = `key`;
INSERT INTO `emulator_texts` (`key`, `value`) VALUES
('wired.abuse.staff.message', 'Room: %roomname%\nOwner: %owner%\nBanned for %minutes% minutes.')
ON DUPLICATE KEY UPDATE `key` = `key`;
INSERT INTO `emulator_texts` (`key`, `value`) VALUES
('wired.abuse.staff.link', 'Go to Room')
ON DUPLICATE KEY UPDATE `key` = `key`;
-- Wired tick resolution
INSERT INTO `emulator_settings` (`key`, `value`) VALUES
('wired.tick.resolution', '100')
ON DUPLICATE KEY UPDATE `key` = `key`;
-- Wired engine configuration
INSERT INTO `emulator_settings` (`key`, `value`) VALUES
('wired.engine.enabled', '0'),
('wired.engine.exclusive', '0'),
('wired.engine.maxStepsPerStack', '100'),
('wired.engine.debug', '0')
ON DUPLICATE KEY UPDATE `key` = `key`;
-- Wired tick system configuration
INSERT INTO `emulator_settings` (`key`, `value`) VALUES
('wired.tick.interval.ms', '50'),
('wired.tick.debug', '0'),
('wired.tick.thread.priority', '6')
ON DUPLICATE KEY UPDATE `key` = `key`;
-- Pathfinder settings
INSERT INTO `emulator_settings` (`key`, `value`) VALUES
('pathfinder.click.delay', '0')
ON DUPLICATE KEY UPDATE `key` = `key`;
INSERT INTO `emulator_settings` (`key`, `value`) VALUES
('pathfinder.retro-style.diagonals', '0')
ON DUPLICATE KEY UPDATE `key` = `key`;
INSERT INTO `emulator_settings` (`key`, `value`) VALUES
('pathfinder.step.allow.falling', '1')
ON DUPLICATE KEY UPDATE `key` = `key`;
-- =============================================================================
-- From: 09012026_UpdateDatabase_to_4-0-2.sql + 12012026_Battle Banzai.sql
-- (These two files are identical - deduplicated here)
-- =============================================================================
INSERT INTO `emulator_settings` (`key`, `value`) VALUES
('hotel.banzai.fill.max_queue', '50'),
('hotel.banzai.fill.cooldown_ms', '100')
ON DUPLICATE KEY UPDATE `value` = VALUES(`value`);
-- =============================================================================
-- From: 12012026_Breeding Fixes.sql
-- =============================================================================
-- Recreate pet_breeding with correct structure
CREATE TABLE IF NOT EXISTS `pet_breeding` (
`pet_id` int(11) NOT NULL COMMENT 'Parent pet type',
`offspring_id` int(11) NOT NULL COMMENT 'Baby pet type',
PRIMARY KEY (`pet_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
TRUNCATE TABLE `pet_breeding`;
INSERT INTO `pet_breeding` (`pet_id`, `offspring_id`) VALUES
(0, 29), -- Dog -> Baby Dog
(1, 28), -- Cat -> Baby Cat
(3, 25), -- Terrier -> Baby Terrier
(4, 24), -- Bear -> Baby Bear
(5, 30); -- Pig -> Baby Pig
-- Recreate pet_breeding_races with correct structure
CREATE TABLE IF NOT EXISTS `pet_breeding_races` (
`pet_type` int(11) NOT NULL COMMENT 'Baby pet type (offspring)',
`rarity_level` int(11) NOT NULL COMMENT '1=Common, 2=Uncommon, 3=Rare, 4=Epic',
`breed` int(11) NOT NULL COMMENT 'Visual breed/color variant',
PRIMARY KEY (`pet_type`, `rarity_level`, `breed`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
TRUNCATE TABLE `pet_breeding_races`;
-- Baby Dog (29) - Offspring of Dog (0)
INSERT INTO `pet_breeding_races` (`pet_type`, `rarity_level`, `breed`) VALUES
(29, 1, 0), (29, 1, 1), (29, 1, 2), (29, 1, 3),
(29, 1, 4), (29, 1, 5), (29, 1, 6), (29, 1, 7),
(29, 2, 8), (29, 2, 9), (29, 2, 10), (29, 2, 11), (29, 2, 12),
(29, 3, 13), (29, 3, 14), (29, 3, 15), (29, 3, 16),
(29, 4, 17), (29, 4, 18), (29, 4, 19);
-- Baby Cat (28) - Offspring of Cat (1)
INSERT INTO `pet_breeding_races` (`pet_type`, `rarity_level`, `breed`) VALUES
(28, 1, 0), (28, 1, 1), (28, 1, 2), (28, 1, 3),
(28, 1, 4), (28, 1, 5), (28, 1, 6), (28, 1, 7),
(28, 2, 8), (28, 2, 9), (28, 2, 10), (28, 2, 11), (28, 2, 12),
(28, 3, 13), (28, 3, 14), (28, 3, 15), (28, 3, 16),
(28, 4, 17), (28, 4, 18), (28, 4, 19);
-- Baby Terrier (25) - Offspring of Terrier (3)
INSERT INTO `pet_breeding_races` (`pet_type`, `rarity_level`, `breed`) VALUES
(25, 1, 0), (25, 1, 1), (25, 1, 2), (25, 1, 3),
(25, 1, 4), (25, 1, 5), (25, 1, 6), (25, 1, 7),
(25, 2, 8), (25, 2, 9), (25, 2, 10), (25, 2, 11), (25, 2, 12),
(25, 3, 13), (25, 3, 14), (25, 3, 15), (25, 3, 16),
(25, 4, 17), (25, 4, 18), (25, 4, 19);
-- Baby Bear (24) - Offspring of Bear (4)
INSERT INTO `pet_breeding_races` (`pet_type`, `rarity_level`, `breed`) VALUES
(24, 1, 0), (24, 1, 1), (24, 1, 2), (24, 1, 3),
(24, 1, 4), (24, 1, 5), (24, 1, 6), (24, 1, 7),
(24, 2, 8), (24, 2, 9), (24, 2, 10), (24, 2, 11), (24, 2, 12),
(24, 3, 13), (24, 3, 14), (24, 3, 15), (24, 3, 16),
(24, 4, 17), (24, 4, 18), (24, 4, 19);
-- Baby Pig (30) - Offspring of Pig (5)
INSERT INTO `pet_breeding_races` (`pet_type`, `rarity_level`, `breed`) VALUES
(30, 1, 0), (30, 1, 1), (30, 1, 2), (30, 1, 3),
(30, 1, 4), (30, 1, 5), (30, 1, 6), (30, 1, 7),
(30, 2, 8), (30, 2, 9), (30, 2, 10), (30, 2, 11), (30, 2, 12),
(30, 3, 13), (30, 3, 14), (30, 3, 15), (30, 3, 16),
(30, 4, 17), (30, 4, 18), (30, 4, 19);
-- Fix pet_actions offspring_type values
UPDATE `pet_actions` SET `offspring_type` = 29 WHERE `pet_type` = 0;
UPDATE `pet_actions` SET `offspring_type` = 28 WHERE `pet_type` = 1;
UPDATE `pet_actions` SET `offspring_type` = 25 WHERE `pet_type` = 3;
UPDATE `pet_actions` SET `offspring_type` = 24 WHERE `pet_type` = 4;
UPDATE `pet_actions` SET `offspring_type` = 30 WHERE `pet_type` = 5;
UPDATE `pet_actions` SET `offspring_type` = -1 WHERE `pet_type` NOT IN (0, 1, 3, 4, 5);
-- Fix items_base whitespace in interaction_type
UPDATE `items_base` SET `interaction_type` = TRIM(`interaction_type`);
-- Ensure breeding nest items have correct interaction_type
UPDATE `items_base` SET `interaction_type` = 'breeding_nest'
WHERE `item_name` LIKE 'pet_breeding_%' AND `interaction_type` != 'breeding_nest';
-- =============================================================================
-- From: 12012026_ChatBubbles.sql
-- =============================================================================
ALTER TABLE `permissions`
ADD COLUMN IF NOT EXISTS `cmd_update_chat_bubbles` ENUM('0','1') NOT NULL DEFAULT '0';
CREATE TABLE IF NOT EXISTS `chat_bubbles` (
`type` INT(11) NOT NULL AUTO_INCREMENT COMMENT 'Only 46 and higher will work',
`name` VARCHAR(255) NOT NULL DEFAULT '',
`permission` VARCHAR(255) NOT NULL DEFAULT '',
`overridable` TINYINT(1) NOT NULL DEFAULT 1,
`triggers_talking_furniture` TINYINT(1) NOT NULL DEFAULT 0,
PRIMARY KEY (`type`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
INSERT IGNORE INTO `emulator_texts` (`key`, `value`) VALUES
('commands.keys.cmd_update_chat_bubbles', 'update_chat_bubbles');
INSERT IGNORE INTO `emulator_texts` (`key`, `value`) VALUES
('commands.success.cmd_update_chat_bubbles', 'Successfully updated chat bubbles');
INSERT IGNORE INTO `emulator_texts` (`key`, `value`) VALUES
('commands.description.cmd_update_chat_bubbles', ':update_chat_bubbles');
-- =============================================================================
-- From: 16032026_updateall_command.sql
-- =============================================================================
ALTER TABLE `permissions`
ADD COLUMN IF NOT EXISTS `cmd_update_all` ENUM('0','1') NOT NULL DEFAULT '0' AFTER `cmd_update_achievements`;
INSERT IGNORE INTO `emulator_texts` (`key`, `value`) VALUES
('commands.keys.cmd_update_all', 'update_all');
INSERT IGNORE INTO `emulator_texts` (`key`, `value`) VALUES
('commands.description.cmd_update_all', ':update_all');
INSERT IGNORE INTO `emulator_texts` (`key`, `value`) VALUES
('commands.succes.cmd_update_all', 'Successfully updated everything!');
-- =============================================================================
-- From: 17032026_allow_underpass.sql
-- =============================================================================
ALTER TABLE `rooms`
ADD COLUMN IF NOT EXISTS `allow_underpass` ENUM('0','1') NOT NULL DEFAULT '0' AFTER `move_diagonally`;
-- =============================================================================
-- From: 19032026_hotel_timezone.sql
-- =============================================================================
INSERT IGNORE INTO `emulator_settings` (`key`, `value`)
VALUES ('hotel.timezone', 'Europe/Rome');
-- =============================================================================
-- From: 21022026_user_prefixes.sql
-- =============================================================================
CREATE TABLE IF NOT EXISTS `user_prefixes` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`user_id` INT(11) NOT NULL,
`text` VARCHAR(50) NOT NULL,
`color` VARCHAR(255) NOT NULL DEFAULT '#FFFFFF',
`icon` VARCHAR(50) NOT NULL DEFAULT '',
`effect` VARCHAR(50) NOT NULL DEFAULT '',
`active` TINYINT(1) NOT NULL DEFAULT 0,
PRIMARY KEY (`id`),
INDEX `idx_user_id` (`user_id`),
INDEX `idx_user_active` (`user_id`, `active`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- =============================================================================
-- Done
-- =============================================================================
SET FOREIGN_KEY_CHECKS = 1;
SET SQL_MODE = @OLD_SQL_MODE;
File diff suppressed because it is too large Load Diff
@@ -1,152 +0,0 @@
-- Wired Abuse Protection Settings
-- These settings control the wired abuse detection and rate limiting system
-- Maximum recursion depth to prevent infinite loops (e.g., collision + chase triggering each other)
INSERT INTO `emulator_settings` (`key`, `value`) VALUES ('wired.abuse.max.recursion.depth', '10');
-- Maximum events of same type per room within the rate limit window before triggering a ban
-- Set higher for rooms with many users and complex wired setups
INSERT INTO `emulator_settings` (`key`, `value`) VALUES ('wired.abuse.max.events.per.window', '100');
-- Time window in milliseconds for counting rapid events
-- Events are counted within this window to detect abuse patterns
INSERT INTO `emulator_settings` (`key`, `value`) VALUES ('wired.abuse.rate.limit.window.ms', '10000');
-- Duration in milliseconds to ban wired execution in a room after abuse is detected
-- Default: 600000 (10 minutes)
INSERT INTO `emulator_settings` (`key`, `value`) VALUES ('wired.abuse.ban.duration.ms', '600000');
-- Wired Abuse Alert Texts
-- Alert shown to all users in the room when wired is temporarily disabled
INSERT INTO `emulator_texts` (`key`, `value`) VALUES ('wired.abuse.room.alert', 'Wired execution has been temporarily disabled in this room due to abuse detection. It will resume in %minutes% minutes.');
-- Title for the staff bubble alert
INSERT INTO `emulator_texts` (`key`, `value`) VALUES ('wired.abuse.staff.title', 'Wired Abuse Detected');
-- Message for the staff bubble alert
-- Available placeholders: %roomname%, %owner%, %minutes%
INSERT INTO `emulator_texts` (`key`, `value`) VALUES ('wired.abuse.staff.message', 'Room: %roomname%\nOwner: %owner%\nBanned for %minutes% minutes.');
-- Link text for the staff bubble alert (navigates to the room)
INSERT INTO `emulator_texts` (`key`, `value`) VALUES ('wired.abuse.staff.link', 'Go to Room');
-- Default tick resolution for wired timer triggers (in milliseconds)
INSERT INTO `emulator_settings` (`key`, `value`) VALUES ('wired.tick.resolution', '100');
-- =====================================================
-- Wired Engine Rewrite - Configuration Settings
-- =====================================================
-- This SQL script adds the configuration options for the new
-- context-driven wired engine architecture.
--
-- Run this script after upgrading to enable the new wired system.
-- =====================================================
-- Insert new wired engine configuration settings
INSERT INTO `emulator_settings` (`key`, `value`) VALUES
('wired.engine.enabled', '0'),
('wired.engine.exclusive', '0'),
('wired.engine.maxStepsPerStack', '100'),
('wired.engine.debug', '0')
ON DUPLICATE KEY UPDATE `key` = `key`;
-- =====================================================
-- Configuration Options Explained:
-- =====================================================
--
-- wired.engine.enabled
-- Enable the new wired engine. When set to 1, the new engine
-- runs alongside the legacy WiredHandler for parallel testing.
-- Default: 0 (disabled)
--
-- wired.engine.exclusive
-- When set to 1, disables the legacy WiredHandler completely.
-- Only enable this after thorough testing with parallel mode.
-- Default: 0 (legacy handler still active)
--
-- wired.engine.maxStepsPerStack
-- Maximum number of steps (trigger checks + condition evaluations
-- + effect executions) allowed per wired stack execution.
-- Prevents infinite loops from misconfigured wired setups.
-- Default: 100
--
-- wired.engine.debug
-- Enable verbose debug logging for wired execution.
-- Useful for troubleshooting wired stack behavior.
-- Default: 0 (disabled)
--
-- =====================================================
-- Migration Path:
-- =====================================================
--
-- Phase 1: Parallel Testing
-- UPDATE emulator_settings SET value = '1' WHERE `key` = 'wired.engine.enabled';
-- -- Test all wired functionality, compare behavior between old and new
--
-- Phase 2: Switch to New Engine
-- UPDATE emulator_settings SET value = '1' WHERE `key` = 'wired.engine.exclusive';
-- -- Legacy handler disabled, new engine handles all wired events
--
-- Phase 3: Cleanup (after confirming stability)
-- -- Remove legacy WiredHandler calls from codebase
--
-- =====================================================
-- =====================================================
-- Wired Tick System - Configuration Settings
-- =====================================================
-- This SQL script adds the configuration options for the new
-- high-resolution wired tick system (50ms default).
--
-- Run this script to configure the wired timer triggers.
-- =====================================================
-- Insert new wired tick system configuration settings
INSERT INTO `emulator_settings` (`key`, `value`) VALUES
('wired.tick.interval.ms', '50'),
('wired.tick.debug', '0'),
('wired.tick.thread.priority', '6')
ON DUPLICATE KEY UPDATE `key` = `key`;
-- =====================================================
-- Configuration Options Explained:
-- =====================================================
--
-- wired.tick.interval.ms
-- The tick interval in milliseconds for wired timer triggers.
-- Lower values = more precise timing but higher CPU usage.
-- Recommended: 50 (default), Range: 10-500
-- Default: 50
--
-- wired.tick.debug
-- Enable verbose debug logging for wired tick operations.
-- Logs each tick cycle and trigger execution.
-- Warning: Very verbose, only enable for troubleshooting.
-- Default: 0 (disabled)
--
-- wired.tick.thread.priority
-- Thread priority for the wired tick service (1-10).
-- Higher priority = better timing accuracy under load.
-- Java Thread priorities: MIN=1, NORM=5, MAX=10
-- Default: 6 (slightly above normal)
--
-- =====================================================
-- Usage Examples:
-- =====================================================
--
-- Increase tick resolution for competitive mini-games:
-- UPDATE emulator_settings SET value = '25' WHERE `key` = 'wired.tick.interval.ms';
--
-- Reduce CPU usage on low-end servers:
-- UPDATE emulator_settings SET value = '100' WHERE `key` = 'wired.tick.interval.ms';
--
-- Enable debug logging for troubleshooting:
-- UPDATE emulator_settings SET value = '1' WHERE `key` = 'wired.tick.debug';
--
-- =====================================================
INSERT INTO `emulator_settings` (`key`, `value`) VALUES ('pathfinder.click.delay', '0');
INSERT INTO `emulator_settings` (`key`, `value`) VALUES ('pathfinder.retro-style.diagonals', '0');
INSERT INTO `emulator_settings` (`key`, `value`) VALUES ('pathfinder.step.allow.falling', '1');
@@ -1,672 +0,0 @@
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- =====================================================
-- SECTION 1: Pet System Emulator Settings
-- =====================================================
INSERT INTO `emulator_settings` (`key`, `value`) VALUES
-- Core pet limits
('hotel.pets.max.room', '15'),
('hotel.pets.max.inventory', '25'),
('hotel.pets.name.length.min', '1'),
('hotel.pets.name.length.max', '15'),
('hotel.daily.respect.pets', '3'),
-- Command cooldown and spam prevention
('pet.command.cooldown_ms', '2000'),
('pet.command.max_same_spam', '3'),
('pet.command.spam_reset_ms', '10000'),
('pet.command.min_energy', '15'),
('pet.command.min_happiness', '10'),
('pet.command.base_obey_chance', '70'),
-- Pet behavior settings
('pet.behavior.autonomous_action_delay', '5000'),
('pet.behavior.idle_wander_min_ms', '10000'),
('pet.behavior.idle_wander_max_ms', '30000'),
-- Pet stats decay/recovery rates (per cycle)
('pet.stats.hunger_decay', '1'),
('pet.stats.thirst_decay', '1'),
('pet.stats.energy_decay', '1'),
('pet.stats.happiness_decay', '1'),
('pet.stats.energy_recovery', '5'),
('pet.stats.happiness_recovery', '1'),
-- Pet thresholds (below this = needs attention)
('pet.threshold.hungry', '50'),
('pet.threshold.thirsty', '50'),
('pet.threshold.tired', '30'),
('pet.threshold.sad', '30'),
-- Pet breeding
('pet.breeding.timeout_seconds', '120')
ON DUPLICATE KEY UPDATE `value` = VALUES(`value`);
-- =====================================================
-- SECTION 2: Pet Actions (Pet Type Definitions)
-- =====================================================
DROP TABLE IF EXISTS `pet_actions`;
CREATE TABLE `pet_actions` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`pet_type` int(11) NOT NULL,
`pet_name` varchar(32) NOT NULL DEFAULT '',
`offspring_type` int(11) NOT NULL DEFAULT -1,
`happy_actions` varchar(100) NOT NULL DEFAULT 'sml',
`tired_actions` varchar(100) NOT NULL DEFAULT 'trd',
`random_actions` varchar(100) NOT NULL DEFAULT 'lov',
`can_swim` enum('0','1') NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
UNIQUE KEY `pet_type` (`pet_type`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
INSERT INTO `pet_actions` (`pet_type`, `pet_name`, `offspring_type`, `happy_actions`, `tired_actions`, `random_actions`, `can_swim`) VALUES
(0, 'Dog', 29, 'sml,wav,joy', 'trd,yng', 'lov,snf', '0'),
(1, 'Cat', 28, 'sml,pur', 'trd,yng', 'lov,lck', '0'),
(2, 'Crocodile', -1, 'sml', 'trd', 'lov,snp', '1'),
(3, 'Terrier', 25, 'sml,wav,joy', 'trd,yng', 'lov,snf', '0'),
(4, 'Bear', 24, 'sml,grw', 'trd,yng', 'lov', '0'),
(5, 'Pig', 30, 'sml,oink', 'trd,yng', 'lov,rol', '0'),
(6, 'Lion', -1, 'sml,ror', 'trd,yng', 'lov', '0'),
(7, 'Rhino', -1, 'sml', 'trd,yng', 'lov', '0'),
(8, 'Tarantula', -1, 'sml', 'trd', 'lov,crw', '0'),
(9, 'Turtle', -1, 'sml', 'trd', 'lov', '1'),
(10, 'Chick', -1, 'sml,chp', 'trd', 'lov,pck', '0'),
(11, 'Frog', -1, 'sml,crk', 'trd', 'lov,jmp', '1'),
(12, 'Dragon', -1, 'sml,flm', 'trd,smk', 'lov,fly', '0'),
(13, 'Monster', -1, 'sml', 'trd', 'lov', '0'),
(14, 'Monkey', -1, 'sml,ook', 'trd,yng', 'lov,swg', '0'),
(15, 'Horse', -1, 'sml,nei', 'trd,yng', 'lov', '0'),
(16, 'Monsterplant', -1, 'sml', 'trd', 'lov', '0'),
(17, 'Bunny', -1, 'sml,hop', 'trd,yng', 'lov', '0'),
(18, 'Evil Bunny', -1, 'sml', 'trd', 'lov', '0'),
(19, 'Bored Bunny', -1, 'sml', 'trd', 'lov', '0'),
(20, 'Cute Bunny', -1, 'sml,hop', 'trd', 'lov', '0'),
(21, 'Wise Pigeon', -1, 'sml,coo', 'trd', 'lov,pck', '0'),
(22, 'Evil Pigeon', -1, 'sml', 'trd', 'lov,pck', '0'),
(23, 'Evil Monkey', -1, 'sml', 'trd', 'lov,swg', '0'),
(24, 'Baby Bear', -1, 'sml', 'trd,yng', 'lov', '0'),
(25, 'Baby Terrier', -1, 'sml', 'trd,yng', 'lov', '0'),
(26, 'Gnome', -1, 'sml,grn', 'trd', 'lov', '0'),
(27, 'Leprechaun', -1, 'sml,grn', 'trd', 'lov,jig', '0'),
(28, 'Baby Cat', -1, 'sml', 'trd,yng', 'lov', '0'),
(29, 'Baby Dog', -1, 'sml', 'trd,yng', 'lov', '0'),
(30, 'Baby Pig', -1, 'sml', 'trd,yng', 'lov', '0'),
(31, 'Haloompa', -1, 'sml', 'trd', 'lov', '0'),
(32, 'Fools Pet', -1, 'sml', 'trd', 'lov', '0'),
(33, 'Pterodactyl', -1, 'sml,sqk', 'trd', 'lov,fly', '0'),
(34, 'Velociraptor', -1, 'sml,hss', 'trd', 'lov,clw', '0'),
(35, 'Cow', -1, 'sml,moo', 'trd,yng', 'lov,chw', '0');
-- =====================================================
-- SECTION 3: Pet Commands Data (English Command Names)
-- =====================================================
-- Command IDs mapped to PetManager.petActions:
-- 0=Free, 1=Sit, 2=Down, 3=Here, 4=Beg, 5=PlayDead, 6=Stay, 7=Follow
-- 8=Stand, 9=Jump, 10=Speak, 11=Play, 12=Silent, 13=Nest, 14=Drink
-- 15=FollowLeft, 16=FollowRight, 17=PlayFootball, 18=Teleport, 19=Bounce
-- 20=Flatten, 21=Dance, 22=Spin, 23=Switch, 24=MoveForward
-- 25=TurnLeft, 26=TurnRight, 27=Relax, 28=Croak, 29=Dip, 30=Wave
-- 31=Mambo, 32=HighJump, 33=ChickenDance, 34=TripleJump
-- 35=Wings, 36=BreatheFire, 37=Hang, 38=Torch, 40=Swing, 41=Roll
-- 42=RingOfFire, 43=Eat, 44=WagTail, 45=Count, 46=Breed
DROP TABLE IF EXISTS `pet_commands_data`;
CREATE TABLE `pet_commands_data` (
`command_id` int(11) NOT NULL,
`text` varchar(25) NOT NULL,
`required_level` int(11) NOT NULL DEFAULT 1,
`reward_xp` int(11) NOT NULL DEFAULT 5,
`cost_happiness` int(11) NOT NULL DEFAULT 0,
`cost_energy` int(11) NOT NULL DEFAULT 0,
PRIMARY KEY (`command_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
INSERT INTO `pet_commands_data` (`command_id`, `text`, `required_level`, `reward_xp`, `cost_happiness`, `cost_energy`) VALUES
(0, 'free', 1, 5, 0, 0),
(1, 'sit', 1, 5, 2, 2),
(2, 'down', 2, 10, 3, 3),
(3, 'come here', 2, 10, 2, 5),
(4, 'beg', 2, 10, 3, 4),
(5, 'play dead', 3, 15, 4, 5),
(6, 'stay', 4, 10, 2, 3),
(7, 'follow', 5, 15, 3, 8),
(8, 'stand', 6, 15, 2, 3),
(9, 'jump', 6, 15, 4, 8),
(10, 'speak', 7, 10, 3, 3),
(11, 'play', 8, 5, 5, 10),
(12, 'silent', 8, 5, 2, 1),
(13, 'nest', 5, 5, 0, 0),
(14, 'drink', 1, 5, 0, 0),
(15, 'follow left', 15, 15, 4, 10),
(16, 'follow right', 15, 15, 4, 10),
(17, 'play football', 10, 5, 5, 12),
(18, 'teleport', 9, 5, 3, 5),
(19, 'bounce', 9, 5, 5, 10),
(20, 'flatten', 11, 5, 3, 4),
(21, 'dance', 12, 10, 6, 12),
(22, 'spin', 10, 5, 4, 8),
(23, 'switch', 12, 5, 3, 3),
(24, 'move forward', 17, 5, 2, 2),
(25, 'turn left', 18, 5, 2, 2),
(26, 'turn right', 18, 5, 2, 2),
(27, 'relax', 13, 5, 0, 0),
(28, 'croak', 14, 5, 3, 3),
(29, 'dip', 14, 5, 5, 10),
(30, 'wave', 5, 5, 2, 3),
(31, 'mambo', 18, 5, 6, 12),
(32, 'high jump', 18, 5, 5, 12),
(33, 'chicken dance', 7, 5, 5, 10),
(34, 'triple jump', 9, 5, 6, 15),
(35, 'spread wings', 8, 5, 4, 6),
(36, 'breathe fire', 10, 5, 5, 8),
(37, 'hang', 12, 5, 4, 6),
(38, 'torch', 6, 5, 3, 5),
(40, 'swing', 13, 5, 4, 8),
(41, 'roll', 10, 5, 5, 10),
(42, 'ring of fire', 20, 10, 8, 15),
(43, 'eat', 1, 5, 0, 0),
(44, 'wag tail', 4, 5, 3, 4),
(45, 'count', 6, 5, 4, 5),
(46, 'breed', 1, 5, 10, 20);
-- =====================================================
-- SECTION 4: Pet Commands (Pet Type -> Command Mapping)
-- =====================================================
DROP TABLE IF EXISTS `pet_commands`;
CREATE TABLE `pet_commands` (
`pet_id` int(11) NOT NULL,
`command_id` int(11) NOT NULL,
PRIMARY KEY (`pet_id`, `command_id`),
KEY `pet_id` (`pet_id`),
KEY `command_id` (`command_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- Dog (0) - Full standard pet commands
INSERT INTO `pet_commands` (`pet_id`, `command_id`) VALUES
(0, 0), (0, 1), (0, 2), (0, 3), (0, 4), (0, 5), (0, 6), (0, 7), (0, 8), (0, 9),
(0, 10), (0, 11), (0, 12), (0, 13), (0, 14), (0, 15), (0, 16), (0, 17), (0, 24),
(0, 25), (0, 26), (0, 43), (0, 44), (0, 46);
-- Cat (1) - Full standard pet commands + breed
INSERT INTO `pet_commands` (`pet_id`, `command_id`) VALUES
(1, 0), (1, 1), (1, 2), (1, 3), (1, 4), (1, 5), (1, 6), (1, 7), (1, 8), (1, 9),
(1, 10), (1, 11), (1, 12), (1, 13), (1, 14), (1, 15), (1, 16), (1, 17), (1, 24),
(1, 25), (1, 26), (1, 43), (1, 46);
-- Crocodile (2) - Standard commands (can swim)
INSERT INTO `pet_commands` (`pet_id`, `command_id`) VALUES
(2, 0), (2, 1), (2, 2), (2, 3), (2, 4), (2, 5), (2, 6), (2, 7), (2, 8), (2, 9),
(2, 10), (2, 11), (2, 12), (2, 13), (2, 14), (2, 15), (2, 16), (2, 17), (2, 24),
(2, 25), (2, 26), (2, 29), (2, 43);
-- Terrier (3) - Standard commands + breed
INSERT INTO `pet_commands` (`pet_id`, `command_id`) VALUES
(3, 0), (3, 1), (3, 2), (3, 3), (3, 4), (3, 5), (3, 6), (3, 7), (3, 8), (3, 9),
(3, 10), (3, 11), (3, 12), (3, 13), (3, 14), (3, 15), (3, 16), (3, 17), (3, 24),
(3, 25), (3, 26), (3, 43), (3, 46);
-- Bear (4) - Standard commands + breed
INSERT INTO `pet_commands` (`pet_id`, `command_id`) VALUES
(4, 0), (4, 1), (4, 2), (4, 3), (4, 4), (4, 5), (4, 6), (4, 7), (4, 8), (4, 9),
(4, 10), (4, 11), (4, 12), (4, 13), (4, 14), (4, 15), (4, 16), (4, 17), (4, 24),
(4, 25), (4, 26), (4, 43), (4, 46);
-- Pig (5) - Standard commands + breed
INSERT INTO `pet_commands` (`pet_id`, `command_id`) VALUES
(5, 0), (5, 1), (5, 2), (5, 3), (5, 4), (5, 5), (5, 6), (5, 7), (5, 8), (5, 9),
(5, 10), (5, 11), (5, 12), (5, 13), (5, 14), (5, 15), (5, 16), (5, 17), (5, 24),
(5, 25), (5, 26), (5, 43), (5, 46);
-- Lion (6) - Standard commands
INSERT INTO `pet_commands` (`pet_id`, `command_id`) VALUES
(6, 0), (6, 1), (6, 2), (6, 3), (6, 4), (6, 5), (6, 6), (6, 7), (6, 8), (6, 9),
(6, 10), (6, 11), (6, 12), (6, 13), (6, 14), (6, 15), (6, 16), (6, 17), (6, 24),
(6, 25), (6, 26), (6, 43);
-- Rhino (7) - Standard commands
INSERT INTO `pet_commands` (`pet_id`, `command_id`) VALUES
(7, 0), (7, 1), (7, 2), (7, 3), (7, 4), (7, 5), (7, 6), (7, 7), (7, 8), (7, 9),
(7, 10), (7, 11), (7, 12), (7, 13), (7, 14), (7, 15), (7, 16), (7, 17), (7, 24),
(7, 25), (7, 26), (7, 43);
-- Tarantula (8) - Spider commands (bounce, flatten, spin, etc.)
INSERT INTO `pet_commands` (`pet_id`, `command_id`) VALUES
(8, 0), (8, 2), (8, 3), (8, 5), (8, 6), (8, 7), (8, 9), (8, 10), (8, 11), (8, 13),
(8, 14), (8, 15), (8, 16), (8, 17), (8, 19), (8, 20), (8, 21), (8, 22), (8, 23),
(8, 24), (8, 25), (8, 26), (8, 43);
-- Turtle (9) - Aquatic commands
INSERT INTO `pet_commands` (`pet_id`, `command_id`) VALUES
(9, 0), (9, 1), (9, 2), (9, 3), (9, 6), (9, 7), (9, 8), (9, 10), (9, 11), (9, 13),
(9, 14), (9, 15), (9, 16), (9, 24), (9, 25), (9, 26), (9, 29), (9, 41), (9, 43);
-- Chick (10) - Bird commands
INSERT INTO `pet_commands` (`pet_id`, `command_id`) VALUES
(10, 0), (10, 2), (10, 3), (10, 6), (10, 7), (10, 11), (10, 13), (10, 15), (10, 16),
(10, 17), (10, 33);
-- Frog (11) - Amphibian commands (croak, dip, wave, mambo)
INSERT INTO `pet_commands` (`pet_id`, `command_id`) VALUES
(11, 0), (11, 1), (11, 2), (11, 3), (11, 4), (11, 5), (11, 6), (11, 7), (11, 9),
(11, 13), (11, 14), (11, 15), (11, 16), (11, 17), (11, 27), (11, 28), (11, 29),
(11, 30), (11, 31), (11, 43);
-- Dragon (12) - Dragon special commands (fire, hang, swing, ring of fire)
INSERT INTO `pet_commands` (`pet_id`, `command_id`) VALUES
(12, 0), (12, 2), (12, 3), (12, 5), (12, 6), (12, 7), (12, 8), (12, 9), (12, 10),
(12, 11), (12, 12), (12, 13), (12, 14), (12, 15), (12, 16), (12, 22), (12, 35),
(12, 36), (12, 37), (12, 38), (12, 40), (12, 41), (12, 42), (12, 43);
-- Monster (13) - Basic commands
INSERT INTO `pet_commands` (`pet_id`, `command_id`) VALUES
(13, 0), (13, 2), (13, 3), (13, 6), (13, 7), (13, 13);
-- Monkey (14) - Monkey commands (wave, hang, swing)
INSERT INTO `pet_commands` (`pet_id`, `command_id`) VALUES
(14, 0), (14, 1), (14, 2), (14, 3), (14, 4), (14, 5), (14, 6), (14, 7), (14, 9),
(14, 13), (14, 14), (14, 15), (14, 16), (14, 17), (14, 27), (14, 29), (14, 30),
(14, 31), (14, 37), (14, 40), (14, 43);
-- Horse (15) - Rideable pet commands + wag tail, count
INSERT INTO `pet_commands` (`pet_id`, `command_id`) VALUES
(15, 0), (15, 2), (15, 3), (15, 6), (15, 7), (15, 10), (15, 11), (15, 12), (15, 13),
(15, 14), (15, 15), (15, 16), (15, 24), (15, 25), (15, 26), (15, 43), (15, 44), (15, 45);
-- Monsterplant (16) - Minimal commands
INSERT INTO `pet_commands` (`pet_id`, `command_id`) VALUES
(16, 0), (16, 14), (16, 43);
-- Bunnies (17-20) - Bunny commands
INSERT INTO `pet_commands` (`pet_id`, `command_id`) VALUES
(17, 0), (17, 2), (17, 3), (17, 6), (17, 7), (17, 11), (17, 13), (17, 15), (17, 16), (17, 17),
(18, 0), (18, 2), (18, 3), (18, 6), (18, 7), (18, 11), (18, 13), (18, 15), (18, 16), (18, 17),
(19, 0), (19, 2), (19, 3), (19, 6), (19, 7), (19, 11), (19, 13), (19, 15), (19, 16), (19, 17),
(20, 0), (20, 2), (20, 3), (20, 6), (20, 7), (20, 11), (20, 13), (20, 15), (20, 16), (20, 17);
-- Pigeons (21-22)
INSERT INTO `pet_commands` (`pet_id`, `command_id`) VALUES
(21, 0), (21, 2), (21, 3), (21, 6), (21, 7), (21, 11), (21, 13), (21, 15), (21, 16), (21, 17),
(22, 0), (22, 2), (22, 3), (22, 6), (22, 7), (22, 11), (22, 13), (22, 15), (22, 16), (22, 17);
-- Evil Monkey (23) - Monkey commands
INSERT INTO `pet_commands` (`pet_id`, `command_id`) VALUES
(23, 0), (23, 1), (23, 2), (23, 3), (23, 4), (23, 5), (23, 6), (23, 7), (23, 9),
(23, 13), (23, 14), (23, 15), (23, 16), (23, 17), (23, 25), (23, 26), (23, 27),
(23, 29), (23, 30), (23, 31), (23, 37), (23, 40), (23, 43);
-- Baby Bear (24)
INSERT INTO `pet_commands` (`pet_id`, `command_id`) VALUES
(24, 0), (24, 1), (24, 2), (24, 3), (24, 4), (24, 6), (24, 7), (24, 8), (24, 10),
(24, 11), (24, 12), (24, 13), (24, 14), (24, 15), (24, 16), (24, 17), (24, 24),
(24, 25), (24, 26), (24, 43);
-- Baby Terrier (25)
INSERT INTO `pet_commands` (`pet_id`, `command_id`) VALUES
(25, 0), (25, 1), (25, 2), (25, 3), (25, 4), (25, 6), (25, 7), (25, 8), (25, 10),
(25, 11), (25, 12), (25, 13), (25, 14), (25, 15), (25, 16), (25, 17), (25, 24),
(25, 25), (25, 26), (25, 43);
-- Gnome (26)
INSERT INTO `pet_commands` (`pet_id`, `command_id`) VALUES
(26, 0), (26, 1), (26, 2), (26, 3), (26, 4), (26, 6), (26, 7), (26, 8), (26, 13),
(26, 14), (26, 15), (26, 16), (26, 17), (26, 25), (26, 26), (26, 43);
-- Leprechaun (27)
INSERT INTO `pet_commands` (`pet_id`, `command_id`) VALUES
(27, 0), (27, 1), (27, 2), (27, 3), (27, 4), (27, 6), (27, 7), (27, 8), (27, 13),
(27, 14), (27, 15), (27, 16), (27, 17), (27, 25), (27, 26), (27, 43);
-- Baby Cat (28)
INSERT INTO `pet_commands` (`pet_id`, `command_id`) VALUES
(28, 0), (28, 1), (28, 2), (28, 3), (28, 4), (28, 6), (28, 7), (28, 8), (28, 10),
(28, 11), (28, 12), (28, 13), (28, 14), (28, 15), (28, 16), (28, 17), (28, 24),
(28, 25), (28, 26), (28, 43);
-- Baby Dog (29)
INSERT INTO `pet_commands` (`pet_id`, `command_id`) VALUES
(29, 0), (29, 1), (29, 2), (29, 3), (29, 4), (29, 6), (29, 7), (29, 8), (29, 10),
(29, 11), (29, 12), (29, 13), (29, 14), (29, 15), (29, 16), (29, 17), (29, 24),
(29, 25), (29, 26), (29, 43);
-- Baby Pig (30)
INSERT INTO `pet_commands` (`pet_id`, `command_id`) VALUES
(30, 0), (30, 1), (30, 2), (30, 3), (30, 4), (30, 6), (30, 7), (30, 8), (30, 10),
(30, 11), (30, 12), (30, 13), (30, 14), (30, 15), (30, 16), (30, 17), (30, 24),
(30, 25), (30, 26), (30, 43);
-- Haloompa (31)
INSERT INTO `pet_commands` (`pet_id`, `command_id`) VALUES
(31, 0), (31, 1), (31, 2), (31, 3), (31, 4), (31, 6), (31, 7), (31, 8), (31, 13),
(31, 14), (31, 15), (31, 16), (31, 17), (31, 25), (31, 26), (31, 43);
-- Fools Pet (32) - Full dance/trick set
INSERT INTO `pet_commands` (`pet_id`, `command_id`) VALUES
(32, 0), (32, 1), (32, 2), (32, 3), (32, 4), (32, 5), (32, 6), (32, 7), (32, 8),
(32, 9), (32, 13), (32, 14), (32, 15), (32, 16), (32, 17), (32, 21), (32, 25),
(32, 26), (32, 43);
-- Pterodactyl (33)
INSERT INTO `pet_commands` (`pet_id`, `command_id`) VALUES
(33, 0), (33, 2), (33, 3), (33, 4), (33, 6), (33, 7), (33, 11), (33, 13), (33, 14),
(33, 15), (33, 16), (33, 25), (33, 26), (33, 43);
-- Velociraptor (34)
INSERT INTO `pet_commands` (`pet_id`, `command_id`) VALUES
(34, 0), (34, 1), (34, 2), (34, 3), (34, 6), (34, 7), (34, 8), (34, 10), (34, 12),
(34, 13), (34, 14), (34, 15), (34, 16), (34, 17), (34, 21), (34, 26), (34, 43);
-- Cow (35)
INSERT INTO `pet_commands` (`pet_id`, `command_id`) VALUES
(35, 0), (35, 2), (35, 3), (35, 4), (35, 6), (35, 7), (35, 13), (35, 14), (35, 15),
(35, 16), (35, 17), (35, 25), (35, 26), (35, 30), (35, 43);
-- =====================================================
-- SECTION 5: Pet Vocals (Pet Speech Messages)
-- =====================================================
-- pet_id = -1 means general vocals for all pets
-- pet_id >= 0 means specific to that pet type
CREATE TABLE IF NOT EXISTS `pet_vocals` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`pet_id` int(11) NOT NULL DEFAULT -1,
`type` varchar(20) NOT NULL,
`message` varchar(255) NOT NULL,
PRIMARY KEY (`id`),
KEY `pet_id` (`pet_id`),
KEY `type` (`type`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- Clear existing vocals
DELETE FROM `pet_vocals`;
-- =====================================================
-- GENERAL VOCALS (pet_id = -1, used by all pets)
-- =====================================================
-- GREET_OWNER - When owner enters room
INSERT INTO `pet_vocals` (`pet_id`, `type`, `message`) VALUES
(-1, 'GREET_OWNER', '*perks up excitedly*'),
(-1, 'GREET_OWNER', 'You''re back!'),
(-1, 'GREET_OWNER', '*bounces with joy*'),
(-1, 'GREET_OWNER', 'I missed you!'),
(-1, 'GREET_OWNER', '*runs in circles happily*'),
(-1, 'GREET_OWNER', 'Yay! My favorite person!'),
(-1, 'GREET_OWNER', '*jumps up and down*'),
(-1, 'GREET_OWNER', 'Finally! You''re here!'),
(-1, 'GREET_OWNER', '*tail wagging intensifies*');
-- LEVEL_UP - When pet gains a level
INSERT INTO `pet_vocals` (`pet_id`, `type`, `message`) VALUES
(-1, 'LEVEL_UP', '*jumps with joy!*'),
(-1, 'LEVEL_UP', 'I leveled up!'),
(-1, 'LEVEL_UP', 'I feel stronger!'),
(-1, 'LEVEL_UP', 'Woohoo! New level!'),
(-1, 'LEVEL_UP', '*celebrates*'),
(-1, 'LEVEL_UP', 'I''m getting better!'),
(-1, 'LEVEL_UP', 'Level up! Yeah!');
-- MUTED - When told to be silent
INSERT INTO `pet_vocals` (`pet_id`, `type`, `message`) VALUES
(-1, 'MUTED', '*stays quiet*'),
(-1, 'MUTED', '...'),
(-1, 'MUTED', '*zips lips*'),
(-1, 'MUTED', '*nods silently*');
-- UNKNOWN_COMMAND - When pet doesn't understand
INSERT INTO `pet_vocals` (`pet_id`, `type`, `message`) VALUES
(-1, 'UNKNOWN_COMMAND', '*tilts head confused*'),
(-1, 'UNKNOWN_COMMAND', 'Huh?'),
(-1, 'UNKNOWN_COMMAND', 'I don''t understand...'),
(-1, 'UNKNOWN_COMMAND', '*looks puzzled*'),
(-1, 'UNKNOWN_COMMAND', 'What do you mean?'),
(-1, 'UNKNOWN_COMMAND', '*scratches head*');
-- DISOBEY - When pet refuses command
INSERT INTO `pet_vocals` (`pet_id`, `type`, `message`) VALUES
(-1, 'DISOBEY', '*ignores command*'),
(-1, 'DISOBEY', 'Maybe later...'),
(-1, 'DISOBEY', 'I don''t feel like it'),
(-1, 'DISOBEY', '*pretends not to hear*'),
(-1, 'DISOBEY', 'Nah...'),
(-1, 'DISOBEY', '*turns away*'),
(-1, 'DISOBEY', 'Not right now'),
(-1, 'DISOBEY', '*yawns dismissively*'),
(-1, 'DISOBEY', 'Too tired for that'),
(-1, 'DISOBEY', 'Ask me again later'),
(-1, 'DISOBEY', '*looks the other way*'),
(-1, 'DISOBEY', 'I''d rather not'),
(-1, 'DISOBEY', '*shakes head*'),
(-1, 'DISOBEY', 'No thanks'),
(-1, 'DISOBEY', '*walks away slowly*'),
(-1, 'DISOBEY', 'Can''t be bothered'),
(-1, 'DISOBEY', '*pretends to be asleep*'),
(-1, 'DISOBEY', 'You can''t make me!'),
(-1, 'DISOBEY', '*stubbornly sits down*'),
(-1, 'DISOBEY', 'I refuse!');
-- DRINKING - When drinking water
INSERT INTO `pet_vocals` (`pet_id`, `type`, `message`) VALUES
(-1, 'DRINKING', '*laps up water*'),
(-1, 'DRINKING', 'Refreshing!'),
(-1, 'DRINKING', '*gulp gulp*'),
(-1, 'DRINKING', 'Ah, that''s good!'),
(-1, 'DRINKING', '*slurp*');
-- EATING - When eating food
INSERT INTO `pet_vocals` (`pet_id`, `type`, `message`) VALUES
(-1, 'EATING', '*munches happily*'),
(-1, 'EATING', 'Yum!'),
(-1, 'EATING', 'Delicious!'),
(-1, 'EATING', '*nom nom nom*'),
(-1, 'EATING', 'This is tasty!'),
(-1, 'EATING', '*chomps*'),
(-1, 'EATING', 'More please!');
-- PLAYFUL - When in playful mood
INSERT INTO `pet_vocals` (`pet_id`, `type`, `message`) VALUES
(-1, 'PLAYFUL', '*bounces excitedly*'),
(-1, 'PLAYFUL', 'Let''s play!'),
(-1, 'PLAYFUL', '*runs around happily*'),
(-1, 'PLAYFUL', 'Play with me!'),
(-1, 'PLAYFUL', '*jumps around*'),
(-1, 'PLAYFUL', 'I wanna play!'),
(-1, 'PLAYFUL', '*brings a toy*'),
(-1, 'PLAYFUL', 'Wheee!'),
(-1, 'PLAYFUL', '*zooms around the room*'),
(-1, 'PLAYFUL', 'Catch me if you can!');
-- SLEEPING - When sleeping
INSERT INTO `pet_vocals` (`pet_id`, `type`, `message`) VALUES
(-1, 'SLEEPING', '*snores softly*'),
(-1, 'SLEEPING', 'Zzz...'),
(-1, 'SLEEPING', '*mumbles in sleep*'),
(-1, 'SLEEPING', 'ZzZzZz...'),
(-1, 'SLEEPING', '*dreams peacefully*'),
(-1, 'SLEEPING', '*twitches while dreaming*'),
(-1, 'SLEEPING', '*snoozes*'),
(-1, 'SLEEPING', '*breathes slowly*');
-- TIRED - When tired/low energy
INSERT INTO `pet_vocals` (`pet_id`, `type`, `message`) VALUES
(-1, 'TIRED', '*yawns*'),
(-1, 'TIRED', 'So sleepy...'),
(-1, 'TIRED', '*eyes drooping*'),
(-1, 'TIRED', 'I need rest...');
-- THIRSTY - When thirsty
INSERT INTO `pet_vocals` (`pet_id`, `type`, `message`) VALUES
(-1, 'THIRSTY', '*pants*'),
(-1, 'THIRSTY', 'Water please!'),
(-1, 'THIRSTY', '*looks at water bowl*'),
(-1, 'THIRSTY', 'So thirsty...'),
(-1, 'THIRSTY', '*dry tongue*'),
(-1, 'THIRSTY', 'Need a drink!'),
(-1, 'THIRSTY', '*licks lips*'),
(-1, 'THIRSTY', 'I''m parched!');
-- HUNGRY - When hungry
INSERT INTO `pet_vocals` (`pet_id`, `type`, `message`) VALUES
(-1, 'HUNGRY', '*stomach growls*'),
(-1, 'HUNGRY', 'I need food!'),
(-1, 'HUNGRY', '*looks at food bowl*'),
(-1, 'HUNGRY', 'Feed me!'),
(-1, 'HUNGRY', 'So hungry...'),
(-1, 'HUNGRY', '*tummy rumbles*'),
(-1, 'HUNGRY', 'Food please!'),
(-1, 'HUNGRY', '*drools at thought of food*'),
(-1, 'HUNGRY', 'Is it dinner time?'),
(-1, 'HUNGRY', '*sniffs around for food*'),
(-1, 'HUNGRY', 'I could eat a horse!'),
(-1, 'HUNGRY', '*begs for food*'),
(-1, 'HUNGRY', 'Starving over here!');
-- GENERIC_NEUTRAL - Random idle chat
INSERT INTO `pet_vocals` (`pet_id`, `type`, `message`) VALUES
(-1, 'GENERIC_NEUTRAL', '*looks around*'),
(-1, 'GENERIC_NEUTRAL', '*sniffs the air*'),
(-1, 'GENERIC_NEUTRAL', '*stretches*'),
(-1, 'GENERIC_NEUTRAL', '*scratches ear*'),
(-1, 'GENERIC_NEUTRAL', '*observes surroundings*'),
(-1, 'GENERIC_NEUTRAL', '*sits quietly*'),
(-1, 'GENERIC_NEUTRAL', '*watches curiously*');
-- GENERIC_SAD - When sad/low happiness
INSERT INTO `pet_vocals` (`pet_id`, `type`, `message`) VALUES
(-1, 'GENERIC_SAD', '*whimpers*'),
(-1, 'GENERIC_SAD', '*looks sad*'),
(-1, 'GENERIC_SAD', '*sighs*'),
(-1, 'GENERIC_SAD', '*droops head*'),
(-1, 'GENERIC_SAD', 'I''m lonely...'),
(-1, 'GENERIC_SAD', '*mopes around*'),
(-1, 'GENERIC_SAD', '*looks dejected*'),
(-1, 'GENERIC_SAD', 'Nobody loves me...'),
(-1, 'GENERIC_SAD', '*sulks in corner*');
-- GENERIC_HAPPY - When happy
INSERT INTO `pet_vocals` (`pet_id`, `type`, `message`) VALUES
(-1, 'GENERIC_HAPPY', '*wags tail happily*'),
(-1, 'GENERIC_HAPPY', '*jumps with joy*'),
(-1, 'GENERIC_HAPPY', ':)'),
(-1, 'GENERIC_HAPPY', 'Life is good!'),
(-1, 'GENERIC_HAPPY', '*prances around*'),
(-1, 'GENERIC_HAPPY', '*does a happy dance*'),
(-1, 'GENERIC_HAPPY', 'I''m so happy!'),
(-1, 'GENERIC_HAPPY', '*beams with joy*'),
(-1, 'GENERIC_HAPPY', 'What a great day!'),
(-1, 'GENERIC_HAPPY', '*grins*'),
(-1, 'GENERIC_HAPPY', '*radiates happiness*'),
(-1, 'GENERIC_HAPPY', 'Yippee!'),
(-1, 'GENERIC_HAPPY', '*spins around happily*'),
(-1, 'GENERIC_HAPPY', 'This is the best!');
-- =====================================================
-- PET-SPECIFIC VOCALS
-- =====================================================
-- Dog (0) specific vocals
INSERT INTO `pet_vocals` (`pet_id`, `type`, `message`) VALUES
(0, 'GENERIC_HAPPY', 'Woof woof!'),
(0, 'GENERIC_HAPPY', '*wags tail furiously*'),
(0, 'GREET_OWNER', '*barks excitedly*'),
(0, 'GREET_OWNER', 'Woof! You''re home!'),
(0, 'PLAYFUL', '*drops ball at your feet*'),
(0, 'PLAYFUL', 'Throw the ball!'),
(0, 'HUNGRY', '*stares at food bowl*'),
(0, 'DISOBEY', '*chases own tail instead*');
-- Cat (1) specific vocals
INSERT INTO `pet_vocals` (`pet_id`, `type`, `message`) VALUES
(1, 'GENERIC_HAPPY', '*purrs*'),
(1, 'GENERIC_HAPPY', 'Meow!'),
(1, 'GENERIC_NEUTRAL', '*grooms self*'),
(1, 'GREET_OWNER', '*rubs against leg*'),
(1, 'DISOBEY', '*looks away disdainfully*'),
(1, 'DISOBEY', '*yawns dismissively*'),
(1, 'PLAYFUL', '*pounces on shadow*'),
(1, 'SLEEPING', '*purrs while sleeping*');
-- Dragon (12) specific vocals
INSERT INTO `pet_vocals` (`pet_id`, `type`, `message`) VALUES
(12, 'GENERIC_HAPPY', '*breathes small flames happily*'),
(12, 'GENERIC_HAPPY', '*roars softly*'),
(12, 'GENERIC_SAD', '*smoke puffs from nostrils*'),
(12, 'DISOBEY', '*snorts flames*'),
(12, 'DISOBEY', 'I am a DRAGON, not a servant!'),
(12, 'HUNGRY', '*eyes the nearest villager*'),
(12, 'HUNGRY', 'I require sustenance!'),
(12, 'THIRSTY', '*smoke rises as throat dries*'),
(12, 'PLAYFUL', '*chases own tail, breathing fire*'),
(12, 'GREET_OWNER', '*bows majestic head*'),
(12, 'SLEEPING', '*snores, causing small fires*'),
(12, 'LEVEL_UP', '*ROARS triumphantly!*');
-- Horse (15) specific vocals
INSERT INTO `pet_vocals` (`pet_id`, `type`, `message`) VALUES
(15, 'GENERIC_HAPPY', '*neighs happily*'),
(15, 'GENERIC_NEUTRAL', '*swishes tail*'),
(15, 'GREET_OWNER', '*whinnies in greeting*'),
(15, 'DISOBEY', 'Nay. (Geddit?)'),
(15, 'HUNGRY', '*looks at hay expectantly*'),
(15, 'PLAYFUL', 'Let''s go for a ride!'),
(15, 'TIRED', '*stamps hoof wearily*');
-- Tarantula (8) specific vocals
INSERT INTO `pet_vocals` (`pet_id`, `type`, `message`) VALUES
(8, 'GREET_OWNER', 'You look more edible every time!'),
(8, 'DISOBEY', '*hisses*'),
(8, 'DISOBEY', 'I do not obey mammals'),
(8, 'HUNGRY', 'Bring me fresh meat!'),
(8, 'PLAYFUL', '*dances on eight legs*'),
(8, 'GENERIC_HAPPY', '*clicks mandibles happily*');
-- Frog (11) specific vocals
INSERT INTO `pet_vocals` (`pet_id`, `type`, `message`) VALUES
(11, 'GENERIC_HAPPY', 'Ribbit!'),
(11, 'GENERIC_NEUTRAL', '*croaks*'),
(11, 'GREET_OWNER', '*hops excitedly*'),
(11, 'PLAYFUL', '*catches fly with tongue*'),
(11, 'THIRSTY', '*seeks water*');
-- Cow (35) specific vocals
INSERT INTO `pet_vocals` (`pet_id`, `type`, `message`) VALUES
(35, 'GENERIC_HAPPY', 'Moooo!'),
(35, 'GREET_OWNER', 'Greetings. Did you bring kale?'),
(35, 'EATING', '*chews grass thoughtfully*'),
(35, 'DISOBEY', 'I''d rather meditate'),
(35, 'LEVEL_UP', '*DING* I''m on the up!');
-- Lion (6) specific vocals
INSERT INTO `pet_vocals` (`pet_id`, `type`, `message`) VALUES
(6, 'GENERIC_HAPPY', '*roars majestically*'),
(6, 'GREET_OWNER', '*nods regally*'),
(6, 'DISOBEY', 'I am the king!'),
(6, 'HUNGRY', '*eyes prey*'),
(6, 'PLAYFUL', '*pounces playfully*');
-- Bear (4) specific vocals
INSERT INTO `pet_vocals` (`pet_id`, `type`, `message`) VALUES
(4, 'GENERIC_HAPPY', '*growls contentedly*'),
(4, 'HUNGRY', '*sniffs for honey*'),
(4, 'SLEEPING', '*hibernates*'),
(4, 'GREET_OWNER', '*bear hug incoming*');
-- Monkey (14) specific vocals
INSERT INTO `pet_vocals` (`pet_id`, `type`, `message`) VALUES
(14, 'GENERIC_HAPPY', 'Ook ook!'),
(14, 'PLAYFUL', '*swings from furniture*'),
(14, 'GREET_OWNER', '*does a backflip*'),
(14, 'DISOBEY', '*throws something*'),
(14, 'HUNGRY', '*looks for bananas*');
-- Bunny (17) specific vocals
INSERT INTO `pet_vocals` (`pet_id`, `type`, `message`) VALUES
(17, 'GENERIC_HAPPY', '*hops happily*'),
(17, 'GREET_OWNER', '*twitches nose excitedly*'),
(17, 'PLAYFUL', '*binkies around*'),
(17, 'HUNGRY', '*nibbles on carrot*');
SET FOREIGN_KEY_CHECKS = 1;
@@ -1,18 +0,0 @@
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- =====================================================
-- Update 4.0.2-beta to 4.0.3-beta
-- =====================================================
INSERT INTO `emulator_settings` (`key`, `value`) VALUES
-- Maximum pending flood-fill tasks in the executor queue
-- Prevents memory leaks from rapid tile locking
('hotel.banzai.fill.max_queue', '50'),
-- Minimum interval (ms) between flood-fill calculations per game
-- Prevents errors via rapid wired triggering
('hotel.banzai.fill.cooldown_ms', '100')
ON DUPLICATE KEY UPDATE `value` = VALUES(`value`);
SET FOREIGN_KEY_CHECKS = 1;
@@ -1,216 +0,0 @@
-- =====================================================
-- Pet Breeding Complete Setup
-- =====================================================
-- This file sets up all breeding-related data:
-- 1. pet_breeding - Maps parent pet types to offspring types
-- 2. pet_breeding_races - Defines possible breeds/colors for offspring by rarity
-- =====================================================
-- =====================================================
-- SECTION 1: Pet Breeding (Parent -> Offspring Mapping)
-- =====================================================
-- This table maps which pet type produces which baby type
CREATE TABLE IF NOT EXISTS `pet_breeding` (
`pet_id` int(11) NOT NULL COMMENT 'Parent pet type',
`offspring_id` int(11) NOT NULL COMMENT 'Baby pet type',
PRIMARY KEY (`pet_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- Clear existing data
TRUNCATE TABLE `pet_breeding`;
-- Insert breeding mappings
INSERT INTO `pet_breeding` (`pet_id`, `offspring_id`) VALUES
(0, 29), -- Dog -> Baby Dog
(1, 28), -- Cat -> Baby Cat
(3, 25), -- Terrier -> Baby Terrier
(4, 24), -- Bear -> Baby Bear
(5, 30); -- Pig -> Baby Pig
-- =====================================================
-- SECTION 2: Pet Breeding Races (Offspring Breeds by Rarity)
-- =====================================================
-- rarity_level: 1=Common, 2=Uncommon, 3=Rare, 4=Epic
-- breed: The visual breed/color variant of the baby pet
--
-- Higher rarity = harder to get, more special colors
-- Each baby pet type should have breeds at all 4 rarity levels
CREATE TABLE IF NOT EXISTS `pet_breeding_races` (
`pet_id` int(11) NOT NULL COMMENT 'Baby pet type (offspring)',
`rarity_level` int(11) NOT NULL COMMENT '1=Common, 2=Uncommon, 3=Rare, 4=Epic',
`breed` int(11) NOT NULL COMMENT 'Visual breed/color variant',
PRIMARY KEY (`pet_id`, `rarity_level`, `breed`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- Clear existing data
TRUNCATE TABLE `pet_breeding_races`;
-- =====================================================
-- Baby Dog (29) - Offspring of Dog (0) - 20 breeds
-- =====================================================
INSERT INTO `pet_breeding_races` (`pet_type`, `rarity_level`, `breed`) VALUES
-- Common breeds (rarity 1) - Most likely to get
(29, 1, 0),
(29, 1, 1),
(29, 1, 2),
(29, 1, 3),
(29, 1, 4),
(29, 1, 5),
(29, 1, 6),
(29, 1, 7),
-- Uncommon breeds (rarity 2)
(29, 2, 8),
(29, 2, 9),
(29, 2, 10),
(29, 2, 11),
(29, 2, 12),
-- Rare breeds (rarity 3)
(29, 3, 13),
(29, 3, 14),
(29, 3, 15),
(29, 3, 16),
-- Epic breeds (rarity 4) - Hardest to get
(29, 4, 17),
(29, 4, 18),
(29, 4, 19);
-- =====================================================
-- Baby Cat (28) - Offspring of Cat (1) - 20 breeds
-- =====================================================
INSERT INTO `pet_breeding_races` (`pet_type`, `rarity_level`, `breed`) VALUES
-- Common breeds (rarity 1)
(28, 1, 0),
(28, 1, 1),
(28, 1, 2),
(28, 1, 3),
(28, 1, 4),
(28, 1, 5),
(28, 1, 6),
(28, 1, 7),
-- Uncommon breeds (rarity 2)
(28, 2, 8),
(28, 2, 9),
(28, 2, 10),
(28, 2, 11),
(28, 2, 12),
-- Rare breeds (rarity 3)
(28, 3, 13),
(28, 3, 14),
(28, 3, 15),
(28, 3, 16),
-- Epic breeds (rarity 4)
(28, 4, 17),
(28, 4, 18),
(28, 4, 19);
-- =====================================================
-- Baby Terrier (25) - Offspring of Terrier (3) - 20 breeds
-- =====================================================
INSERT INTO `pet_breeding_races` (`pet_type`, `rarity_level`, `breed`) VALUES
-- Common breeds (rarity 1)
(25, 1, 0),
(25, 1, 1),
(25, 1, 2),
(25, 1, 3),
(25, 1, 4),
(25, 1, 5),
(25, 1, 6),
(25, 1, 7),
-- Uncommon breeds (rarity 2)
(25, 2, 8),
(25, 2, 9),
(25, 2, 10),
(25, 2, 11),
(25, 2, 12),
-- Rare breeds (rarity 3)
(25, 3, 13),
(25, 3, 14),
(25, 3, 15),
(25, 3, 16),
-- Epic breeds (rarity 4)
(25, 4, 17),
(25, 4, 18),
(25, 4, 19);
-- =====================================================
-- Baby Bear (24) - Offspring of Bear (4) - 20 breeds
-- =====================================================
INSERT INTO `pet_breeding_races` (`pet_type`, `rarity_level`, `breed`) VALUES
-- Common breeds (rarity 1)
(24, 1, 0),
(24, 1, 1),
(24, 1, 2),
(24, 1, 3),
(24, 1, 4),
(24, 1, 5),
(24, 1, 6),
(24, 1, 7),
-- Uncommon breeds (rarity 2)
(24, 2, 8),
(24, 2, 9),
(24, 2, 10),
(24, 2, 11),
(24, 2, 12),
-- Rare breeds (rarity 3)
(24, 3, 13),
(24, 3, 14),
(24, 3, 15),
(24, 3, 16),
-- Epic breeds (rarity 4)
(24, 4, 17),
(24, 4, 18),
(24, 4, 19);
-- =====================================================
-- Baby Pig (30) - Offspring of Pig (5) - 20 breeds
-- =====================================================
INSERT INTO `pet_breeding_races` (`pet_type`, `rarity_level`, `breed`) VALUES
-- Common breeds (rarity 1)
(30, 1, 0),
(30, 1, 1),
(30, 1, 2),
(30, 1, 3),
(30, 1, 4),
(30, 1, 5),
(30, 1, 6),
(30, 1, 7),
-- Uncommon breeds (rarity 2)
(30, 2, 8),
(30, 2, 9),
(30, 2, 10),
(30, 2, 11),
(30, 2, 12),
-- Rare breeds (rarity 3)
(30, 3, 13),
(30, 3, 14),
(30, 3, 15),
(30, 3, 16),
-- Epic breeds (rarity 4)
(30, 4, 17),
(30, 4, 18),
(30, 4, 19);
-- =====================================================
-- Also ensure pet_actions has correct offspring_type values
-- =====================================================
UPDATE `pet_actions` SET `offspring_type` = 29 WHERE `pet_type` = 0; -- Dog -> Baby Dog
UPDATE `pet_actions` SET `offspring_type` = 28 WHERE `pet_type` = 1; -- Cat -> Baby Cat
UPDATE `pet_actions` SET `offspring_type` = 25 WHERE `pet_type` = 3; -- Terrier -> Baby Terrier
UPDATE `pet_actions` SET `offspring_type` = 24 WHERE `pet_type` = 4; -- Bear -> Baby Bear
UPDATE `pet_actions` SET `offspring_type` = 30 WHERE `pet_type` = 5; -- Pig -> Baby Pig
-- Set non-breedable pets to -1
UPDATE `pet_actions` SET `offspring_type` = -1 WHERE `pet_type` NOT IN (0, 1, 3, 4, 5);
-- =====================================================
-- Fix any items_base with leading/trailing spaces in interaction_type
-- =====================================================
UPDATE `items_base` SET `interaction_type` = TRIM(`interaction_type`);
-- =====================================================
-- Ensure breeding nest items have correct interaction_type
-- =====================================================
UPDATE `items_base` SET `interaction_type` = 'breeding_nest'
WHERE `item_name` LIKE 'pet_breeding_%' AND `interaction_type` != 'breeding_nest';
-15
View File
@@ -1,15 +0,0 @@
ALTER TABLE `permissions` ADD COLUMN `cmd_update_chat_bubbles` ENUM('0','1') NOT NULL DEFAULT '0';
--New table for custom chat bubbles
CREATE TABLE chat_bubbles (
type INT(11) PRIMARY KEY AUTO_INCREMENT COMMENT "Only 46 and higher will work",
name VARCHAR(255) NOT NULL DEFAULT '',
permission VARCHAR(255) NOT NULL DEFAULT '',
overridable BOOLEAN NOT NULL DEFAULT TRUE,
triggers_talking_furniture BOOLEAN NOT NULL DEFAULT FALSE
);
--New texts for update chat bubbles command
INSERT INTO `emulator_texts` (`key`, `value`) VALUES ('commands.keys.cmd_update_chat_bubbles', 'update_chat_bubbles');
INSERT INTO `emulator_texts` (`key`, `value`) VALUES ('commands.success.cmd_update_chat_bubbles', 'Successfully updated chat bubbles');
INSERT INTO `emulator_texts` (`key`, `value`) VALUES ('commands.description.cmd_update_chat_bubbles', ':update_chat_bubbles');
@@ -1,6 +0,0 @@
ALTER TABLE `permissions` ADD `cmd_update_all` ENUM('0','1') NOT NULL DEFAULT '0' AFTER `cmd_update_achievements`;
INSERT INTO `emulator_texts` (`key`, `value`) VALUES
('commands.keys.cmd_update_all', 'update_all'),
('commands.description.cmd_update_all', ':update_all'),
('commands.succes.cmd_update_all', 'Successfully updated everything!');
@@ -1 +0,0 @@
ALTER TABLE `rooms` ADD COLUMN `allow_underpass` ENUM('0','1') NOT NULL DEFAULT '0' AFTER `move_diagonally`;
@@ -1,22 +0,0 @@
SET NAMES utf8mb4;
-- Create the hotel timezone setting if it does not exist yet.
INSERT INTO `emulator_settings` (`key`, `value`)
SELECT 'hotel.timezone', 'Europe/Rome'
WHERE NOT EXISTS (
SELECT 1
FROM `emulator_settings`
WHERE `key` = 'hotel.timezone'
);
-- Keep the default/example value aligned for existing installs too.
UPDATE `emulator_settings`
SET `value` = 'Europe/Rome'
WHERE `key` = 'hotel.timezone';
-- Helper query for a timezone selector.
-- If MySQL/MariaDB timezone tables are populated, this returns the available timezone ids.
SELECT `Name` AS `timezone_id`
FROM `mysql`.`time_zone_name`
WHERE `Name` IS NOT NULL
ORDER BY `Name`;
@@ -1,12 +0,0 @@
CREATE TABLE IF NOT EXISTS `user_prefixes` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`user_id` INT(11) NOT NULL,
`text` VARCHAR(50) NOT NULL,
`color` VARCHAR(255) NOT NULL DEFAULT '#FFFFFF',
`icon` VARCHAR(50) NOT NULL DEFAULT '',
`effect` VARCHAR(50) NOT NULL DEFAULT '',
`active` TINYINT(1) NOT NULL DEFAULT 0,
PRIMARY KEY (`id`),
INDEX `idx_user_id` (`user_id`),
INDEX `idx_user_active` (`user_id`, `active`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-71
View File
@@ -1,71 +0,0 @@
-- ============================================================
-- Camera - Database Setup
-- Run this SQL manually before using the camera feature.
-- ============================================================
-- -----------------------------------------
-- Table: camera_web (stores published photos)
-- -----------------------------------------
CREATE TABLE IF NOT EXISTS `camera_web` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`user_id` INT(11) NOT NULL,
`room_id` INT(11) NOT NULL DEFAULT 0,
`timestamp` INT(11) NOT NULL DEFAULT 0,
`url` VARCHAR(255) NOT NULL DEFAULT '',
PRIMARY KEY (`id`),
INDEX `idx_camera_web_user_id` (`user_id`),
INDEX `idx_camera_web_timestamp` (`timestamp`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
-- -----------------------------------------
-- Emulator Settings for Camera
-- -----------------------------------------
-- Uses INSERT IGNORE so existing values are not overwritten.
-- Base URL where camera photos are served (include trailing slash)
INSERT IGNORE INTO `emulator_settings` (`key`, `value`) VALUES
('camera.url', 'http://localhost/camera/');
-- Filesystem path where full-size camera photos are saved (include trailing slash)
INSERT IGNORE INTO `emulator_settings` (`key`, `value`) VALUES
('imager.location.output.camera', '/path/to/www/camera/');
-- Filesystem path where room thumbnail images are saved (include trailing slash)
INSERT IGNORE INTO `emulator_settings` (`key`, `value`) VALUES
('imager.location.output.thumbnail', '/path/to/www/thumbnails/');
-- Item ID for the wall photo item (must exist in items_base with interaction type "external_image")
INSERT IGNORE INTO `emulator_settings` (`key`, `value`) VALUES
('camera.item_id', '0');
-- Price in credits to purchase a photo as a wall item
INSERT IGNORE INTO `emulator_settings` (`key`, `value`) VALUES
('camera.price.credits', '2');
-- Price in seasonal points to purchase a photo as a wall item
INSERT IGNORE INTO `emulator_settings` (`key`, `value`) VALUES
('camera.price.points', '0');
-- Price in seasonal points to publish a photo to the web
INSERT IGNORE INTO `emulator_settings` (`key`, `value`) VALUES
('camera.price.points.publish', '1');
-- JSON template for photo item extradata
-- Available placeholders: %timestamp%, %room_id%, %url%, %id%
INSERT IGNORE INTO `emulator_settings` (`key`, `value`) VALUES
('camera.extradata', '{"t":"%timestamp%","u":"%id%","m":"","s":"%room_id%","w":"%url%"}');
-- -----------------------------------------
-- Emulator Texts for Camera
-- -----------------------------------------
INSERT IGNORE INTO `emulator_texts` (`key`, `value`) VALUES
('camera.permission', 'You do not have permission to use the camera.');
INSERT IGNORE INTO `emulator_texts` (`key`, `value`) VALUES
('camera.wait', 'Please wait %seconds% more seconds before taking another photo.');
INSERT IGNORE INTO `emulator_texts` (`key`, `value`) VALUES
('camera.error.creation', 'An error occurred while processing your photo. Please try again.');
INSERT IGNORE INTO `emulator_texts` (`key`, `value`) VALUES
('camera.daily.limit', 'You have reached the daily photo limit. Try again tomorrow.');
@@ -1 +0,0 @@
INSERT INTO emulator_settings (`key`, `value`) VALUES ('pathfinder.diagonal.enabled', '1');
-4
View File
@@ -1,4 +0,0 @@
### New bot walking settings
INSERT INTO `emulator_settings` (`key`, `value`) VALUES ('hotel.bot.limit.walking.distance', '1');
INSERT INTO `emulator_settings` (`key`, `value`) VALUES ('hotel.bot.limit.walking.distance.radius', '5');
@@ -1,4 +0,0 @@
ALTER TABLE `users`
ADD COLUMN `background_id` INT(11) NOT NULL DEFAULT 0 AFTER `machine_id`,
ADD COLUMN `background_stand_id` INT(11) NOT NULL DEFAULT 0 AFTER `background_id`,
ADD COLUMN `background_overlay_id` INT(11) NOT NULL DEFAULT 0 AFTER `background_stand_id`;
@@ -1,5 +0,0 @@
ALTER TABLE `camwijs`.`permissions`
ADD COLUMN `cms_dance` ENUM('0', '1') NULL DEFAULT '0' AFTER `cmd_credits`;
INSERT INTO emulator_texts (`key`, `value`) VALUES ('commands.description.cmd_dance', 'dance around the world ! use 1 t/m 4 and 0 to stop');
INSERT INTO emulator_texts (`key`, `value`) VALUES ('commands.keys.cmd_dance', 'dance');
@@ -1,4 +0,0 @@
UPDATE `emulator_texts` SET `key` = 'generic.pet.happiness', `value` = 'Happiness' WHERE `key` = 'generic.pet.happyness';
ALTER TABLE `pet_commands_data` CHANGE `cost_happyness` `cost_happiness` int(11) NOT NULL DEFAULT '0';
ALTER TABLE `users_pets` CHANGE `happyness` `happiness` int(11) NOT NULL DEFAULT '100';
@@ -1,6 +0,0 @@
### WEBSOCKET SETTINGS
INSERT INTO `emulator_settings` (`key`, `value`) VALUES ('websockets.whitelist', 'localhost'); # Change this to the url of the websocket Expl. ws.mydomain.com
INSERT INTO `emulator_settings` (`key`, `value`) VALUES ('ws.nitro.host', '0.0.0.0'); # Best is this to leave it at 0.0.0.0
INSERT INTO `emulator_settings` (`key`, `value`) VALUES ('ws.nitro.ip.header', ''); # When useing a proxy change the header : X-Forwarded-For when using a proxy server or CF-Connecting-IP if behind Cloudflare.
INSERT INTO `emulator_settings` (`key`, `value`) VALUES ('ws.nitro.port', '2096'); # set the port of the websocket, cloudflare ports : 443 / 2053 / 2083 / 2087 / 2096 / 8443
@@ -1,2 +0,0 @@
--New permission
ALTER TABLE `permissions` ADD COLUMN `acc_unignorable` ENUM('0','1') NOT NULL DEFAULT '0';
-3
View File
@@ -1,3 +0,0 @@
# Default ignored files
/shelf/
/workspace.xml
-13
View File
@@ -1,13 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<annotationProcessing>
<profile name="Maven default annotation processors profile" enabled="true">
<sourceOutputDir name="target/generated-sources/annotations" />
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
<outputRelativeToContentRoot value="true" />
<module name="Habbo" />
</profile>
</annotationProcessing>
</component>
</project>
-7
View File
@@ -1,7 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding">
<file url="file://$PROJECT_DIR$/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/src/main/resources" charset="UTF-8" />
</component>
</project>
-25
View File
@@ -1,25 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RemoteRepositoriesConfiguration">
<remote-repository>
<option name="id" value="central" />
<option name="name" value="central" />
<option name="url" value="https://repo1.maven.org/maven2/" />
</remote-repository>
<remote-repository>
<option name="id" value="central" />
<option name="name" value="Maven Central repository" />
<option name="url" value="https://repo1.maven.org/maven2" />
</remote-repository>
<remote-repository>
<option name="id" value="mvnrepo" />
<option name="name" value="mvnrepo" />
<option name="url" value="https://mvnrepository.com/" />
</remote-repository>
<remote-repository>
<option name="id" value="jboss.community" />
<option name="name" value="JBoss Community repository" />
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
</remote-repository>
</component>
</project>
-12
View File
@@ -1,12 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="MavenProjectsManager">
<option name="originalFiles">
<list>
<option value="$PROJECT_DIR$/pom.xml" />
</list>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_21" default="true" project-jdk-name="graalvm-jdk-21" project-jdk-type="JavaSDK" />
</project>
@@ -4,7 +4,6 @@ import com.eu.habbo.Emulator;
import com.eu.habbo.habbohotel.guilds.forums.ForumThread;
import com.eu.habbo.habbohotel.users.Habbo;
import com.eu.habbo.messages.incoming.friends.SearchUserEvent;
import com.eu.habbo.messages.incoming.navigator.SearchRoomsEvent;
import com.eu.habbo.messages.outgoing.users.UserDataComposer;
import com.eu.habbo.threading.runnables.AchievementUpdater;
import org.slf4j.Logger;
@@ -101,8 +100,7 @@ public class CleanerThread implements Runnable {
LAST_HABBO_CACHE_CLEARED = time;
}
SearchRoomsEvent.cachedResults.clear();
SearchUserEvent.cachedResults.clear();
SearchUserEvent.cleanExpiredCache();
}
@@ -130,8 +130,8 @@ public class Room implements Comparable<Room>, ISerialize, Runnable {
private String password;
private RoomState state;
private int usersMax;
private volatile int score;
private volatile int category;
private int score;
private int category;
private String floorPaint;
private String wallPaint;
private String backgroundPaint;
@@ -140,41 +140,41 @@ public class Room implements Comparable<Room>, ISerialize, Runnable {
private int floorSize;
private int guild;
private String tags;
private volatile boolean publicRoom;
private volatile boolean staffPromotedRoom;
private volatile boolean allowPets;
private volatile boolean allowPetsEat;
private volatile boolean allowWalkthrough;
private volatile boolean allowBotsWalk;
private volatile boolean allowEffects;
private volatile boolean hideWall;
private volatile int chatMode;
private volatile int chatWeight;
private volatile int chatSpeed;
private volatile int chatDistance;
private volatile int chatProtection;
private volatile int muteOption;
private volatile int kickOption;
private volatile int banOption;
private volatile int pollId;
private volatile boolean promoted;
private volatile int tradeMode;
private volatile boolean moveDiagonally;
private volatile boolean allowUnderpass;
private volatile boolean jukeboxActive;
private volatile boolean hideWired;
private boolean publicRoom;
private boolean staffPromotedRoom;
private boolean allowPets;
private boolean allowPetsEat;
private boolean allowWalkthrough;
private boolean allowBotsWalk;
private boolean allowEffects;
private boolean hideWall;
private int chatMode;
private int chatWeight;
private int chatSpeed;
private int chatDistance;
private int chatProtection;
private int muteOption;
private int kickOption;
private int banOption;
private int pollId;
private boolean promoted;
private int tradeMode;
private boolean moveDiagonally;
private boolean allowUnderpass;
private boolean jukeboxActive;
private boolean hideWired;
private RoomPromotion promotion;
private volatile boolean needsUpdate;
private volatile boolean loaded;
private volatile boolean preLoaded;
private volatile boolean loadingInProgress;
private volatile CompletableFuture<Void> loadingFuture;
private volatile int rollerSpeed;
private volatile int lastTimerReset = Emulator.getIntUnixTimestamp();
private int rollerSpeed;
private int lastTimerReset = Emulator.getIntUnixTimestamp();
private volatile boolean muted;
private RoomSpecialTypes roomSpecialTypes;
private TraxManager traxManager;
public final THashMap<String, Object> cache;
public Room(ResultSet set) throws SQLException {
@@ -222,8 +222,8 @@ public class Room implements Comparable<Room>, ISerialize, Runnable {
this.bannedHabbos = new TIntObjectHashMap<>();
try (Connection connection = Emulator.getDatabase().getDataSource()
.getConnection(); PreparedStatement statement = connection.prepareStatement(
"SELECT * FROM room_promotions WHERE room_id = ? AND end_timestamp > ? LIMIT 1")) {
.getConnection(); PreparedStatement statement = connection.prepareStatement(
"SELECT * FROM room_promotions WHERE room_id = ? AND end_timestamp > ? LIMIT 1")) {
if (this.promoted) {
statement.setInt(1, this.id);
statement.setInt(2, Emulator.getIntUnixTimestamp());
@@ -398,7 +398,7 @@ public class Room implements Comparable<Room>, ISerialize, Runnable {
if (this.loaded || this.loadingInProgress || !this.preLoaded) {
return;
}
this.loadingInProgress = true;
this.loadingFuture = CompletableFuture.runAsync(() -> {
this.loadDataInternal();
@@ -418,7 +418,7 @@ public class Room implements Comparable<Room>, ISerialize, Runnable {
}
future = this.loadingFuture;
}
if (future != null) {
try {
future.join();
@@ -433,7 +433,7 @@ public class Room implements Comparable<Room>, ISerialize, Runnable {
public void loadData() {
CompletableFuture<Void> futureToWait = null;
boolean shouldLoad = false;
synchronized (this.loadLock) {
if (this.loadingInProgress) {
// Get the future to wait on outside the lock
@@ -443,7 +443,7 @@ public class Room implements Comparable<Room>, ISerialize, Runnable {
shouldLoad = true;
}
}
// Wait for existing load outside the lock
if (futureToWait != null) {
try {
@@ -453,7 +453,7 @@ public class Room implements Comparable<Room>, ISerialize, Runnable {
}
return;
}
// Load if needed
if (shouldLoad) {
this.loadDataInternal();
@@ -567,7 +567,7 @@ public class Room implements Comparable<Room>, 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);
}
@@ -586,7 +586,7 @@ public class Room implements Comparable<Room>, ISerialize, Runnable {
item.setExtradata("1");
this.updateItem(item);
}
// Set loaded flag with lock
synchronized (this.loadLock) {
this.loaded = true;
@@ -603,7 +603,7 @@ public class Room implements Comparable<Room>, ISerialize, Runnable {
this.layout = Emulator.getGameEnvironment().getRoomManager().loadCustomLayout(this);
} else {
this.layout = Emulator.getGameEnvironment().getRoomManager()
.loadLayout(this.layoutName, this);
.loadLayout(this.layoutName, this);
}
}
}
@@ -635,7 +635,7 @@ public class Room implements Comparable<Room>, 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()) {
@@ -646,11 +646,11 @@ public class Room implements Comparable<Room>, 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"));
@@ -674,7 +674,7 @@ public class Room implements Comparable<Room>, 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()) {
@@ -684,11 +684,11 @@ public class Room implements Comparable<Room>, 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")]);
@@ -760,7 +760,7 @@ public class Room implements Comparable<Room>, ISerialize, Runnable {
THashSet<RoomTile> 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++) {
@@ -784,7 +784,7 @@ public class Room implements Comparable<Room>, 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));
@@ -1022,7 +1022,7 @@ public class Room implements Comparable<Room>, 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);
@@ -1086,8 +1086,8 @@ public class Room implements Comparable<Room>, 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);
@@ -1152,8 +1152,8 @@ public class Room implements Comparable<Room>, 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();
@@ -1467,7 +1467,7 @@ public class Room implements Comparable<Room>, 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]));
}
}
}
@@ -1574,7 +1574,7 @@ public class Room implements Comparable<Room>, ISerialize, Runnable {
public String[] filterAnything() {
return new String[]{this.getOwnerName(), this.getGuildName(), this.getDescription(),
this.getPromotionDesc()};
this.getPromotionDesc()};
}
public long getCycleTimestamp() {
@@ -1906,7 +1906,7 @@ public class Room implements Comparable<Room>, ISerialize, Runnable {
}
public void talk(final Habbo habbo, final RoomChatMessage roomChatMessage, RoomChatType chatType,
boolean ignoreWired) {
boolean ignoreWired) {
this.chatManager.talk(habbo, roomChatMessage, chatType, ignoreWired);
}
@@ -2051,7 +2051,7 @@ public class Room implements Comparable<Room>, 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()) {
@@ -2067,7 +2067,7 @@ public class Room implements Comparable<Room>, 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()) {
@@ -2089,7 +2089,7 @@ public class Room implements Comparable<Room>, 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;
}
@@ -2167,15 +2167,15 @@ public class Room implements Comparable<Room>, 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);
@@ -2189,11 +2189,11 @@ public class Room implements Comparable<Room>, 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());
@@ -2227,9 +2227,9 @@ public class Room implements Comparable<Room>, 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());
}
@@ -2251,8 +2251,8 @@ public class Room implements Comparable<Room>, 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);
@@ -2289,18 +2289,18 @@ public class Room implements Comparable<Room>, ISerialize, Runnable {
public void refreshGuild(Guild guild) {
if (guild.getRoomId() == this.id) {
THashSet<GuildMember> members = Emulator.getGameEnvironment().getGuildManager()
.getGuildMembers(guild.getId());
.getGuildMembers(guild.getId());
for (Habbo habbo : this.getHabbos()) {
Optional<GuildMember> 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()));
}
}
@@ -2335,7 +2335,7 @@ public class Room implements Comparable<Room>, 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);
}
}
@@ -2421,18 +2421,18 @@ public class Room implements Comparable<Room>, 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);
}
@@ -2441,17 +2441,17 @@ public class Room implements Comparable<Room>, 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);
}
@@ -2460,17 +2460,17 @@ public class Room implements Comparable<Room>, 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);
}
@@ -2487,12 +2487,12 @@ public class Room implements Comparable<Room>, 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);
}
@@ -40,6 +40,7 @@ import com.eu.habbo.messages.outgoing.rooms.pets.RoomPetComposer;
import com.eu.habbo.messages.outgoing.rooms.promotions.RoomPromotionMessageComposer;
import com.eu.habbo.messages.outgoing.rooms.users.*;
import com.eu.habbo.messages.outgoing.users.MutedWhisperComposer;
import com.eu.habbo.messages.outgoing.users.UserBadgesComposer;
import com.eu.habbo.plugin.events.navigator.NavigatorRoomCreatedEvent;
import com.eu.habbo.plugin.events.rooms.RoomFloorItemsLoadEvent;
import com.eu.habbo.plugin.events.rooms.RoomUncachedEvent;
@@ -72,6 +73,7 @@ public class RoomManager {
private final THashMap<Integer, RoomCategory> roomCategories;
private final List<String> mapNames;
private final ConcurrentHashMap<Integer, Room> activeRooms;
private final ConcurrentHashMap<Integer, Set<Integer>> roomsByOwner;
private final ArrayList<Class<? extends Game>> gameTypes;
public RoomManager() {
@@ -79,6 +81,7 @@ public class RoomManager {
this.roomCategories = new THashMap<>();
this.mapNames = new ArrayList<>();
this.activeRooms = new ConcurrentHashMap<>();
this.roomsByOwner = new ConcurrentHashMap<>();
this.loadRoomCategories();
this.loadRoomModels();
@@ -95,6 +98,20 @@ public class RoomManager {
LOGGER.info("Room Manager -> Loaded! ({} MS)", System.currentTimeMillis() - millis);
}
private void trackRoomOwner(Room room) {
this.roomsByOwner.computeIfAbsent(room.getOwnerId(), k -> ConcurrentHashMap.newKeySet()).add(room.getId());
}
private void untrackRoomOwner(Room room) {
Set<Integer> rooms = this.roomsByOwner.get(room.getOwnerId());
if (rooms != null) {
rooms.remove(room.getId());
if (rooms.isEmpty()) {
this.roomsByOwner.remove(room.getOwnerId());
}
}
}
public void loadRoomModels() {
this.mapNames.clear();
try (Connection connection = Emulator.getDatabase().getDataSource().getConnection(); Statement statement = connection.createStatement(); ResultSet set = statement.executeQuery("SELECT * FROM room_models")) {
@@ -143,6 +160,7 @@ public class RoomManager {
Room room = new Room(set);
room.preventUncaching = true;
this.activeRooms.put(set.getInt("id"), room);
this.trackRoomOwner(room);
}
}
} catch (SQLException e) {
@@ -162,6 +180,7 @@ public class RoomManager {
if (room == null) {
room = new Room(set);
this.activeRooms.put(set.getInt("id"), room);
this.trackRoomOwner(room);
}
if (!rooms.containsKey(set.getInt("category"))) {
@@ -179,12 +198,7 @@ public class RoomManager {
}
public RoomCategory getCategory(int id) {
for (RoomCategory category : this.roomCategories.values()) {
if (category.getId() == id)
return category;
}
return null;
return this.roomCategories.get(id);
}
public RoomCategory getCategory(String name) {
@@ -220,15 +234,8 @@ public class RoomManager {
}
public boolean hasCategory(int categoryId, Habbo habbo) {
for (RoomCategory category : this.roomCategories.values()) {
if (category.getId() == categoryId) {
if (category.getMinRank() <= habbo.getHabboInfo().getRank().getId()) {
return true;
}
}
}
return false;
RoomCategory category = this.roomCategories.get(categoryId);
return category != null && category.getMinRank() <= habbo.getHabboInfo().getRank().getId();
}
public THashMap<Integer, RoomCategory> getRoomCategories() {
@@ -333,6 +340,7 @@ public class RoomManager {
if (room != null) {
this.activeRooms.put(room.getId(), room);
this.trackRoomOwner(room);
}
} catch (SQLException e) {
LOGGER.error("Caught SQL exception", e);
@@ -380,8 +388,11 @@ public class RoomManager {
statement.setInt(1, habbo.getHabboInfo().getId());
try (ResultSet set = statement.executeQuery()) {
while (set.next()) {
if (!this.activeRooms.containsKey(set.getInt("id")))
this.activeRooms.put(set.getInt("id"), new Room(set));
if (!this.activeRooms.containsKey(set.getInt("id"))) {
Room room = new Room(set);
this.activeRooms.put(room.getId(), room);
this.trackRoomOwner(room);
}
}
}
} catch (SQLException e) {
@@ -402,22 +413,31 @@ public class RoomManager {
continue;
room.dispose();
this.untrackRoomOwner(room);
this.activeRooms.remove(room.getId());
}
}
public void clearInactiveRooms() {
THashSet<Room> roomsToDispose = new THashSet<>();
for (Room room : this.activeRooms.values()) {
if (!room.isPublicRoom() && !room.isStaffPromotedRoom() && !Emulator.getGameServer().getGameClientManager().containsHabbo(room.getOwnerId()) && room.isPreLoaded()) {
roomsToDispose.add(room);
for (Map.Entry<Integer, Set<Integer>> entry : this.roomsByOwner.entrySet()) {
int ownerId = entry.getKey();
if (!Emulator.getGameServer().getGameClientManager().containsHabbo(ownerId)) {
for (int roomId : entry.getValue()) {
Room room = this.activeRooms.get(roomId);
if (room != null && !room.isPublicRoom() && !room.isStaffPromotedRoom() && room.isPreLoaded()) {
roomsToDispose.add(room);
}
}
}
}
for (Room room : roomsToDispose) {
room.dispose();
if (room.getUserCount() == 0)
if (room.getUserCount() == 0) {
this.untrackRoomOwner(room);
this.activeRooms.remove(room.getId());
}
}
}
@@ -446,6 +466,7 @@ public class RoomManager {
}
public void uncacheRoom(Room room) {
this.untrackRoomOwner(room);
this.activeRooms.remove(room.getId());
}
@@ -745,6 +766,9 @@ 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<Habbo> habbos = new ArrayList<>();
if (!room.getCurrentHabbos().isEmpty()) {
@@ -1137,6 +1161,7 @@ public class RoomManager {
Room r = new Room(set);
rooms.add(r);
this.activeRooms.put(r.getId(), r);
this.trackRoomOwner(r);
}
}
} catch (SQLException e) {
@@ -1197,6 +1222,7 @@ public class RoomManager {
rooms.add(r);
this.activeRooms.put(r.getId(), r);
this.trackRoomOwner(r);
}
}
} catch (SQLException e) {
@@ -1260,6 +1286,7 @@ public class RoomManager {
room = new Room(set);
this.activeRooms.put(room.getId(), room);
this.trackRoomOwner(room);
}
rooms.add(room);
@@ -1501,6 +1528,7 @@ public class RoomManager {
room.dispose();
}
this.roomsByOwner.clear();
this.activeRooms.clear();
LOGGER.info("Room Manager -> Disposed!");
@@ -259,7 +259,7 @@ public class Habbo implements Runnable {
this.getHabboInfo().addCredits(event.credits);
if (this.client != null) this.client.sendResponse(new UserCreditsComposer(this.client.getHabbo()));
if (this.client != null) this.client.sendResponse(new UserCreditsComposer(this));
}
@@ -35,11 +35,13 @@ public class HabboManager {
public static boolean NAMECHANGE_ENABLED = false;
private final ConcurrentHashMap<Integer, Habbo> onlineHabbos;
private final ConcurrentHashMap<String, Habbo> onlineHabbosByName;
public HabboManager() {
long millis = System.currentTimeMillis();
this.onlineHabbos = new ConcurrentHashMap<>();
this.onlineHabbosByName = new ConcurrentHashMap<>();
LOGGER.info("Habbo Manager -> Loaded! ({} MS)", System.currentTimeMillis() - millis);
}
@@ -80,10 +82,12 @@ public class HabboManager {
public void addHabbo(Habbo habbo) {
this.onlineHabbos.put(habbo.getHabboInfo().getId(), habbo);
this.onlineHabbosByName.put(habbo.getHabboInfo().getUsername().toLowerCase(), habbo);
}
public void removeHabbo(Habbo habbo) {
this.onlineHabbos.remove(habbo.getHabboInfo().getId());
this.onlineHabbosByName.remove(habbo.getHabboInfo().getUsername().toLowerCase());
}
public Habbo getHabbo(int id) {
@@ -91,14 +95,7 @@ public class HabboManager {
}
public Habbo getHabbo(String username) {
synchronized (this.onlineHabbos) {
for (Map.Entry<Integer, Habbo> map : this.onlineHabbos.entrySet()) {
if (map.getValue().getHabboInfo().getUsername().equalsIgnoreCase(username))
return map.getValue();
}
}
return null;
return this.onlineHabbosByName.get(username.toLowerCase());
}
public Habbo loadHabbo(String sso) {
@@ -178,11 +175,9 @@ public class HabboManager {
}
public void sendPacketToHabbosWithPermission(ServerMessage message, String perm) {
synchronized (this.onlineHabbos) {
for (Habbo habbo : this.onlineHabbos.values()) {
if (habbo.hasPermission(perm)) {
habbo.getClient().sendResponse(message);
}
for (Habbo habbo : this.onlineHabbos.values()) {
if (habbo.hasPermission(perm)) {
habbo.getClient().sendResponse(message);
}
}
}
@@ -159,14 +159,63 @@ public class ItemsComponent {
}
if (!this.items.isEmpty()) {
for (int i = this.items.size(); i-- > 0; ) {
try {
items.advance();
} catch (NoSuchElementException e) {
break;
try (Connection connection = Emulator.getDatabase().getDataSource().getConnection()) {
try (PreparedStatement updateStmt = connection.prepareStatement(
"UPDATE items SET user_id = ?, room_id = ?, wall_pos = ?, x = ?, y = ?, z = ?, rot = ?, extra_data = ?, limited_data = ? WHERE id = ?")) {
try (PreparedStatement deleteStmt = connection.prepareStatement(
"DELETE FROM items WHERE id = ?")) {
int updateCount = 0;
int deleteCount = 0;
for (int i = this.items.size(); i-- > 0; ) {
try {
items.advance();
} catch (NoSuchElementException e) {
break;
}
HabboItem item = items.value();
if (item.needsDelete()) {
deleteStmt.setInt(1, item.getId());
deleteStmt.addBatch();
deleteCount++;
item.needsUpdate(false);
item.needsDelete(false);
} else if (item.needsUpdate()) {
updateStmt.setInt(1, item.getUserId());
updateStmt.setInt(2, item.getRoomId());
updateStmt.setString(3, item.getWallPosition());
updateStmt.setInt(4, item.getX());
updateStmt.setInt(5, item.getY());
updateStmt.setDouble(6, item.getZ());
updateStmt.setInt(7, item.getRotation());
updateStmt.setString(8, item.getExtradata());
updateStmt.setString(9, item.getLimitedStack() + ":" + item.getLimitedSells());
updateStmt.setInt(10, item.getId());
updateStmt.addBatch();
updateCount++;
item.needsUpdate(false);
}
if (updateCount > 0 && updateCount % 100 == 0) {
updateStmt.executeBatch();
}
if (deleteCount > 0 && deleteCount % 100 == 0) {
deleteStmt.executeBatch();
}
}
if (deleteCount % 100 != 0) {
deleteStmt.executeBatch();
}
if (updateCount % 100 != 0) {
updateStmt.executeBatch();
}
}
}
if (items.value().needsUpdate())
Emulator.getThreading().run(items.value());
} catch (SQLException e) {
LOGGER.error("Caught SQL exception during batch item save", e);
}
}
@@ -3,7 +3,6 @@ package com.eu.habbo.messages.incoming.friends;
import com.eu.habbo.Emulator;
import com.eu.habbo.habbohotel.messenger.Messenger;
import com.eu.habbo.habbohotel.users.Habbo;
import com.eu.habbo.habbohotel.users.HabboInfo;
import com.eu.habbo.messages.incoming.MessageHandler;
import com.eu.habbo.messages.outgoing.friends.FriendRequestErrorComposer;
import org.slf4j.Logger;
@@ -14,7 +13,6 @@ import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import static com.eu.habbo.habbohotel.users.HabboManager.getOfflineHabboInfo;
public class AcceptFriendRequestEvent extends MessageHandler {
private static final Logger LOGGER = LoggerFactory.getLogger(AcceptFriendRequestEvent.class);
@@ -44,18 +42,10 @@ public class AcceptFriendRequestEvent extends MessageHandler {
Habbo target = Emulator.getGameEnvironment().getHabboManager().getHabbo(userId);
if(target == null) {
HabboInfo habboInfo = getOfflineHabboInfo(userId);
if(habboInfo == null) {
this.client.sendResponse(new FriendRequestErrorComposer(FriendRequestErrorComposer.TARGET_NOT_FOUND));
this.client.getHabbo().getMessenger().deleteFriendRequests(userId, this.client.getHabbo().getHabboInfo().getId());
continue;
}
try (Connection connection = Emulator.getDatabase().getDataSource().getConnection(); PreparedStatement statement = connection.prepareStatement("SELECT users.*, users_settings.block_friendrequests FROM users INNER JOIN users_settings ON users.id = users_settings.user_id WHERE username = ? LIMIT 1")) {
statement.setString(1, habboInfo.getUsername());
try (Connection connection = Emulator.getDatabase().getDataSource().getConnection(); PreparedStatement statement = connection.prepareStatement("SELECT users.*, users_settings.block_friendrequests FROM users INNER JOIN users_settings ON users.id = users_settings.user_id WHERE users.id = ? LIMIT 1")) {
statement.setInt(1, userId);
try (ResultSet set = statement.executeQuery()) {
while (set.next()) {
if (set.next()) {
target = new Habbo(set);
}
}
@@ -9,7 +9,20 @@ import gnu.trove.set.hash.THashSet;
import java.util.concurrent.ConcurrentHashMap;
public class SearchUserEvent extends MessageHandler {
public static ConcurrentHashMap<String, THashSet<MessengerBuddy>> cachedResults = new ConcurrentHashMap<>();
private static final long CACHE_TTL_MS = 30_000; // 30 second TTL
private static final ConcurrentHashMap<String, Long> cacheTimestamps = new ConcurrentHashMap<>();
public static final ConcurrentHashMap<String, THashSet<MessengerBuddy>> cachedResults = new ConcurrentHashMap<>();
public static void cleanExpiredCache() {
long now = System.currentTimeMillis();
cacheTimestamps.entrySet().removeIf(entry -> {
if (now - entry.getValue() > CACHE_TTL_MS) {
cachedResults.remove(entry.getKey());
return true;
}
return false;
});
}
@Override
public void handle() throws Exception {
@@ -31,6 +44,7 @@ public class SearchUserEvent extends MessageHandler {
if (buddies == null) {
buddies = Messenger.searchUsers(username);
cachedResults.put(username, buddies);
cacheTimestamps.put(username, System.currentTimeMillis());
}
this.client.sendResponse(new UserSearchResultComposer(buddies, this.client.getHabbo().getMessenger().getFriends(username), this.client.getHabbo()));