You've already forked Arcturus-Morningstar-Extended
mirror of
https://github.com/duckietm/Arcturus-Morningstar-Extended.git
synced 2026-06-19 15:06:19 +00:00
@@ -29,6 +29,7 @@
|
||||
-- 15. 17032026_allow_underpass.sql
|
||||
-- 16. 19032026_hotel_timezone.sql
|
||||
-- 17. 21022026_user_prefixes.sql
|
||||
-- 18. 06042026_builders_club_catalog_offers.sql
|
||||
-- =============================================================================
|
||||
|
||||
SET NAMES utf8mb4;
|
||||
@@ -213,8 +214,8 @@ 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.enabled', '1'),
|
||||
('wired.engine.exclusive', '1'),
|
||||
('wired.engine.maxStepsPerStack', '100'),
|
||||
('wired.engine.debug', '0')
|
||||
ON DUPLICATE KEY UPDATE `key` = `key`;
|
||||
@@ -408,6 +409,109 @@ CREATE TABLE IF NOT EXISTS `user_prefixes` (
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
|
||||
-- =============================================================================
|
||||
-- From: 06042026_builders_club_catalog_offers.sql
|
||||
-- =============================================================================
|
||||
ALTER TABLE `catalog_club_offers`
|
||||
MODIFY COLUMN `type` ENUM('HC','VIP','BUILDERS_CLUB','BUILDERS_CLUB_ADDON') NOT NULL DEFAULT 'HC';
|
||||
|
||||
ALTER TABLE `catalog_pages`
|
||||
MODIFY COLUMN `page_layout` ENUM(
|
||||
'default_3x3',
|
||||
'club_buy',
|
||||
'club_gift',
|
||||
'frontpage',
|
||||
'spaces',
|
||||
'recycler',
|
||||
'recycler_info',
|
||||
'recycler_prizes',
|
||||
'trophies',
|
||||
'plasto',
|
||||
'marketplace',
|
||||
'marketplace_own_items',
|
||||
'spaces_new',
|
||||
'soundmachine',
|
||||
'guilds',
|
||||
'guild_furni',
|
||||
'info_duckets',
|
||||
'info_rentables',
|
||||
'info_pets',
|
||||
'roomads',
|
||||
'single_bundle',
|
||||
'sold_ltd_items',
|
||||
'badge_display',
|
||||
'bots',
|
||||
'pets',
|
||||
'pets2',
|
||||
'pets3',
|
||||
'productpage1',
|
||||
'room_bundle',
|
||||
'recent_purchases',
|
||||
'default_3x3_color_grouping',
|
||||
'guild_forum',
|
||||
'vip_buy',
|
||||
'info_loyalty',
|
||||
'loyalty_vip_buy',
|
||||
'collectibles',
|
||||
'petcustomization',
|
||||
'frontpage_featured',
|
||||
'builders_club_frontpage',
|
||||
'builders_club_addons',
|
||||
'builders_club_loyalty'
|
||||
) NOT NULL DEFAULT 'default_3x3';
|
||||
|
||||
ALTER TABLE `catalog_pages`
|
||||
ADD COLUMN `catalog_mode` ENUM('NORMAL','BUILDER','BOTH') NOT NULL DEFAULT 'NORMAL' AFTER `club_only`;
|
||||
|
||||
ALTER TABLE `catalog_pages_bc`
|
||||
MODIFY COLUMN `page_layout` ENUM(
|
||||
'default_3x3',
|
||||
'club_buy',
|
||||
'club_gift',
|
||||
'frontpage',
|
||||
'spaces',
|
||||
'recycler',
|
||||
'recycler_info',
|
||||
'recycler_prizes',
|
||||
'trophies',
|
||||
'plasto',
|
||||
'marketplace',
|
||||
'marketplace_own_items',
|
||||
'spaces_new',
|
||||
'soundmachine',
|
||||
'guilds',
|
||||
'guild_furni',
|
||||
'info_duckets',
|
||||
'info_rentables',
|
||||
'info_pets',
|
||||
'roomads',
|
||||
'single_bundle',
|
||||
'sold_ltd_items',
|
||||
'badge_display',
|
||||
'bots',
|
||||
'pets',
|
||||
'pets2',
|
||||
'pets3',
|
||||
'productpage1',
|
||||
'room_bundle',
|
||||
'recent_purchases',
|
||||
'default_3x3_color_grouping',
|
||||
'guild_forum',
|
||||
'vip_buy',
|
||||
'info_loyalty',
|
||||
'loyalty_vip_buy',
|
||||
'collectibles',
|
||||
'petcustomization',
|
||||
'frontpage_featured',
|
||||
'builders_club_frontpage',
|
||||
'builders_club_addons',
|
||||
'builders_club_loyalty'
|
||||
) NOT NULL DEFAULT 'default_3x3';
|
||||
|
||||
ALTER TABLE `users_settings`
|
||||
ADD COLUMN IF NOT EXISTS `builders_club_bonus_furni` INT(11) NOT NULL DEFAULT 0 AFTER `hc_gifts_claimed`;
|
||||
|
||||
|
||||
-- =============================================================================
|
||||
-- Done
|
||||
-- =============================================================================
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
CREATE TABLE IF NOT EXISTS `wired_emulator_settings` (
|
||||
`key` varchar(191) NOT NULL,
|
||||
`value` text NOT NULL,
|
||||
`comment` text NOT NULL,
|
||||
PRIMARY KEY (`key`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci;
|
||||
|
||||
INSERT INTO `wired_emulator_settings` (`key`, `value`, `comment`)
|
||||
SELECT 'wired.engine.enabled', COALESCE((SELECT `value` FROM `emulator_settings` WHERE `key` = 'wired.engine.enabled' LIMIT 1), '1'), 'Compatibility flag kept for older configs. The runtime now always uses the new wired engine.'
|
||||
UNION ALL
|
||||
SELECT 'wired.engine.exclusive', COALESCE((SELECT `value` FROM `emulator_settings` WHERE `key` = 'wired.engine.exclusive' LIMIT 1), '1'), 'Compatibility flag kept for older configs. The runtime now always uses the new wired engine.'
|
||||
UNION ALL
|
||||
SELECT 'wired.engine.maxStepsPerStack', COALESCE((SELECT `value` FROM `emulator_settings` WHERE `key` = 'wired.engine.maxStepsPerStack' LIMIT 1), '100'), 'Maximum amount of internal processing steps allowed for a single wired stack execution.'
|
||||
UNION ALL
|
||||
SELECT 'wired.engine.debug', COALESCE((SELECT `value` FROM `emulator_settings` WHERE `key` = 'wired.engine.debug' LIMIT 1), '0'), 'Enable verbose debug logging for the new wired engine.'
|
||||
UNION ALL
|
||||
SELECT 'wired.custom.enabled', COALESCE((SELECT `value` FROM `emulator_settings` WHERE `key` = 'wired.custom.enabled' LIMIT 1), '0'), 'Enable custom legacy wired behaviour such as user-based cooldown exceptions and compatibility logic.'
|
||||
UNION ALL
|
||||
SELECT 'hotel.wired.furni.selection.count', COALESCE((SELECT `value` FROM `emulator_settings` WHERE `key` = 'hotel.wired.furni.selection.count' LIMIT 1), '5'), 'Maximum number of furni that a wired box can store or select.'
|
||||
UNION ALL
|
||||
SELECT 'hotel.wired.max_delay', COALESCE((SELECT `value` FROM `emulator_settings` WHERE `key` = 'hotel.wired.max_delay' LIMIT 1), '20'), 'Maximum delay value accepted by wired effects that support delayed execution.'
|
||||
UNION ALL
|
||||
SELECT 'hotel.wired.message.max_length', COALESCE((SELECT `value` FROM `emulator_settings` WHERE `key` = 'hotel.wired.message.max_length' LIMIT 1), '100'), 'Maximum length of text fields used by wired messages and bot text effects.'
|
||||
UNION ALL
|
||||
SELECT 'wired.effect.teleport.delay', COALESCE((SELECT `value` FROM `emulator_settings` WHERE `key` = 'wired.effect.teleport.delay' LIMIT 1), '500'), 'Delay in milliseconds used by wired teleport movement.'
|
||||
UNION ALL
|
||||
SELECT 'wired.place.under', COALESCE((SELECT `value` FROM `emulator_settings` WHERE `key` = 'wired.place.under' LIMIT 1), '0'), 'Allow placing wired furniture underneath other items when room rules permit it.'
|
||||
UNION ALL
|
||||
SELECT 'wired.tick.interval.ms', COALESCE((SELECT `value` FROM `emulator_settings` WHERE `key` = 'wired.tick.interval.ms' LIMIT 1), '50'), 'Global wired tick interval in milliseconds used by repeaters and other tick-driven wired items.'
|
||||
UNION ALL
|
||||
SELECT 'wired.tick.resolution', COALESCE((SELECT `value` FROM `emulator_settings` WHERE `key` = 'wired.tick.resolution' LIMIT 1), '100'), 'Legacy wired tick resolution value kept for compatibility with older wired timing setups.'
|
||||
UNION ALL
|
||||
SELECT 'wired.tick.debug', COALESCE((SELECT `value` FROM `emulator_settings` WHERE `key` = 'wired.tick.debug' LIMIT 1), '0'), 'Enable verbose logging for the wired tick service.'
|
||||
UNION ALL
|
||||
SELECT 'wired.tick.thread.priority', COALESCE((SELECT `value` FROM `emulator_settings` WHERE `key` = 'wired.tick.thread.priority' LIMIT 1), '6'), 'Java thread priority used by the wired tick service.'
|
||||
UNION ALL
|
||||
SELECT 'wired.highscores.displaycount', COALESCE((SELECT `value` FROM `emulator_settings` WHERE `key` = 'wired.highscores.displaycount' LIMIT 1), '25'), 'Maximum number of wired highscore entries shown to users when a highscore is displayed.'
|
||||
UNION ALL
|
||||
SELECT 'wired.abuse.max.recursion.depth', COALESCE((SELECT `value` FROM `emulator_settings` WHERE `key` = 'wired.abuse.max.recursion.depth' LIMIT 1), '10'), 'Maximum recursive wired depth allowed before execution is stopped.'
|
||||
UNION ALL
|
||||
SELECT 'wired.abuse.max.events.per.window', COALESCE((SELECT `value` FROM `emulator_settings` WHERE `key` = 'wired.abuse.max.events.per.window' LIMIT 1), '100'), 'Maximum amount of identical wired events allowed inside the abuse rate-limit window before a room ban is applied.'
|
||||
UNION ALL
|
||||
SELECT 'wired.abuse.rate.limit.window.ms', COALESCE((SELECT `value` FROM `emulator_settings` WHERE `key` = 'wired.abuse.rate.limit.window.ms' LIMIT 1), '10000'), 'Time window in milliseconds used by the wired abuse rate limiter.'
|
||||
UNION ALL
|
||||
SELECT 'wired.abuse.ban.duration.ms', COALESCE((SELECT `value` FROM `emulator_settings` WHERE `key` = 'wired.abuse.ban.duration.ms' LIMIT 1), '600000'), 'Duration in milliseconds of the temporary wired ban after abuse detection.'
|
||||
UNION ALL
|
||||
SELECT 'wired.monitor.usage.window.ms', COALESCE((SELECT `value` FROM `emulator_settings` WHERE `key` = 'wired.monitor.usage.window.ms' LIMIT 1), '1000'), 'Rolling window size in milliseconds used to calculate wired usage in the :wired monitor.'
|
||||
UNION ALL
|
||||
SELECT 'wired.monitor.usage.limit', COALESCE((SELECT `value` FROM `emulator_settings` WHERE `key` = 'wired.monitor.usage.limit' LIMIT 1), '1000'), 'Maximum wired usage budget allowed in one monitor window before EXECUTION_CAP is raised.'
|
||||
UNION ALL
|
||||
SELECT 'wired.monitor.delayed.events.limit', COALESCE((SELECT `value` FROM `emulator_settings` WHERE `key` = 'wired.monitor.delayed.events.limit' LIMIT 1), '100'), 'Maximum number of delayed wired events that can be queued in one room at the same time.'
|
||||
UNION ALL
|
||||
SELECT 'wired.monitor.overload.average.ms', COALESCE((SELECT `value` FROM `emulator_settings` WHERE `key` = 'wired.monitor.overload.average.ms' LIMIT 1), '50'), 'Average execution time threshold in milliseconds that starts overload tracking.'
|
||||
UNION ALL
|
||||
SELECT 'wired.monitor.overload.peak.ms', COALESCE((SELECT `value` FROM `emulator_settings` WHERE `key` = 'wired.monitor.overload.peak.ms' LIMIT 1), '150'), 'Peak single execution time threshold in milliseconds that starts overload tracking.'
|
||||
UNION ALL
|
||||
SELECT 'wired.monitor.overload.consecutive.windows', COALESCE((SELECT `value` FROM `emulator_settings` WHERE `key` = 'wired.monitor.overload.consecutive.windows' LIMIT 1), '2'), 'Number of consecutive overloaded monitor windows required before logging EXECUTOR_OVERLOAD.'
|
||||
UNION ALL
|
||||
SELECT 'wired.monitor.heavy.usage.percent', COALESCE((SELECT `value` FROM `emulator_settings` WHERE `key` = 'wired.monitor.heavy.usage.percent' LIMIT 1), '70'), 'Usage percentage threshold that contributes to marking a room as heavy in the :wired monitor.'
|
||||
UNION ALL
|
||||
SELECT 'wired.monitor.heavy.consecutive.windows', COALESCE((SELECT `value` FROM `emulator_settings` WHERE `key` = 'wired.monitor.heavy.consecutive.windows' LIMIT 1), '5'), 'Number of consecutive windows above the heavy usage threshold required before the room is marked as heavy.'
|
||||
UNION ALL
|
||||
SELECT 'wired.monitor.heavy.delayed.percent', COALESCE((SELECT `value` FROM `emulator_settings` WHERE `key` = 'wired.monitor.heavy.delayed.percent' LIMIT 1), '60'), 'Delayed queue percentage threshold that also contributes to the heavy-room calculation.'
|
||||
ON DUPLICATE KEY UPDATE
|
||||
`value` = VALUES(`value`),
|
||||
`comment` = VALUES(`comment`);
|
||||
|
||||
DELETE FROM `emulator_settings`
|
||||
WHERE `key` IN (
|
||||
'wired.engine.enabled',
|
||||
'wired.engine.exclusive',
|
||||
'wired.engine.maxStepsPerStack',
|
||||
'wired.engine.debug',
|
||||
'wired.custom.enabled',
|
||||
'hotel.wired.furni.selection.count',
|
||||
'hotel.wired.max_delay',
|
||||
'hotel.wired.message.max_length',
|
||||
'wired.effect.teleport.delay',
|
||||
'wired.place.under',
|
||||
'wired.tick.interval.ms',
|
||||
'wired.tick.resolution',
|
||||
'wired.tick.debug',
|
||||
'wired.tick.thread.priority',
|
||||
'wired.highscores.displaycount',
|
||||
'wired.abuse.max.recursion.depth',
|
||||
'wired.abuse.max.events.per.window',
|
||||
'wired.abuse.rate.limit.window.ms',
|
||||
'wired.abuse.ban.duration.ms',
|
||||
'wired.monitor.usage.window.ms',
|
||||
'wired.monitor.usage.limit',
|
||||
'wired.monitor.delayed.events.limit',
|
||||
'wired.monitor.overload.average.ms',
|
||||
'wired.monitor.overload.peak.ms',
|
||||
'wired.monitor.overload.consecutive.windows',
|
||||
'wired.monitor.heavy.usage.percent',
|
||||
'wired.monitor.heavy.consecutive.windows',
|
||||
'wired.monitor.heavy.delayed.percent'
|
||||
);
|
||||
@@ -0,0 +1,332 @@
|
||||
ALTER TABLE `emulator_settings`
|
||||
ADD COLUMN IF NOT EXISTS `comment` text NOT NULL AFTER `value`;
|
||||
|
||||
UPDATE `emulator_settings` SET `comment` = 'Characters allowed when users choose or change a username.' WHERE `key` = 'allowed.username.characters';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Cooldown in milliseconds used by the Apollyon-specific behaviour or command flow.' WHERE `key` = 'apollyon.cooldown.amount';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Asset URL used by the BaseJump or FastFood game client.' WHERE `key` = 'basejump.assets.url';
|
||||
UPDATE `emulator_settings` SET `comment` = 'SWF URL used to launch the BaseJump or FastFood game client.' WHERE `key` = 'basejump.url';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Date format used by visitor bots when they print timestamps.' WHERE `key` = 'bots.visitor.dateformat';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Master switch for bubble alert notifications.' WHERE `key` = 'bubblealerts.enabled';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Enable bubble alerts when friends come online.' WHERE `key` = 'bubblealerts.notif_friendonline.enabled';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Image template used when showing friend-online bubble alerts.' WHERE `key` = 'bubblealerts.notif_friendonline.image';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Use the configured figure image inside friend-online bubble alerts.' WHERE `key` = 'bubblealerts.notif_friendonline.useimage';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Show bubble alerts for marketplace notifications.' WHERE `key` = 'bubblealerts.notif_marketplace.enabled';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Show bubble alerts for limited-item purchases.' WHERE `key` = 'bubblealerts.notif_purchase.limited';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Allow bots to be included in room bundles or package rewards.' WHERE `key` = 'bundle.bots.enabled';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Allow pets to be included in room bundles or package rewards.' WHERE `key` = 'bundle.pets.enabled';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Enable the GET callback used to report version to external services.' WHERE `key` = 'callback.get.version';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Enable the POST callback used to report errors to external services.' WHERE `key` = 'callback.post.errors';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Enable the POST callback used to report statistics to external services.' WHERE `key` = 'callback.post.statistics';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Enable the in-room camera feature.' WHERE `key` = 'camera.enabled';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Extradata template written into camera photo items when they are created.' WHERE `key` = 'camera.extradata';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Base item ID used by the generated camera photo furniture.' WHERE `key` = 'camera.item_id';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Credit price charged when taking a camera photo.' WHERE `key` = 'camera.price.credits';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Amount of activity points charged when taking a camera photo.' WHERE `key` = 'camera.price.points';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Amount of activity points charged when publishing a camera photo.' WHERE `key` = 'camera.price.points.publish';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Activity point type used for the camera publish cost.' WHERE `key` = 'camera.price.points.publish.type';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Activity point type used for the camera capture cost.' WHERE `key` = 'camera.price.points.type';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Delay in seconds before a published camera photo becomes available.' WHERE `key` = 'camera.publish.delay';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Base URL where camera images are published.' WHERE `key` = 'camera.url';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Force HTTPS when generating camera image URLs.' WHERE `key` = 'camera.use.https';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Require HC or VIP status before users can create a guild.' WHERE `key` = 'catalog.guild.hc_required';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Credit cost required to create a guild.' WHERE `key` = 'catalog.guild.price';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Layout or image ID used when a limited page is sold out.' WHERE `key` = 'catalog.ltd.page.soldout';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Randomize the order or selection of limited catalog items.' WHERE `key` = 'catalog.ltd.random';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Catalog page ID used for VIP gift redemption.' WHERE `key` = 'catalog.page.vipgifts';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Semicolon-separated list of chat color IDs blocked for the chatcolor command.' WHERE `key` = 'commands.cmd_chatcolor.banned_numbers';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Minimum permission rank required to use the staffonline command.' WHERE `key` = 'commands.cmd_staffonline.min_rank';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Use the legacy command plugin loading style.' WHERE `key` = 'commands.plugins.oldstyle';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Controls the emulator console mode or console output style.' WHERE `key` = 'console.mode';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Enable custom item stacking behaviour outside the default stacking rules.' WHERE `key` = 'custom.stacking.enabled';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Maximum batch or partition size used by partitioned database operations.' WHERE `key` = 'db.max.partition.size';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Minimum batch or partition size used by partitioned database operations.' WHERE `key` = 'db.min.partition.size';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Maximum size of the database connection pool.' WHERE `key` = 'db.pool.maxsize';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Minimum number of open connections kept in the database pool.' WHERE `key` = 'db.pool.minsize';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Enable general emulator debug mode.' WHERE `key` = 'debug.mode';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Show internal debug error messages.' WHERE `key` = 'debug.show.errors';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Show packet headers in debug logs.' WHERE `key` = 'debug.show.headers';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Print packet-level debug output.' WHERE `key` = 'debug.show.packets';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Print debug output for undefined incoming or outgoing packets.' WHERE `key` = 'debug.show.packets.undefined';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Log SQL exceptions to the console.' WHERE `key` = 'debug.show.sql.exception';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Show user-related debug messages.' WHERE `key` = 'debug.show.users';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Semicolon-separated discount thresholds used for extra batch bonuses.' WHERE `key` = 'discount.additional.thresholds';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Number of free items granted inside one discount batch.' WHERE `key` = 'discount.batch.free.items';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Number of items required for one discount batch.' WHERE `key` = 'discount.batch.size';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Minimum number of discount batches required before the bonus logic applies.' WHERE `key` = 'discount.bonus.min.discounts';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Maximum number of catalog items that can participate in one discount batch.' WHERE `key` = 'discount.max.allowed.items';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Enable or disable the feature controlled by `easter_eggs.enabled`.' WHERE `key` = 'easter_eggs.enabled';
|
||||
UPDATE `emulator_settings` SET `comment` = 'RSA private exponent used by the encryption layer.' WHERE `key` = 'enc.d';
|
||||
UPDATE `emulator_settings` SET `comment` = 'RSA public exponent used by the encryption layer.' WHERE `key` = 'enc.e';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Enable RSA encryption support for the socket handshake.' WHERE `key` = 'enc.enabled';
|
||||
UPDATE `emulator_settings` SET `comment` = 'RSA modulus used by the encryption layer.' WHERE `key` = 'enc.n';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Semicolon-separated effect IDs used by the kill command for the killer.' WHERE `key` = 'essentials.cmd_kill.effect.killer';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Semicolon-separated effect IDs used by the kill command for the victim.' WHERE `key` = 'essentials.cmd_kill.effect.victim';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Allow users with room rights to bypass the normal flood protection.' WHERE `key` = 'flood.with.rights';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Enable FTP uploads for generated assets.' WHERE `key` = 'ftp.enabled';
|
||||
UPDATE `emulator_settings` SET `comment` = 'FTP host used for asset uploads.' WHERE `key` = 'ftp.host';
|
||||
UPDATE `emulator_settings` SET `comment` = 'FTP password used for asset uploads.' WHERE `key` = 'ftp.password';
|
||||
UPDATE `emulator_settings` SET `comment` = 'FTP username used for asset uploads.' WHERE `key` = 'ftp.user';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Maximum tile distance at which talking furniture can react to nearby speech.' WHERE `key` = 'furniture.talking.range';
|
||||
UPDATE `emulator_settings` SET `comment` = 'API key used by the FastFood or BaseJump integration.' WHERE `key` = 'gamecenter.fastfood.apiKey';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Asset base URL used by the FastFood or BaseJump game client.' WHERE `key` = 'gamecenter.fastfood.assets';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Background color used by the FastFood launcher UI.' WHERE `key` = 'gamecenter.fastfood.background.color';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Enable the FastFood or BaseJump gamecenter integration.' WHERE `key` = 'gamecenter.fastfood.enabled';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Text color used by the FastFood launcher UI.' WHERE `key` = 'gamecenter.fastfood.text.color';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Theme name used by the FastFood launcher.' WHERE `key` = 'gamecenter.fastfood.theme';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Background image used for the SnowWar Arctic map.' WHERE `key` = 'gamecenter.snowwar.artic.bg';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Asset base URL used by the SnowWar game client.' WHERE `key` = 'gamecenter.snowwar.assets';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Background image used for the SnowWar Dragon Cave map.' WHERE `key` = 'gamecenter.snowwar.dragoncave.bg';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Enable the SnowWar gamecenter integration.' WHERE `key` = 'gamecenter.snowwar.enabled';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Background image used for the SnowWar Fight Night map.' WHERE `key` = 'gamecenter.snowwar.fightnight.bg';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Background color used by the SnowWar launcher UI.' WHERE `key` = 'gamecenter.snowwar.game.background.color';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Countdown in seconds before a SnowWar round starts.' WHERE `key` = 'gamecenter.snowwar.game.start.time';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Text color used by the SnowWar launcher UI.' WHERE `key` = 'gamecenter.snowwar.game.text.color';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Minimum number of players required to start SnowWar.' WHERE `key` = 'gamecenter.snowwar.players.min';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Room ID used as the SnowWar lobby or host room.' WHERE `key` = 'gamecenter.snowwar.room.id';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Remote figuredata URL used when the hotel loads avatar figure definitions.' WHERE `key` = 'gamedata.figuredata.url';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Time in seconds that guardians have to accept a case.' WHERE `key` = 'guardians.accept.timer';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Maximum number of guardians that can be assigned to one case.' WHERE `key` = 'guardians.maximum.guardians.total';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Maximum number of times an unanswered guardian case can be resent.' WHERE `key` = 'guardians.maximum.resends';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Minimum number of guardian votes required to resolve a case.' WHERE `key` = 'guardians.minimum.votes';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Cooldown in seconds before the same user can open a new guardian report.' WHERE `key` = 'guardians.reporting.cooldown';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Use the legacy generic alert window style.' WHERE `key` = 'hotel.alert.oldstyle';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Allow users to ignore staff accounts.' WHERE `key` = 'hotel.allow.ignore.staffs';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Amount of credits granted on each automatic payout.' WHERE `key` = 'hotel.auto.credits.amount';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Enable automatic credits payouts.' WHERE `key` = 'hotel.auto.credits.enabled';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Multiplier applied to automatic credits payouts for HC users.' WHERE `key` = 'hotel.auto.credits.hc_modifier';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Skip users staying in hotel view when giving automatic credits payouts.' WHERE `key` = 'hotel.auto.credits.ignore.hotelview';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Skip idle users when giving automatic credits payouts.' WHERE `key` = 'hotel.auto.credits.ignore.idled';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Interval in seconds between automatic credits payouts.' WHERE `key` = 'hotel.auto.credits.interval';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Enable automatic gotwpoints payouts.' WHERE `key` = 'hotel.auto.gotwpoints.enabled';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Multiplier applied to automatic gotwpoints payouts for HC users.' WHERE `key` = 'hotel.auto.gotwpoints.hc_modifier';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Skip users staying in hotel view when giving automatic gotwpoints payouts.' WHERE `key` = 'hotel.auto.gotwpoints.ignore.hotelview';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Skip idle users when giving automatic gotwpoints payouts.' WHERE `key` = 'hotel.auto.gotwpoints.ignore.idled';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Interval in seconds between automatic gotwpoints payouts.' WHERE `key` = 'hotel.auto.gotwpoints.interval';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Internal currency name used by the automatic gotwpoints payout.' WHERE `key` = 'hotel.auto.gotwpoints.name';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Currency type ID used by the automatic gotwpoints payout.' WHERE `key` = 'hotel.auto.gotwpoints.type';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Amount of pixels granted on each automatic payout.' WHERE `key` = 'hotel.auto.pixels.amount';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Enable automatic pixels payouts.' WHERE `key` = 'hotel.auto.pixels.enabled';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Multiplier applied to automatic pixels payouts for HC users.' WHERE `key` = 'hotel.auto.pixels.hc_modifier';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Skip users staying in hotel view when giving automatic pixels payouts.' WHERE `key` = 'hotel.auto.pixels.ignore.hotelview';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Skip idle users when giving automatic pixels payouts.' WHERE `key` = 'hotel.auto.pixels.ignore.idled';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Interval in seconds between automatic pixels payouts.' WHERE `key` = 'hotel.auto.pixels.interval';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Amount of points granted on each automatic payout.' WHERE `key` = 'hotel.auto.points.amount';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Enable automatic points payouts.' WHERE `key` = 'hotel.auto.points.enabled';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Multiplier applied to automatic points payouts for HC users.' WHERE `key` = 'hotel.auto.points.hc_modifier';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Skip users staying in hotel view when giving automatic points payouts.' WHERE `key` = 'hotel.auto.points.ignore.hotelview';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Skip idle users when giving automatic points payouts.' WHERE `key` = 'hotel.auto.points.ignore.idled';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Interval in seconds between automatic points payouts.' WHERE `key` = 'hotel.auto.points.interval';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Configuration value used by `hotel.banzai.points.tile.fill`.' WHERE `key` = 'hotel.banzai.points.tile.fill';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Configuration value used by `hotel.banzai.points.tile.lock`.' WHERE `key` = 'hotel.banzai.points.tile.lock';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Configuration value used by `hotel.banzai.points.tile.steal`.' WHERE `key` = 'hotel.banzai.points.tile.steal';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Maximum tile distance from which a butler bot accepts commands.' WHERE `key` = 'hotel.bot.butler.commanddistance';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Maximum tile distance from which a butler bot can serve requests.' WHERE `key` = 'hotel.bot.butler.servedistance';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Minimum number of seconds between bot chat lines.' WHERE `key` = 'hotel.bot.chat.minimum.interval';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Maximum bot chat delay allowed when configuring scripted speech.' WHERE `key` = 'hotel.bot.max.chatdelay';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Maximum number of characters allowed in bot chat lines.' WHERE `key` = 'hotel.bot.max.chatlength';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Maximum number of characters allowed in bot names.' WHERE `key` = 'hotel.bot.max.namelength';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Maximum number of bots allowed in one inventory.' WHERE `key` = 'hotel.bots.max.inventory';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Maximum number of bots allowed in one room.' WHERE `key` = 'hotel.bots.max.room';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Default calendar campaign name or identifier.' WHERE `key` = 'hotel.calendar.default';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Enable the hotel calendar feature.' WHERE `key` = 'hotel.calendar.enabled';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Multiplier applied to calendar pixel rewards for HC users.' WHERE `key` = 'hotel.calendar.pixels.hc_modifier';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Unix timestamp used as the calendar start date.' WHERE `key` = 'hotel.calendar.starttimestamp';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Number of discount slots or discount batches shown by the catalog.' WHERE `key` = 'hotel.catalog.discounts.amount';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Respect catalog item order numbers when rendering pages.' WHERE `key` = 'hotel.catalog.items.display.ordernum';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Enable daily purchase limits for limited catalog items.' WHERE `key` = 'hotel.catalog.ltd.limit.enabled';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Cooldown in seconds between catalog purchases.' WHERE `key` = 'hotel.catalog.purchase.cooldown';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Enable the catalog recycler feature.' WHERE `key` = 'hotel.catalog.recycler.enabled';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Maximum number of characters allowed in one public chat message.' WHERE `key` = 'hotel.chat.max.length';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Daily amount of respect points available for users.' WHERE `key` = 'hotel.daily.respect';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Daily amount of pet respect points available for users.' WHERE `key` = 'hotel.daily.respect.pets';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Enable or disable the feature controlled by `hotel.ecotron.enabled`.' WHERE `key` = 'hotel.ecotron.enabled';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Configuration value used by `hotel.ecotron.rarity.chance.1`.' WHERE `key` = 'hotel.ecotron.rarity.chance.1';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Configuration value used by `hotel.ecotron.rarity.chance.2`.' WHERE `key` = 'hotel.ecotron.rarity.chance.2';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Configuration value used by `hotel.ecotron.rarity.chance.3`.' WHERE `key` = 'hotel.ecotron.rarity.chance.3';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Configuration value used by `hotel.ecotron.rarity.chance.4`.' WHERE `key` = 'hotel.ecotron.rarity.chance.4';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Configuration value used by `hotel.ecotron.rarity.chance.5`.' WHERE `key` = 'hotel.ecotron.rarity.chance.5';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Mute duration in seconds applied by the hotel flood protection.' WHERE `key` = 'hotel.flood.mute.time';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Maximum total floorplan area allowed for custom rooms.' WHERE `key` = 'hotel.floorplan.max.totalarea';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Maximum floorplan width or length allowed for custom rooms.' WHERE `key` = 'hotel.floorplan.max.widthlength';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Number of explosion boosts lost when a player gets frozen.' WHERE `key` = 'hotel.freeze.onfreeze.loose.explosionboost';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Number of snowballs lost when a player gets frozen.' WHERE `key` = 'hotel.freeze.onfreeze.loose.snowballs';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Time in seconds a player remains frozen.' WHERE `key` = 'hotel.freeze.onfreeze.time.frozen';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Score awarded for blocking tiles in Freeze.' WHERE `key` = 'hotel.freeze.points.block';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Score awarded for using Freeze effects or power-up actions.' WHERE `key` = 'hotel.freeze.points.effect';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Score awarded for freezing another player in Freeze.' WHERE `key` = 'hotel.freeze.points.freeze';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Chance for Freeze power-ups to spawn.' WHERE `key` = 'hotel.freeze.powerup.chance';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Maximum number of extra lives granted by a Freeze power-up.' WHERE `key` = 'hotel.freeze.powerup.max.lives';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Maximum number of extra snowballs granted by a Freeze power-up.' WHERE `key` = 'hotel.freeze.powerup.max.snowballs';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Allow Freeze protection power-ups to stack.' WHERE `key` = 'hotel.freeze.powerup.protection.stack';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Protection time in seconds after receiving a Freeze protection power-up.' WHERE `key` = 'hotel.freeze.powerup.protection.time';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Default friend category ID assigned to new friends.' WHERE `key` = 'hotel.friendcategory';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Configuration value used by `hotel.furni.gym.achievement.olympics_c16_crosstrainer`.' WHERE `key` = 'hotel.furni.gym.achievement.olympics_c16_crosstrainer';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Configuration value used by `hotel.furni.gym.achievement.olympics_c16_trampoline`.' WHERE `key` = 'hotel.furni.gym.achievement.olympics_c16_trampoline';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Configuration value used by `hotel.furni.gym.achievement.olympics_c16_treadmill`.' WHERE `key` = 'hotel.furni.gym.achievement.olympics_c16_treadmill';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Configuration value used by `hotel.furni.gym.forcerot.olympics_c16_crosstrainer`.' WHERE `key` = 'hotel.furni.gym.forcerot.olympics_c16_crosstrainer';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Configuration value used by `hotel.furni.gym.forcerot.olympics_c16_trampoline`.' WHERE `key` = 'hotel.furni.gym.forcerot.olympics_c16_trampoline';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Configuration value used by `hotel.furni.gym.forcerot.olympics_c16_treadmill`.' WHERE `key` = 'hotel.furni.gym.forcerot.olympics_c16_treadmill';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Comma-separated list of gift box type IDs allowed in the catalog.' WHERE `key` = 'hotel.gifts.box_types';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Maximum message length allowed on gift notes.' WHERE `key` = 'hotel.gifts.length.max';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Comma-separated list of ribbon type IDs allowed in the catalog.' WHERE `key` = 'hotel.gifts.ribbon_types';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Credit price used by special gift boxes.' WHERE `key` = 'hotel.gifts.special.price';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Room ID used as the default home room for new users.' WHERE `key` = 'hotel.home.room';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Maximum number of items allowed in one inventory.' WHERE `key` = 'hotel.inventory.max.items';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Configuration value used by `hotel.item.trap.hween14_rare2`.' WHERE `key` = 'hotel.item.trap.hween14_rare2';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Configuration value used by `hotel.item.trap.hween_c17_handstrap`.' WHERE `key` = 'hotel.item.trap.hween_c17_handstrap';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Configuration value used by `hotel.item.trap.hween_c17_spiketrap`.' WHERE `key` = 'hotel.item.trap.hween_c17_spiketrap';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Configuration value used by `hotel.item.trap.pirate_sandtrap`.' WHERE `key` = 'hotel.item.trap.pirate_sandtrap';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Track limit used by large jukebox furniture.' WHERE `key` = 'hotel.jukebox.limit.large';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Track limit used by normal jukebox furniture.' WHERE `key` = 'hotel.jukebox.limit.normal';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Enable logging for chat.' WHERE `key` = 'hotel.log.chat';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Enable logging for chat private.' WHERE `key` = 'hotel.log.chat.private';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Enable logging for room enter.' WHERE `key` = 'hotel.log.room.enter';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Enable logging for trades.' WHERE `key` = 'hotel.log.trades';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Currency type used for marketplace prices and taxes.' WHERE `key` = 'hotel.marketplace.currency';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Enable or disable the feature controlled by `hotel.marketplace.enabled`.' WHERE `key` = 'hotel.marketplace.enabled';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Maximum number of bots allowed in one room.' WHERE `key` = 'hotel.max.bots.room';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Maximum amount of duckets a user can hold.' WHERE `key` = 'hotel.max.duckets';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Enable or disable the feature controlled by `hotel.messenger.offline.messaging.enabled`.' WHERE `key` = 'hotel.messenger.offline.messaging.enabled';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Maximum number of results returned by messenger user searches.' WHERE `key` = 'hotel.messenger.search.maxresults';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Public hotel name shown across the client and outgoing messages.' WHERE `key` = 'hotel.name';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Enable navigator room previews or camera mode.' WHERE `key` = 'hotel.navigator.camera';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Default owner name displayed by the navigator.' WHERE `key` = 'hotel.navigator.owner';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Number of rooms shown in the popular rooms list.' WHERE `key` = 'hotel.navigator.popular.amount';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Maximum number of rooms shown per popular category.' WHERE `key` = 'hotel.navigator.popular.category.maxresults';
|
||||
UPDATE `emulator_settings` SET `comment` = 'List type used for the popular rooms tab.' WHERE `key` = 'hotel.navigator.popular.listtype';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Include public rooms inside the popular rooms tab.' WHERE `key` = 'hotel.navigator.populartab.publics';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Maximum number of results returned by navigator searches.' WHERE `key` = 'hotel.navigator.search.maxresults';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Respect order numbers when sorting navigator results.' WHERE `key` = 'hotel.navigator.sort.ordernum';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Category ID used for the staff picks tab.' WHERE `key` = 'hotel.navigator.staffpicks.categoryid';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Enable the NUX gift flow for new users.' WHERE `key` = 'hotel.nux.gifts.enabled';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Maximum number of pets allowed in one inventory.' WHERE `key` = 'hotel.pets.max.inventory';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Maximum number of pets allowed in one room.' WHERE `key` = 'hotel.pets.max.room';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Maximum pet name length.' WHERE `key` = 'hotel.pets.name.length.max';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Minimum pet name length.' WHERE `key` = 'hotel.pets.name.length.min';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Generic player label used by text templates and client messages.' WHERE `key` = 'hotel.player.name';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Maximum number of the same limited item a user can buy per day.' WHERE `key` = 'hotel.purchase.ltd.limit.daily.item';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Maximum number of limited items a user can buy per day across all limited sales.' WHERE `key` = 'hotel.purchase.ltd.limit.daily.total';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Cooldown in seconds before daily counters such as respect are refilled.' WHERE `key` = 'hotel.refill.daily';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Maximum roller delay or speed value accepted by roller furniture.' WHERE `key` = 'hotel.rollers.speed.maximum';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Enable room-entry logs.' WHERE `key` = 'hotel.room.enter.logs';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Validate custom floorplans before rooms are saved.' WHERE `key` = 'hotel.room.floorplan.check.enabled';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Maximum amount of furniture allowed in one room.' WHERE `key` = 'hotel.room.furni.max';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Room ID used as the newbie lobby.' WHERE `key` = 'hotel.room.nooblobby';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Kick users who stand on public room door tiles.' WHERE `key` = 'hotel.room.public.doortile.kick';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Allow rollers to ignore normal placement rules.' WHERE `key` = 'hotel.room.rollers.norules';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Maximum number of avatars that rollers can move at once.' WHERE `key` = 'hotel.room.rollers.roll_avatars.max';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Maximum number of sticky notes allowed in one room.' WHERE `key` = 'hotel.room.stickies.max';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Prefix template written by sticky pole furniture.' WHERE `key` = 'hotel.room.stickypole.prefix';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Semicolon-separated staff room tags.' WHERE `key` = 'hotel.room.tags.staff';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Allow empty rooms to switch into the idle state automatically.' WHERE `key` = 'hotel.rooms.auto.idle';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Enable decoration-hosting features for rooms.' WHERE `key` = 'hotel.rooms.deco_hosting';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Time in seconds before temporary hand items are cleared.' WHERE `key` = 'hotel.rooms.handitem.time';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Maximum number of favorite rooms allowed per user.' WHERE `key` = 'hotel.rooms.max.favorite';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Idle cycle count before a room user is marked idle.' WHERE `key` = 'hotel.roomuser.idle.cycles';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Idle cycle count before a room user is kicked for idling.' WHERE `key` = 'hotel.roomuser.idle.cycles.kick';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Ignore the wired idle status when checking the room idle rule.' WHERE `key` = 'hotel.roomuser.idle.not_dancing.ignore.wired_idle';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Enable the sanctions system.' WHERE `key` = 'hotel.sanctions.enabled';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Modifier used by the shop discount calculation.' WHERE `key` = 'hotel.shop.discount.modifier';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Enable the talent track feature.' WHERE `key` = 'hotel.talenttrack.enabled';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Offer ID requested when the client asks for a targeted offer.' WHERE `key` = 'hotel.targetoffer.id';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Allow users to use teleports inside locked rooms when they otherwise qualify.' WHERE `key` = 'hotel.teleport.locked.allowed';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Enable room trading.' WHERE `key` = 'hotel.trading.enabled';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Require the trading perk before users may trade.' WHERE `key` = 'hotel.trading.requires.perk';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Maximum value used by `hotel.trophies.length.max`.' WHERE `key` = 'hotel.trophies.length.max';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Run clothing validation when the related action occurs: onchangelooks.' WHERE `key` = 'hotel.users.clothingvalidation.onchangelooks';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Run clothing validation when the related action occurs: onfballgate.' WHERE `key` = 'hotel.users.clothingvalidation.onfballgate';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Run clothing validation when the related action occurs: onhcexpired.' WHERE `key` = 'hotel.users.clothingvalidation.onhcexpired';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Run clothing validation when the related action occurs: onlogin.' WHERE `key` = 'hotel.users.clothingvalidation.onlogin';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Run clothing validation when the related action occurs: onmannequin.' WHERE `key` = 'hotel.users.clothingvalidation.onmannequin';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Run clothing validation when the related action occurs: onmimic.' WHERE `key` = 'hotel.users.clothingvalidation.onmimic';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Maximum number of friends allowed for normal users.' WHERE `key` = 'hotel.users.max.friends';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Maximum number of friends allowed for HC users.' WHERE `key` = 'hotel.users.max.friends.hc';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Maximum number of rooms allowed for normal users.' WHERE `key` = 'hotel.users.max.rooms';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Maximum number of rooms allowed for HC users.' WHERE `key` = 'hotel.users.max.rooms.hc';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Enable the limited-countdown hotel-view widget.' WHERE `key` = 'hotel.view.ltdcountdown.enabled';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Item ID shown by the limited-countdown widget.' WHERE `key` = 'hotel.view.ltdcountdown.itemid';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Item name shown by the limited-countdown widget.' WHERE `key` = 'hotel.view.ltdcountdown.itemname';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Catalog page ID linked by the limited-countdown widget.' WHERE `key` = 'hotel.view.ltdcountdown.pageid';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Unix timestamp used by the limited-countdown widget.' WHERE `key` = 'hotel.view.ltdcountdown.timestamp';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Delay in milliseconds before the welcome alert is shown.' WHERE `key` = 'hotel.welcome.alert.delay';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Enable the welcome alert shown after login.' WHERE `key` = 'hotel.welcome.alert.enabled';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Message template used by the welcome alert.' WHERE `key` = 'hotel.welcome.alert.message';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Use the legacy welcome alert window style.' WHERE `key` = 'hotel.welcome.alert.oldstyle';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Mute duration in minutes applied when word-filter automute is triggered.' WHERE `key` = 'hotel.wordfilter.automute';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Enable the word filter system.' WHERE `key` = 'hotel.wordfilter.enabled';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Apply the word filter to messenger messages.' WHERE `key` = 'hotel.wordfilter.messenger';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Normalise text before checking it against the word filter.' WHERE `key` = 'hotel.wordfilter.normalise';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Replacement word used when text is censored.' WHERE `key` = 'hotel.wordfilter.replacement';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Apply the word filter to room chat.' WHERE `key` = 'hotel.wordfilter.rooms';
|
||||
UPDATE `emulator_settings` SET `comment` = 'SQL query used to populate the hotel-view hall of fame panel.' WHERE `key` = 'hotelview.halloffame.query';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Amount of activity points awarded by the hotel-view promotion.' WHERE `key` = 'hotelview.promotional.points';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Activity point type used by the hotel-view promotional reward.' WHERE `key` = 'hotelview.promotional.points.type';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Base item ID used by the hotel-view promotional reward.' WHERE `key` = 'hotelview.promotional.reward.id';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Public item name used by the hotel-view promotional reward.' WHERE `key` = 'hotelview.promotional.reward.name';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Generate images locally instead of relying on an external imager service.' WHERE `key` = 'imager.internal.enabled';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Filesystem path where badge part assets are stored.' WHERE `key` = 'imager.location.badgeparts';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Filesystem output path for generated badges.' WHERE `key` = 'imager.location.output.badges';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Filesystem output path for saved camera photos.' WHERE `key` = 'imager.location.output.camera';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Filesystem output path for generated camera thumbnails.' WHERE `key` = 'imager.location.output.thumbnail';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Template URL used to fetch YouTube thumbnails.' WHERE `key` = 'imager.url.youtube';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Client asset path used for the basejump gamecenter images.' WHERE `key` = 'images.gamecenter.basejump';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Client asset path used for the snowwar gamecenter images.' WHERE `key` = 'images.gamecenter.snowwar';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Show the hotel information panel or startup information message.' WHERE `key` = 'info.shown';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Prevent invisible users from speaking in rooms.' WHERE `key` = 'invisible.prevent.chat';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Number of Netty boss-group threads used by the socket server.' WHERE `key` = 'io.bossgroup.threads';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Handle incoming client packets with a multi-threaded pipeline.' WHERE `key` = 'io.client.multithreaded.handler';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Number of Netty worker-group threads used by the socket server.' WHERE `key` = 'io.workergroup.threads';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Enable extra debug logging in the emulator logger.' WHERE `key` = 'logging.debug';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Log packet parsing errors.' WHERE `key` = 'logging.errors.packets';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Log runtime exceptions.' WHERE `key` = 'logging.errors.runtime';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Log SQL errors.' WHERE `key` = 'logging.errors.sql';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Log packet traffic in the standard logger.' WHERE `key` = 'logging.packets';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Log undefined packets in the standard logger.' WHERE `key` = 'logging.packets.undefined';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Global switch for the marketplace subsystem.' WHERE `key` = 'marketplace.enabled';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Configuration value used by `monsterplant.seed.item_id`.' WHERE `key` = 'monsterplant.seed.item_id';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Configuration value used by `monsterplant.seed_rare.item_id`.' WHERE `key` = 'monsterplant.seed_rare.item_id';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Validate moodlight color values before applying them.' WHERE `key` = 'moodlight.color_check.enabled';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Semicolon-separated navigator event category definitions shown in the events tab.' WHERE `key` = 'navigator.eventcategories';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Enable TCP proxy-aware networking behaviour.' WHERE `key` = 'networking.tcp.proxy';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Automatically notify staff when a chat report is created.' WHERE `key` = 'notify.staff.chat.auto.report';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Base path used by the client to load furniture icon assets.' WHERE `key` = 'path.furniture.icons';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Maximum pathfinder execution time in milliseconds before aborting.' WHERE `key` = 'pathfinder.execution_time.milli';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Enforce the pathfinder execution time limit.' WHERE `key` = 'pathfinder.max_execution_time.enabled';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Allow the pathfinder to walk down falling steps.' WHERE `key` = 'pathfinder.step.allow.falling';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Maximum height difference the pathfinder may step onto.' WHERE `key` = 'pathfinder.step.maximum.height';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Chat bubble style ID used by the pirate parrot.' WHERE `key` = 'pirate_parrot.message.bubble';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Number of predefined messages available to the pirate parrot.' WHERE `key` = 'pirate_parrot.message.count';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Maximum number of characters allowed on post-it notes.' WHERE `key` = 'postit.charlimit';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Maximum delay allowed in the Pyramids minigame or puzzle timing.' WHERE `key` = 'pyramids.max.delay';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Use retro-style home room behaviour in the navigator or onboarding flow.' WHERE `key` = 'retro.style.homeroom';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Extra room chat delay applied before users can speak again.' WHERE `key` = 'room.chat.delay';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Allow whispering while a user stands inside a mute area.' WHERE `key` = 'room.chat.mutearea.allow_whisper';
|
||||
UPDATE `emulator_settings` SET `comment` = 'HTML or text format used for room chat prefixes.' WHERE `key` = 'room.chat.prefix.format';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Badge code displayed on promoted rooms.' WHERE `key` = 'room.promotion.badge';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Image used by Rosie bubble notifications.' WHERE `key` = 'rosie.bubble.image.url';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Currency type used by Rosie when buying a room or room package.' WHERE `key` = 'rosie.buyroom.currency.type';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Configuration value used by `runtime.threads`.' WHERE `key` = 'runtime.threads';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Configuration value used by `save.private.chats`.' WHERE `key` = 'save.private.chats';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Configuration value used by `save.room.chats`.' WHERE `key` = 'save.room.chats';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Expose moderation tickets to the scripter or automation tooling.' WHERE `key` = 'scripter.modtool.tickets';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Currency type ID used for diamonds.' WHERE `key` = 'seasonal.currency.diamond';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Currency type ID used for duckets.' WHERE `key` = 'seasonal.currency.ducket';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Semicolon-separated display names for seasonal currency types.' WHERE `key` = 'seasonal.currency.names';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Currency type ID used for pixels.' WHERE `key` = 'seasonal.currency.pixel';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Currency type ID used for shells.' WHERE `key` = 'seasonal.currency.shell';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Primary seasonal currency type ID.' WHERE `key` = 'seasonal.primary.type';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Semicolon-separated list of currency type IDs treated as seasonal currencies.' WHERE `key` = 'seasonal.types';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Achievement code granted for the HC subscription tier.' WHERE `key` = 'subscriptions.hc.achievement';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Number of days before expiry when HC discount offers become available.' WHERE `key` = 'subscriptions.hc.discount.days_before_end';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Enable discounted HC renewal offers.' WHERE `key` = 'subscriptions.hc.discount.enabled';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Reset tracked credits spent when the HC subscription expires.' WHERE `key` = 'subscriptions.hc.payday.creditsspent_reset_on_expire';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Currency rewarded by the HC payday system.' WHERE `key` = 'subscriptions.hc.payday.currency';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Enable the HC payday reward system.' WHERE `key` = 'subscriptions.hc.payday.enabled';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Date interval used between HC payday reward runs.' WHERE `key` = 'subscriptions.hc.payday.interval';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Next scheduled execution date for HC payday rewards.' WHERE `key` = 'subscriptions.hc.payday.next_date';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Percentage of eligible spending returned by HC payday.' WHERE `key` = 'subscriptions.hc.payday.percentage';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Semicolon-separated streak thresholds and rewards for HC payday.' WHERE `key` = 'subscriptions.hc.payday.streak';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Enable the subscription background scheduler.' WHERE `key` = 'subscriptions.scheduler.enabled';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Interval in minutes between subscription scheduler runs.' WHERE `key` = 'subscriptions.scheduler.interval';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Compatibility marker used by the custom team wired implementation. Do not remove.' WHERE `key` = 'team.wired.update.rc-1';
|
||||
UPDATE `emulator_settings` SET `comment` = 'API key used by the YouTube integration.' WHERE `key` = 'youtube.apikey';
|
||||
@@ -0,0 +1,499 @@
|
||||
-- Normalizes the legacy `permissions` table into:
|
||||
-- 1. `permission_ranks` -> one row per rank with rank metadata.
|
||||
-- 2. `permission_definitions` -> one row per permission key with comments and one `rank_<id>` column per rank.
|
||||
--
|
||||
-- This migration keeps the old `permissions` table untouched so the emulator can safely fall back to it.
|
||||
-- It also cleans up the older experimental normalized objects if they were already created.
|
||||
|
||||
DROP VIEW IF EXISTS `permissions_matrix_view`;
|
||||
DROP PROCEDURE IF EXISTS `refresh_permissions_matrix_view`;
|
||||
DROP TABLE IF EXISTS `permission_rank_values`;
|
||||
DROP TABLE IF EXISTS `permission_nodes`;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `permission_ranks` (
|
||||
`id` int(11) NOT NULL,
|
||||
`rank_name` varchar(25) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL,
|
||||
`hidden_rank` tinyint(1) NOT NULL DEFAULT 0,
|
||||
`badge` varchar(12) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL DEFAULT '',
|
||||
`job_description` varchar(255) NOT NULL DEFAULT 'Here to help',
|
||||
`staff_color` varchar(8) NOT NULL DEFAULT '#327fa8',
|
||||
`staff_background` varchar(255) NOT NULL DEFAULT 'staff-bg.png',
|
||||
`level` int(11) NOT NULL DEFAULT 1,
|
||||
`room_effect` int(11) NOT NULL DEFAULT 0,
|
||||
`log_commands` enum('0','1') CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL DEFAULT '0',
|
||||
`prefix` varchar(5) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL DEFAULT '',
|
||||
`prefix_color` varchar(7) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL DEFAULT '',
|
||||
`auto_credits_amount` int(11) DEFAULT 0,
|
||||
`auto_pixels_amount` int(11) DEFAULT 0,
|
||||
`auto_gotw_amount` int(11) DEFAULT 0,
|
||||
`auto_points_amount` int(11) DEFAULT 0,
|
||||
PRIMARY KEY (`id`) USING BTREE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_uca1400_ai_ci ROW_FORMAT=DYNAMIC;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `permission_definitions` (
|
||||
`permission_key` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL,
|
||||
`max_value` tinyint(3) unsigned NOT NULL DEFAULT 1,
|
||||
`comment` text NOT NULL,
|
||||
PRIMARY KEY (`permission_key`) USING BTREE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_uca1400_ai_ci ROW_FORMAT=DYNAMIC;
|
||||
|
||||
ALTER TABLE `permission_definitions`
|
||||
DROP COLUMN IF EXISTS `category`,
|
||||
DROP COLUMN IF EXISTS `value_type`,
|
||||
DROP COLUMN IF EXISTS `sort_order`;
|
||||
|
||||
INSERT INTO `permission_ranks` (
|
||||
`id`,
|
||||
`rank_name`,
|
||||
`hidden_rank`,
|
||||
`badge`,
|
||||
`job_description`,
|
||||
`staff_color`,
|
||||
`staff_background`,
|
||||
`level`,
|
||||
`room_effect`,
|
||||
`log_commands`,
|
||||
`prefix`,
|
||||
`prefix_color`,
|
||||
`auto_credits_amount`,
|
||||
`auto_pixels_amount`,
|
||||
`auto_gotw_amount`,
|
||||
`auto_points_amount`
|
||||
)
|
||||
SELECT
|
||||
`id`,
|
||||
`rank_name`,
|
||||
`hidden_rank`,
|
||||
`badge`,
|
||||
`job_description`,
|
||||
`staff_color`,
|
||||
`staff_background`,
|
||||
`level`,
|
||||
`room_effect`,
|
||||
`log_commands`,
|
||||
`prefix`,
|
||||
`prefix_color`,
|
||||
`auto_credits_amount`,
|
||||
`auto_pixels_amount`,
|
||||
`auto_gotw_amount`,
|
||||
`auto_points_amount`
|
||||
FROM `permissions`
|
||||
ON DUPLICATE KEY UPDATE
|
||||
`rank_name` = VALUES(`rank_name`),
|
||||
`hidden_rank` = VALUES(`hidden_rank`),
|
||||
`badge` = VALUES(`badge`),
|
||||
`job_description` = VALUES(`job_description`),
|
||||
`staff_color` = VALUES(`staff_color`),
|
||||
`staff_background` = VALUES(`staff_background`),
|
||||
`level` = VALUES(`level`),
|
||||
`room_effect` = VALUES(`room_effect`),
|
||||
`log_commands` = VALUES(`log_commands`),
|
||||
`prefix` = VALUES(`prefix`),
|
||||
`prefix_color` = VALUES(`prefix_color`),
|
||||
`auto_credits_amount` = VALUES(`auto_credits_amount`),
|
||||
`auto_pixels_amount` = VALUES(`auto_pixels_amount`),
|
||||
`auto_gotw_amount` = VALUES(`auto_gotw_amount`),
|
||||
`auto_points_amount` = VALUES(`auto_points_amount`);
|
||||
|
||||
DROP PROCEDURE IF EXISTS `refresh_permission_definition_rank_columns`;
|
||||
|
||||
DELIMITER $$
|
||||
CREATE PROCEDURE `refresh_permission_definition_rank_columns`()
|
||||
BEGIN
|
||||
DECLARE done INT DEFAULT 0;
|
||||
DECLARE current_rank_id INT;
|
||||
DECLARE current_column_name VARCHAR(32);
|
||||
DECLARE column_exists INT DEFAULT 0;
|
||||
DECLARE rank_cursor CURSOR FOR SELECT `id` FROM `permission_ranks` ORDER BY `id` ASC;
|
||||
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
|
||||
|
||||
OPEN rank_cursor;
|
||||
|
||||
rank_loop: LOOP
|
||||
FETCH rank_cursor INTO current_rank_id;
|
||||
|
||||
IF done = 1 THEN
|
||||
LEAVE rank_loop;
|
||||
END IF;
|
||||
|
||||
SET current_column_name = CONCAT('rank_', current_rank_id);
|
||||
|
||||
SELECT COUNT(*)
|
||||
INTO column_exists
|
||||
FROM `information_schema`.`columns`
|
||||
WHERE `table_schema` = DATABASE()
|
||||
AND `table_name` = 'permission_definitions'
|
||||
AND `column_name` = current_column_name;
|
||||
|
||||
IF column_exists = 0 THEN
|
||||
SET @alter_permissions_column_sql = CONCAT(
|
||||
'ALTER TABLE `permission_definitions` ADD COLUMN `',
|
||||
current_column_name,
|
||||
'` tinyint(3) unsigned NOT NULL DEFAULT 0'
|
||||
);
|
||||
|
||||
PREPARE alter_permissions_column_stmt FROM @alter_permissions_column_sql;
|
||||
EXECUTE alter_permissions_column_stmt;
|
||||
DEALLOCATE PREPARE alter_permissions_column_stmt;
|
||||
END IF;
|
||||
END LOOP;
|
||||
|
||||
CLOSE rank_cursor;
|
||||
END$$
|
||||
DELIMITER ;
|
||||
|
||||
CALL `refresh_permission_definition_rank_columns`();
|
||||
|
||||
INSERT INTO `permission_definitions` (
|
||||
`permission_key`,
|
||||
`max_value`,
|
||||
`comment`
|
||||
)
|
||||
SELECT
|
||||
`column_name` AS `permission_key`,
|
||||
CASE
|
||||
WHEN `column_type` LIKE '%''2''%' THEN 2
|
||||
ELSE 1
|
||||
END AS `max_value`,
|
||||
CASE
|
||||
WHEN COALESCE(`column_comment`, '') <> '' THEN `column_comment`
|
||||
WHEN `column_name` LIKE 'cmd\_%' AND `column_type` LIKE '%''2''%' THEN CONCAT(
|
||||
'Controls access to the :',
|
||||
REPLACE(SUBSTRING(`column_name`, 5), '_', ' '),
|
||||
' command. Values: 0 = disabled, 1 = allowed, 2 = allowed only when room-owner rights may be used.'
|
||||
)
|
||||
WHEN `column_name` LIKE 'cmd\_%' THEN CONCAT(
|
||||
'Controls access to the :',
|
||||
REPLACE(SUBSTRING(`column_name`, 5), '_', ' '),
|
||||
' command. Values: 0 = disabled, 1 = allowed.'
|
||||
)
|
||||
WHEN `column_name` LIKE 'acc\_%' AND `column_type` LIKE '%''2''%' THEN CONCAT(
|
||||
'Controls the ',
|
||||
REPLACE(SUBSTRING(`column_name`, 5), '_', ' '),
|
||||
' capability for this rank. Values: 0 = disabled, 1 = enabled, 2 = enabled only when room-owner rights may be used.'
|
||||
)
|
||||
WHEN `column_name` LIKE 'acc\_%' THEN CONCAT(
|
||||
'Controls the ',
|
||||
REPLACE(SUBSTRING(`column_name`, 5), '_', ' '),
|
||||
' capability for this rank. Values: 0 = disabled, 1 = enabled.'
|
||||
)
|
||||
ELSE CONCAT(
|
||||
'Legacy permission-related value migrated from the old permissions table for ',
|
||||
`column_name`,
|
||||
'.'
|
||||
)
|
||||
END AS `comment`
|
||||
FROM `information_schema`.`columns`
|
||||
WHERE `table_schema` = DATABASE()
|
||||
AND `table_name` = 'permissions'
|
||||
AND `column_name` NOT IN (
|
||||
'id',
|
||||
'rank_name',
|
||||
'hidden_rank',
|
||||
'badge',
|
||||
'job_description',
|
||||
'staff_color',
|
||||
'staff_background',
|
||||
'level',
|
||||
'room_effect',
|
||||
'log_commands',
|
||||
'prefix',
|
||||
'prefix_color',
|
||||
'auto_credits_amount',
|
||||
'auto_pixels_amount',
|
||||
'auto_gotw_amount',
|
||||
'auto_points_amount'
|
||||
)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
`max_value` = VALUES(`max_value`),
|
||||
`comment` = VALUES(`comment`);
|
||||
|
||||
DROP TEMPORARY TABLE IF EXISTS `tmp_permission_comments`;
|
||||
|
||||
CREATE TEMPORARY TABLE `tmp_permission_comments` (
|
||||
`permission_key` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL,
|
||||
`comment` text NOT NULL,
|
||||
PRIMARY KEY (`permission_key`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_uca1400_ai_ci;
|
||||
|
||||
INSERT INTO `tmp_permission_comments` (`permission_key`, `comment`) VALUES
|
||||
('cmd_about', 'Allows using :about to display emulator, revision, or hotel information exposed by the command.'),
|
||||
('cmd_alert', 'Allows using :alert to send a hotel alert popup to a specific user.'),
|
||||
('cmd_allow_trading', 'Allows using the trading-toggle command to enable or disable trading for a target user.'),
|
||||
('cmd_badge', 'Allows granting a badge code to a target user through a command.'),
|
||||
('cmd_ban', 'Allows banning users from the hotel.'),
|
||||
('cmd_blockalert', 'Allows sending the block-alert style moderation message.'),
|
||||
('cmd_bots', 'Allows using :bots to list the bots currently placed in the room.'),
|
||||
('cmd_bundle', 'Allows using :bundle / :roombundle to create a catalog room-bundle offer for the current room.'),
|
||||
('cmd_calendar', 'Allows using the hotel calendar command and any calendar actions wired to that command entry.'),
|
||||
('cmd_changename', 'Allows forcing a user-name change through the change-name command flow.'),
|
||||
('cmd_chatcolor', 'Allows changing the active chat bubble color through the chat-color command.'),
|
||||
('cmd_commands', 'Allows using :commands to list the command keys available to the current user.'),
|
||||
('cmd_connect_camera', 'Allows using the command that links the in-room camera feature to the current room session.'),
|
||||
('cmd_control', 'Allows using :control to take over another in-room user and stop controlling them later.'),
|
||||
('cmd_coords', 'Allows using :coords to inspect room coordinates for tiles, users, or furniture.'),
|
||||
('cmd_credits', 'Allows giving or removing credits from a user through the staff currency command.'),
|
||||
('cmd_subscription', 'Allows granting or editing subscription time through the subscription command.'),
|
||||
('cmd_danceall', 'Allows forcing every Habbo currently in the room to dance.'),
|
||||
('cmd_diagonal', 'Allows toggling diagonal walking for the current room.'),
|
||||
('cmd_disconnect', 'Allows disconnecting a user from the hotel immediately.'),
|
||||
('cmd_duckets', 'Allows giving or removing duckets from a user through the staff currency command.'),
|
||||
('cmd_ejectall', 'Allows ejecting all users from the current room.'),
|
||||
('cmd_empty', 'Allows clearing the current user furniture inventory through the empty-inventory command.'),
|
||||
('cmd_empty_bots', 'Allows clearing the current user bot inventory through the empty-bots command.'),
|
||||
('cmd_empty_pets', 'Allows clearing the current user pet inventory through the empty-pets command.'),
|
||||
('cmd_enable', 'Allows applying an avatar effect to yourself, or to another user when acc_enable_others is also granted.'),
|
||||
('cmd_event', 'Allows marking the current room as an event room through the event command.'),
|
||||
('cmd_faceless', 'Allows toggling the faceless avatar visual state on the executing room unit.'),
|
||||
('cmd_fastwalk', 'Allows toggling fast-walk mode for yourself or another in-room user.'),
|
||||
('cmd_filterword', 'Allows adding or removing entries from the configured word filter through command usage.'),
|
||||
('cmd_freeze', 'Allows freezing a target user in place.'),
|
||||
('cmd_freeze_bots', 'Allows freezing bots that are placed in the room.'),
|
||||
('cmd_gift', 'Allows sending a gift to a target user through the gift command.'),
|
||||
('cmd_give_rank', 'Allows setting another user rank through the give-rank command.'),
|
||||
('cmd_ha', 'Allows sending a hotel-wide alert.'),
|
||||
('acc_can_stalk', 'Allows following users even when they have disabled stalking.'),
|
||||
('cmd_hal', 'Allows sending a hotel-wide alert with a clickable link or extended content.'),
|
||||
('cmd_invisible', 'Allows toggling invisible staff mode.'),
|
||||
('cmd_ip_ban', 'Allows banning a user by IP address.'),
|
||||
('cmd_machine_ban', 'Allows banning a user by machine identifier.'),
|
||||
('cmd_hand_item', 'Allows spawning or changing the hand item currently held by a user.'),
|
||||
('cmd_happyhour', 'Allows starting or stopping the happy-hour event flow exposed by the happyhour command.'),
|
||||
('cmd_hidewired', 'Allows toggling whether wired furniture is visually hidden in the current room.'),
|
||||
('cmd_kickall', 'Allows kicking every user from the current room.'),
|
||||
('cmd_softkick', 'Allows soft-kicking a user back to the hotel view without a full sanction.'),
|
||||
('cmd_massbadge', 'Allows giving the same badge to many users at once.'),
|
||||
('cmd_roombadge', 'Allows setting or overriding the room badge shown to users.'),
|
||||
('cmd_masscredits', 'Allows giving credits to many users at once through the mass-credits command.'),
|
||||
('cmd_massduckets', 'Allows giving duckets to many users at once through the mass-duckets command.'),
|
||||
('cmd_massgift', 'Allows sending the same gift to many users at once.'),
|
||||
('cmd_masspoints', 'Allows giving activity points to many users at once through the mass-points command.'),
|
||||
('cmd_moonwalk', 'Allows toggling the moonwalk avatar effect for yourself while you are inside a room.'),
|
||||
('cmd_mimic', 'Allows copying another user appearance or presence state through the mimic command.'),
|
||||
('cmd_multi', 'Allows executing multiple chat commands from the special sticky/post-it scripting payload.'),
|
||||
('cmd_mute', 'Allows muting a target user.'),
|
||||
('cmd_pet_info', 'Allows opening the detailed pet-information view for a pet.'),
|
||||
('cmd_pickall', 'Allows picking up every furniture item from the current room.'),
|
||||
('cmd_plugins', 'Legacy key for the :plugins command, which currently lists loaded plugins without enforcing this dedicated permission node in code.'),
|
||||
('cmd_points', 'Allows giving or removing activity points from a user through the points command.'),
|
||||
('cmd_promote_offer', 'Allows using :promoteoffer to list active target offers or switch the globally promoted target offer.'),
|
||||
('cmd_pull', 'Allows pulling a nearby user onto the tile directly in front of you.'),
|
||||
('cmd_push', 'Allows pushing the user standing in front of you one tile farther in the direction you are facing.'),
|
||||
('cmd_redeem', 'Allows redeeming redeemable inventory items through the redeem command flow.'),
|
||||
('cmd_reload_room', 'Allows unloading and reloading the current room, then forwarding the occupants back into the fresh room instance.'),
|
||||
('cmd_roomalert', 'Allows sending the same alert message to everyone in the current room.'),
|
||||
('cmd_roomcredits', 'Allows giving credits to every Habbo currently in the room.'),
|
||||
('cmd_roomeffect', 'Allows applying the same avatar effect id to every Habbo currently in the room.'),
|
||||
('cmd_roomgift', 'Allows sending the same gift to every Habbo currently in the room.'),
|
||||
('cmd_roomitem', 'Allows setting the same hand-item id for every Habbo in the room; using 0 clears the hand item.'),
|
||||
('cmd_roommute', 'Allows muting every Habbo currently in the room.'),
|
||||
('cmd_roompixels', 'Allows giving duckets or pixels to every Habbo currently in the room.'),
|
||||
('cmd_roompoints', 'Allows giving activity points to every Habbo currently in the room.'),
|
||||
('cmd_say', 'Allows forcing another online user to say a custom message in their current room.'),
|
||||
('cmd_say_all', 'Allows making everyone in the room say a message.'),
|
||||
('cmd_setmax', 'Allows using :setmax to change the maximum user capacity of the current room.'),
|
||||
('cmd_set_poll', 'Allows using :setpoll to attach or remove a poll on the current room.'),
|
||||
('cmd_setpublic', 'Allows using :setpublic to change the room public/private visibility state.'),
|
||||
('cmd_setspeed', 'Allows using :setspeed to change the room walking speed setting.'),
|
||||
('cmd_shout', 'Allows forcing another online user to shout a custom message in their current room.'),
|
||||
('cmd_shout_all', 'Allows making everyone in the room shout a message.'),
|
||||
('cmd_shutdown', 'Allows using the shutdown command to stop the emulator process.'),
|
||||
('cmd_sitdown', 'Allows forcing users to sit down through the sitdown command.'),
|
||||
('cmd_staffalert', 'Allows sending an alert that is visible only to staff members.'),
|
||||
('cmd_staffonline', 'Allows viewing the current list of online staff members.'),
|
||||
('cmd_summon', 'Allows summoning a target user into the room where the staff member currently is.'),
|
||||
('cmd_summonrank', 'Allows summoning all online users of a given rank into the current room.'),
|
||||
('cmd_super_ban', 'Allows issuing the strongest ban command variant exposed by the super-ban command.'),
|
||||
('cmd_stalk', 'Allows following another user to their room.'),
|
||||
('cmd_superpull', 'Allows pulling a user to the tile in front of you without the short-range reach check used by :pull.'),
|
||||
('cmd_take_badge', 'Allows removing a badge code from a target user.'),
|
||||
('cmd_talk', 'Allows using the legacy :talk command to make another user speak a command-provided message.'),
|
||||
('cmd_teleport', 'Allows toggling the room-unit teleport mode used by the :teleport command.'),
|
||||
('cmd_trash', 'Allows deleting or trashing furniture/items through the trash command flow.'),
|
||||
('cmd_transform', 'Allows transforming your room unit into a chosen pet type, race, and color.'),
|
||||
('cmd_unban', 'Allows removing active bans.'),
|
||||
('cmd_unload', 'Allows disposing the current room instance immediately through :unload / :crash.'),
|
||||
('cmd_unmute', 'Allows removing an active mute from a target user.'),
|
||||
('cmd_update_achievements', 'Allows using :update_achievements to reload achievements configuration.'),
|
||||
('cmd_update_bots', 'Allows using :update_bots to reload bot data and bot configuration.'),
|
||||
('cmd_update_catalogue', 'Allows using :update_catalogue to reload catalogue pages and offers.'),
|
||||
('cmd_update_config', 'Allows using :update_config to reload emulator configuration settings.'),
|
||||
('cmd_update_guildparts', 'Allows using :update_guildparts to reload guild badge parts and guild configuration.'),
|
||||
('cmd_update_hotel_view', 'Allows using :update_hotel_view to reload hotel-view assets or settings.'),
|
||||
('cmd_update_items', 'Allows using :update_items to reload item data and furniture definitions.'),
|
||||
('cmd_update_navigator', 'Allows using :update_navigator to reload navigator configuration and listings.'),
|
||||
('cmd_update_permissions', 'Allows using :update_permissions to reload ranks and permissions from the database.'),
|
||||
('cmd_update_pet_data', 'Allows using :update_pet_data to reload pet types and pet races.'),
|
||||
('cmd_update_plugins', 'Allows using :update_plugins to reload plugin data or plugin metadata.'),
|
||||
('cmd_update_polls', 'Allows using :update_polls to reload poll and questionnaire data.'),
|
||||
('cmd_update_texts', 'Allows using :update_texts to reload external texts and localizations.'),
|
||||
('cmd_update_wordfilter', 'Allows using :update_wordfilter to reload the word-filter list.'),
|
||||
('cmd_userinfo', 'Allows opening the detailed user-information view used by staff tools.'),
|
||||
('cmd_word_quiz', 'Allows starting a room word-quiz event with a custom question and optional duration.'),
|
||||
('cmd_warp', 'Allows instantly warping your room unit to a target tile.'),
|
||||
('acc_anychatcolor', 'Allows selecting any chat bubble color, including normally restricted colors.'),
|
||||
('acc_anyroomowner', 'Treats the rank as room owner for owner-only checks such as room settings, wired saving, rights management, floorplan editing, and similar room-owner gates.'),
|
||||
('acc_empty_others', 'Allows :empty, :empty_bots, and :empty_pets to target another user inventory instead of only your own.'),
|
||||
('acc_enable_others', 'Allows :enable to apply avatar effects to another user instead of only to yourself.'),
|
||||
('acc_see_whispers', 'Allows seeing whispers sent between other users in the room.'),
|
||||
('acc_see_tentchat', 'Allows seeing tent chat or similar hidden chat channels that are normally not visible to everyone.'),
|
||||
('acc_superwired', 'Allows saving advanced wired data without the normal wordfilter and reward payload restrictions applied to regular users.'),
|
||||
('acc_supporttool', 'Allows opening and using the support/moderation tool interface.'),
|
||||
('acc_unkickable', 'Prevents the user from being kicked by normal moderation or room commands.'),
|
||||
('acc_guildgate', 'Allows bypassing guild gate access restrictions.'),
|
||||
('acc_moverotate', 'Allows moving, rotating, and saving wired furniture without the usual room-owner restriction checks.'),
|
||||
('acc_placefurni', 'Allows placing furniture, opening :wired, and passing room-right checks that normally require owner or controller rights.'),
|
||||
('acc_unlimited_bots', 'Removes both the bot inventory cap and the per-room bot placement cap for this rank.'),
|
||||
('acc_unlimited_pets', 'Removes both the pet inventory cap and the per-room pet placement cap for this rank.'),
|
||||
('acc_hide_ip', 'Hides the user IP address in staff tools and other staff-facing views.'),
|
||||
('acc_hide_mail', 'Hides the user email address in moderation tools and staff views.'),
|
||||
('acc_not_mimiced', 'Prevents other users from mimicking this account.'),
|
||||
('acc_chat_no_flood', 'Exempts the user from flood protection limits.'),
|
||||
('acc_staff_chat', 'Allows accessing staff-only chat channels and staff broadcasts.'),
|
||||
('acc_staff_pick', 'Allows using staff item pick-up actions that bypass normal room ownership restrictions.'),
|
||||
('acc_enteranyroom', 'Allows entering rooms regardless of door mode, bans, or normal access restrictions.'),
|
||||
('acc_fullrooms', 'Allows entering rooms even when they are at maximum user capacity.'),
|
||||
('acc_infinite_credits', 'Prevents credits from being consumed when a command or purchase checks credit balance.'),
|
||||
('acc_infinite_pixels', 'Prevents duckets or pixels from being consumed when the balance is checked.'),
|
||||
('acc_infinite_points', 'Prevents activity points from being consumed when the balance is checked.'),
|
||||
('acc_ambassador', 'Marks the rank as an ambassador for ambassador-only tools and visuals.'),
|
||||
('acc_debug', 'Allows using debug-only features, commands, or internal tooling.'),
|
||||
('acc_chat_no_limit', 'Lets the user hear and be heard regardless of room hearing distance limits.'),
|
||||
('acc_chat_no_filter', 'Bypasses the word filter for chat and staff-generated messages.'),
|
||||
('acc_nomute', 'Prevents the user from being muted by normal mute checks.'),
|
||||
('acc_guild_admin', 'Allows bypassing guild admin restrictions when managing guilds.'),
|
||||
('acc_catalog_ids', 'Allows seeing internal catalogue page ids, offer ids, or related technical catalogue identifiers.'),
|
||||
('acc_modtool_ticket_q', 'Allows seeing and handling the moderation ticket queue.'),
|
||||
('acc_modtool_user_logs', 'Allows reading user chat logs in the moderation tool.'),
|
||||
('acc_modtool_user_alert', 'Allows sending moderation alerts or cautions to users.'),
|
||||
('acc_modtool_user_kick', 'Allows kicking users from the moderation tool.'),
|
||||
('acc_modtool_user_ban', 'Allows banning users from the moderation tool.'),
|
||||
('acc_modtool_room_info', 'Allows viewing room information in the moderation tool.'),
|
||||
('acc_modtool_room_logs', 'Allows viewing room chat logs in the moderation tool.'),
|
||||
('acc_trade_anywhere', 'Allows starting trades outside the normal trade-enabled areas.'),
|
||||
('acc_update_notifications', 'Allows receiving update notifications emitted by the emulator.'),
|
||||
('acc_helper_use_guide_tool', 'Allows opening the helper guide tool.'),
|
||||
('acc_helper_give_guide_tours', 'Allows accepting and handling guide tour requests.'),
|
||||
('acc_helper_judge_chat_reviews', 'Allows reviewing helper or chat review tickets.'),
|
||||
('acc_floorplan_editor', 'Allows opening and saving the floorplan editor.'),
|
||||
('acc_camera', 'Allows using the in-room camera feature and related camera UI actions.'),
|
||||
('acc_ads_background', 'Allows editing room advertisement backgrounds.'),
|
||||
('cmd_wordquiz', 'Legacy alias of cmd_word_quiz for starting a room word-quiz event.'),
|
||||
('acc_room_staff_tags', 'Shows staff tags or markers above the user while inside rooms.'),
|
||||
('acc_infinite_friends', 'Removes the normal friend-list size limit.'),
|
||||
('acc_mimic_unredeemed', 'Allows mimicking looks even when they contain unreleased or restricted clothing.'),
|
||||
('cmd_update_youtube_playlists', 'Allows reloading YouTube playlist configuration for furniture integrations.'),
|
||||
('cmd_add_youtube_playlist', 'Allows adding a new YouTube playlist entry.'),
|
||||
('acc_mention', 'Allows using mention-related chat features beyond the normal rank restriction.'),
|
||||
('cmd_setstate', 'Legacy room-editor permission for :setstate / :ss, used to change the selected furni state or extradata value.'),
|
||||
('cmd_buildheight', 'Legacy room-editor permission for :buildheight / :bh, used to change the room build-height override.'),
|
||||
('cmd_setrotation', 'Legacy room-editor permission for :setrotation / :rot, used to change the rotation of the selected furni.'),
|
||||
('cmd_sellroom', 'Allows putting the current room up for sale through the sell-room command.'),
|
||||
('cmd_buyroom', 'Allows purchasing a room that is marked as for sale through the buy-room command.'),
|
||||
('cmd_pay', 'Allows transferring currency to another user through the pay command.'),
|
||||
('cmd_kill', 'Allows using the kill command effect exposed by the current command set.'),
|
||||
('cmd_hoverboard', 'Allows toggling the hoverboard effect or hoverboard movement mode.'),
|
||||
('cmd_kiss', 'Allows using the kiss interaction command on another user.'),
|
||||
('cmd_hug', 'Allows using the hug interaction command on another user.'),
|
||||
('cmd_welcome', 'Allows triggering the welcome command behavior defined by the current command set.'),
|
||||
('cmd_disable_effects', 'Allows disabling active avatar effects through the disable-effects command.'),
|
||||
('cmd_brb', 'Allows toggling the be-right-back status command.'),
|
||||
('cmd_nuke', 'Allows using the nuke command exposed by the current command set.'),
|
||||
('cmd_slime', 'Allows applying the slime command/effect exposed by the current command set.'),
|
||||
('cmd_explain', 'Allows using the explain command to send the predefined explanation/help flow to users.'),
|
||||
('cmd_closedice', 'Legacy essentials permission for :closedice, used to close dice items in the room or all dice at once.'),
|
||||
('acc_closedice_room', 'Legacy companion permission used by older closed-dice room checks.'),
|
||||
('cmd_set', 'Legacy essentials permission for :set / :changefurni, the generic furni editing command documented by :set info.'),
|
||||
('cmd_furnidata', 'Allows viewing technical furnidata information in-game for selected furniture.'),
|
||||
('kiss_cmd', 'Legacy alias used for the kiss command permission.'),
|
||||
('acc_calendar_force', 'Allows claiming calendar rewards even when the normal day-difference timing check would block the claim.'),
|
||||
('cmd_update_calendar', 'Allows using :update_calendar to reload calendar definitions and rewards.'),
|
||||
('cmd_update_all', 'Allows using :update_all to reload all supported runtime data sets in one command.'),
|
||||
('cms_dance', 'Legacy CMS-side permission kept for website integrations; no direct in-emulator command handler was found in the current tree.'),
|
||||
('acc_catalogfurni', 'Allows using catalogue administration features related to furniture pages and offers.'),
|
||||
('acc_unignorable', 'Prevents the account from being ignored by other users through the ignore system.'),
|
||||
('cmd_update_chat_bubbles', 'Allows using :update_chat_bubbles to reload chat-bubble definitions and assets.'),
|
||||
('cmd_calendar_staff', 'Allows the staff-only actions exposed by the calendar command flow.');
|
||||
|
||||
UPDATE `permission_definitions` pd
|
||||
INNER JOIN `tmp_permission_comments` tc ON tc.`permission_key` = pd.`permission_key`
|
||||
SET pd.`comment` = tc.`comment`;
|
||||
|
||||
DROP TEMPORARY TABLE IF EXISTS `tmp_permission_comments`;
|
||||
|
||||
DROP PROCEDURE IF EXISTS `refresh_permission_definition_values`;
|
||||
|
||||
DELIMITER $$
|
||||
CREATE PROCEDURE `refresh_permission_definition_values`()
|
||||
BEGIN
|
||||
DECLARE done INT DEFAULT 0;
|
||||
DECLARE current_rank_id INT;
|
||||
DECLARE current_column_name VARCHAR(32);
|
||||
DECLARE rank_cursor CURSOR FOR SELECT `id` FROM `permission_ranks` ORDER BY `id` ASC;
|
||||
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
|
||||
|
||||
OPEN rank_cursor;
|
||||
|
||||
rank_loop: LOOP
|
||||
FETCH rank_cursor INTO current_rank_id;
|
||||
|
||||
IF done = 1 THEN
|
||||
LEAVE rank_loop;
|
||||
END IF;
|
||||
|
||||
SET current_column_name = CONCAT('rank_', current_rank_id);
|
||||
|
||||
SELECT GROUP_CONCAT(
|
||||
CONCAT(
|
||||
'SELECT ''',
|
||||
REPLACE(`column_name`, '''', ''''''),
|
||||
''' AS permission_key, CAST(COALESCE(`',
|
||||
REPLACE(`column_name`, '`', '``'),
|
||||
'`, ''0'') AS UNSIGNED) AS permission_value FROM `permissions` WHERE `id` = ',
|
||||
current_rank_id
|
||||
)
|
||||
ORDER BY `ordinal_position`
|
||||
SEPARATOR ' UNION ALL '
|
||||
) INTO @permission_rank_source_sql
|
||||
FROM `information_schema`.`columns`
|
||||
WHERE `table_schema` = DATABASE()
|
||||
AND `table_name` = 'permissions'
|
||||
AND `column_name` NOT IN (
|
||||
'id',
|
||||
'rank_name',
|
||||
'hidden_rank',
|
||||
'badge',
|
||||
'job_description',
|
||||
'staff_color',
|
||||
'staff_background',
|
||||
'level',
|
||||
'room_effect',
|
||||
'log_commands',
|
||||
'prefix',
|
||||
'prefix_color',
|
||||
'auto_credits_amount',
|
||||
'auto_pixels_amount',
|
||||
'auto_gotw_amount',
|
||||
'auto_points_amount'
|
||||
);
|
||||
|
||||
SET @permission_rank_update_sql = CONCAT(
|
||||
'UPDATE `permission_definitions` pd ',
|
||||
'INNER JOIN (',
|
||||
@permission_rank_source_sql,
|
||||
') src ON src.permission_key = pd.permission_key ',
|
||||
'SET pd.`',
|
||||
current_column_name,
|
||||
'` = src.permission_value'
|
||||
);
|
||||
|
||||
PREPARE permission_rank_update_stmt FROM @permission_rank_update_sql;
|
||||
EXECUTE permission_rank_update_stmt;
|
||||
DEALLOCATE PREPARE permission_rank_update_stmt;
|
||||
END LOOP;
|
||||
|
||||
CLOSE rank_cursor;
|
||||
END$$
|
||||
DELIMITER ;
|
||||
|
||||
CALL `refresh_permission_definition_values`();
|
||||
@@ -0,0 +1,7 @@
|
||||
CREATE TABLE IF NOT EXISTS `room_wired_settings` (
|
||||
`room_id` int(11) NOT NULL,
|
||||
`inspect_mask` int(11) NOT NULL DEFAULT 0 COMMENT 'Bitmask for who can open and inspect Wired in the room. 1=everyone, 2=users with rights, 4=group members, 8=group admins.',
|
||||
`modify_mask` int(11) NOT NULL DEFAULT 0 COMMENT 'Bitmask for who can modify Wired in the room. 2=users with rights, 4=group members, 8=group admins.',
|
||||
PRIMARY KEY (`room_id`),
|
||||
CONSTRAINT `fk_room_wired_settings_room_id` FOREIGN KEY (`room_id`) REFERENCES `rooms` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
@@ -1,71 +0,0 @@
|
||||
ALTER TABLE `users` DROP KEY IF EXISTS `auth_ticket`;
|
||||
ALTER TABLE `users`
|
||||
MODIFY `auth_ticket` VARCHAR(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '';
|
||||
CREATE INDEX IF NOT EXISTS `idx_users_auth_ticket` ON `users` (`auth_ticket`);
|
||||
CREATE INDEX IF NOT EXISTS `idx_rel_user_room` ON `room_enter_log` (`user_id`, `room_id`);
|
||||
CREATE INDEX IF NOT EXISTS `idx_lhcp_user_claimed` ON `logs_hc_payday` (`user_id`, `claimed`);
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS `uniq_room_votes_user_room` ON `room_votes` (`user_id`, `room_id`);
|
||||
ALTER TABLE `room_votes` DROP KEY IF EXISTS `user_id`;
|
||||
CREATE INDEX IF NOT EXISTS `idx_rgs_room_ts` ON `room_game_scores` (`room_id`, `game_start_timestamp`);
|
||||
CREATE INDEX IF NOT EXISTS `idx_rgs_user` ON `room_game_scores` (`user_id`);
|
||||
CREATE UNIQUE INDEX IF NOT EXISTS `uniq_crc_user_campaign_reward`
|
||||
ON `calendar_rewards_claimed` (`user_id`, `campaign_id`, `reward_id`);
|
||||
ALTER TABLE `calendar_rewards_claimed` DROP KEY IF EXISTS `idx_cal_claimed_user_id`;
|
||||
ALTER TABLE `emulator_settings`
|
||||
ENGINE = InnoDB,
|
||||
CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
DROP TABLE IF EXISTS `gift_wrappers_new`;
|
||||
CREATE TABLE `gift_wrappers_new` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`sprite_id` int(11) NOT NULL,
|
||||
`item_id` int(11) NOT NULL,
|
||||
`type` enum('gift','wrapper') NOT NULL DEFAULT 'wrapper',
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
INSERT INTO `gift_wrappers_new` (`id`, `sprite_id`, `item_id`, `type`)
|
||||
SELECT `id`, `sprite_id`, `item_id`, `type` FROM `gift_wrappers`;
|
||||
DROP TABLE `gift_wrappers`;
|
||||
RENAME TABLE `gift_wrappers_new` TO `gift_wrappers`;
|
||||
|
||||
|
||||
DROP TABLE IF EXISTS `pet_actions_new`;
|
||||
CREATE TABLE `pet_actions_new` (
|
||||
`pet_type` int(2) NOT NULL AUTO_INCREMENT,
|
||||
`pet_name` varchar(32) NOT NULL,
|
||||
`offspring_type` int(3) NOT NULL DEFAULT -1,
|
||||
`happy_actions` varchar(100) NOT NULL DEFAULT '',
|
||||
`tired_actions` varchar(100) NOT NULL DEFAULT '',
|
||||
`random_actions` varchar(100) NOT NULL DEFAULT '',
|
||||
`can_swim` enum('1','0') DEFAULT '0',
|
||||
PRIMARY KEY (`pet_type`) USING BTREE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
INSERT INTO `pet_actions_new`
|
||||
(`pet_type`, `pet_name`, `offspring_type`, `happy_actions`, `tired_actions`, `random_actions`, `can_swim`)
|
||||
SELECT `pet_type`, `pet_name`, `offspring_type`, `happy_actions`, `tired_actions`, `random_actions`, `can_swim`
|
||||
FROM `pet_actions`;
|
||||
DROP TABLE `pet_actions`;
|
||||
RENAME TABLE `pet_actions_new` TO `pet_actions`;
|
||||
|
||||
|
||||
DROP TABLE IF EXISTS `pet_commands_data_new`;
|
||||
CREATE TABLE `pet_commands_data_new` (
|
||||
`command_id` int(3) NOT NULL,
|
||||
`text` varchar(25) NOT NULL,
|
||||
`required_level` int(2) NOT NULL,
|
||||
`reward_xp` int(3) NOT NULL DEFAULT 5,
|
||||
`cost_happiness` int(11) NOT NULL DEFAULT 0,
|
||||
`cost_energy` int(3) NOT NULL DEFAULT 0,
|
||||
PRIMARY KEY (`command_id`) USING BTREE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
INSERT INTO `pet_commands_data_new`
|
||||
(`command_id`, `text`, `required_level`, `reward_xp`, `cost_happiness`, `cost_energy`)
|
||||
SELECT `command_id`, `text`, `required_level`, `reward_xp`, `cost_happiness`, `cost_energy`
|
||||
FROM `pet_commands_data`;
|
||||
DROP TABLE `pet_commands_data`;
|
||||
RENAME TABLE `pet_commands_data_new` TO `pet_commands_data`;
|
||||
|
||||
ALTER TABLE `calendar_rewards`
|
||||
MODIFY `product_name` VARCHAR(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
|
||||
MODIFY `custom_image` VARCHAR(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
|
||||
MODIFY `badge` VARCHAR(25) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
|
||||
MODIFY `subscription_type` VARCHAR(128) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT '';
|
||||
@@ -0,0 +1,997 @@
|
||||
UPDATE emulator_settings SET `value` = '1' WHERE (`key` = 'wired.engine.enabled');
|
||||
UPDATE emulator_settings SET `value` = '1' WHERE (`key` = 'wired.engine.exclusive');
|
||||
|
||||
ALTER TABLE emulator_settings
|
||||
ADD COLUMN IF NOT EXISTS `comment` VARCHAR(255) NOT NULL AFTER `value`;
|
||||
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `catalog_items_bc` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`item_ids` varchar(666) NOT NULL,
|
||||
`page_id` int(11) NOT NULL,
|
||||
`catalog_name` varchar(100) NOT NULL,
|
||||
`order_number` int(11) NOT NULL DEFAULT 1,
|
||||
`extradata` varchar(500) NOT NULL DEFAULT '',
|
||||
PRIMARY KEY (`id`) USING BTREE
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=21 DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci ROW_FORMAT=DYNAMIC;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `catalog_pages_bc` (
|
||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
||||
`parent_id` int(11) NOT NULL DEFAULT -1,
|
||||
`caption` varchar(128) NOT NULL,
|
||||
`page_layout` enum(
|
||||
'default_3x3','club_buy','club_gift','frontpage','spaces','recycler',
|
||||
'recycler_info','recycler_prizes','trophies','plasto','marketplace',
|
||||
'marketplace_own_items','spaces_new','soundmachine','guilds','guild_furni',
|
||||
'info_duckets','info_rentables','info_pets','roomads','single_bundle',
|
||||
'sold_ltd_items','badge_display','bots','pets','pets2','pets3',
|
||||
'productpage1','room_bundle','recent_purchases',
|
||||
'default_3x3_color_grouping','guild_forum','vip_buy','info_loyalty',
|
||||
'loyalty_vip_buy','collectibles','petcustomization','frontpage_featured'
|
||||
) NOT NULL DEFAULT 'default_3x3',
|
||||
`icon_color` int(11) NOT NULL DEFAULT 1,
|
||||
`icon_image` int(11) NOT NULL DEFAULT 1,
|
||||
`order_num` int(11) NOT NULL DEFAULT 1,
|
||||
`visible` enum('0','1') NOT NULL DEFAULT '1',
|
||||
`enabled` enum('0','1') NOT NULL DEFAULT '1',
|
||||
`page_headline` varchar(1024) NOT NULL DEFAULT '',
|
||||
`page_teaser` varchar(64) NOT NULL DEFAULT '',
|
||||
`page_special` varchar(2048) DEFAULT '' COMMENT 'Gold Bubble: catalog_special_txtbg1 // Speech Bubble: catalog_special_txtbg2 // Place normal text in page_text_teaser',
|
||||
`page_text1` text DEFAULT NULL,
|
||||
`page_text2` text DEFAULT NULL,
|
||||
`page_text_details` text DEFAULT NULL,
|
||||
`page_text_teaser` text DEFAULT NULL,
|
||||
PRIMARY KEY (`id`) USING BTREE
|
||||
) ENGINE=MyISAM AUTO_INCREMENT=9 DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci ROW_FORMAT=DYNAMIC;
|
||||
|
||||
ALTER TABLE `catalog_club_offers`
|
||||
MODIFY COLUMN `type` ENUM('HC','VIP','BUILDERS_CLUB','BUILDERS_CLUB_ADDON') NOT NULL DEFAULT 'HC';
|
||||
|
||||
ALTER TABLE `catalog_pages`
|
||||
MODIFY COLUMN `page_layout` ENUM(
|
||||
'default_3x3',
|
||||
'club_buy',
|
||||
'club_gift',
|
||||
'frontpage',
|
||||
'spaces',
|
||||
'recycler',
|
||||
'recycler_info',
|
||||
'recycler_prizes',
|
||||
'trophies',
|
||||
'plasto',
|
||||
'marketplace',
|
||||
'marketplace_own_items',
|
||||
'spaces_new',
|
||||
'soundmachine',
|
||||
'guilds',
|
||||
'guild_furni',
|
||||
'info_duckets',
|
||||
'info_rentables',
|
||||
'info_pets',
|
||||
'roomads',
|
||||
'single_bundle',
|
||||
'sold_ltd_items',
|
||||
'badge_display',
|
||||
'bots',
|
||||
'pets',
|
||||
'pets2',
|
||||
'pets3',
|
||||
'productpage1',
|
||||
'room_bundle',
|
||||
'recent_purchases',
|
||||
'default_3x3_color_grouping',
|
||||
'guild_forum',
|
||||
'vip_buy',
|
||||
'info_loyalty',
|
||||
'loyalty_vip_buy',
|
||||
'collectibles',
|
||||
'petcustomization',
|
||||
'frontpage_featured',
|
||||
'builders_club_frontpage',
|
||||
'builders_club_addons',
|
||||
'builders_club_loyalty'
|
||||
) NOT NULL DEFAULT 'default_3x3';
|
||||
|
||||
ALTER TABLE `catalog_pages`
|
||||
ADD COLUMN IF NOT EXISTS `catalog_mode` ENUM('NORMAL','BUILDER','BOTH') NOT NULL DEFAULT 'NORMAL'
|
||||
AFTER `club_only`;
|
||||
|
||||
ALTER TABLE `catalog_pages_bc`
|
||||
MODIFY COLUMN `page_layout` ENUM(
|
||||
'default_3x3',
|
||||
'club_buy',
|
||||
'club_gift',
|
||||
'frontpage',
|
||||
'spaces',
|
||||
'recycler',
|
||||
'recycler_info',
|
||||
'recycler_prizes',
|
||||
'trophies',
|
||||
'plasto',
|
||||
'marketplace',
|
||||
'marketplace_own_items',
|
||||
'spaces_new',
|
||||
'soundmachine',
|
||||
'guilds',
|
||||
'guild_furni',
|
||||
'info_duckets',
|
||||
'info_rentables',
|
||||
'info_pets',
|
||||
'roomads',
|
||||
'single_bundle',
|
||||
'sold_ltd_items',
|
||||
'badge_display',
|
||||
'bots',
|
||||
'pets',
|
||||
'pets2',
|
||||
'pets3',
|
||||
'productpage1',
|
||||
'room_bundle',
|
||||
'recent_purchases',
|
||||
'default_3x3_color_grouping',
|
||||
'guild_forum',
|
||||
'vip_buy',
|
||||
'info_loyalty',
|
||||
'loyalty_vip_buy',
|
||||
'collectibles',
|
||||
'petcustomization',
|
||||
'frontpage_featured',
|
||||
'builders_club_frontpage',
|
||||
'builders_club_addons',
|
||||
'builders_club_loyalty'
|
||||
) NOT NULL DEFAULT 'default_3x3';
|
||||
|
||||
SET @col_exists := (
|
||||
SELECT COUNT(*) FROM information_schema.COLUMNS
|
||||
WHERE TABLE_SCHEMA = DATABASE()
|
||||
AND TABLE_NAME = 'users_settings'
|
||||
AND COLUMN_NAME = 'builders_club_bonus_furni'
|
||||
);
|
||||
SET @sql := IF(@col_exists = 0,
|
||||
'ALTER TABLE `users_settings` ADD COLUMN `builders_club_bonus_furni` INT NOT NULL DEFAULT 0;',
|
||||
'SELECT "exists";'
|
||||
);
|
||||
PREPARE stmt FROM @sql; EXECUTE stmt; DEALLOCATE PREPARE stmt;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `wired_emulator_settings` (
|
||||
`key` varchar(191) NOT NULL,
|
||||
`value` text NOT NULL,
|
||||
`comment` text NOT NULL,
|
||||
PRIMARY KEY (`key`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci;
|
||||
|
||||
INSERT INTO `wired_emulator_settings` (`key`, `value`, `comment`)
|
||||
SELECT 'wired.engine.enabled', COALESCE((SELECT `value` FROM `emulator_settings` WHERE `key` = 'wired.engine.enabled' LIMIT 1), '1'), 'Compatibility flag kept for older configs. The runtime now always uses the new wired engine.'
|
||||
UNION ALL
|
||||
SELECT 'wired.engine.exclusive', COALESCE((SELECT `value` FROM `emulator_settings` WHERE `key` = 'wired.engine.exclusive' LIMIT 1), '1'), 'Compatibility flag kept for older configs. The runtime now always uses the new wired engine.'
|
||||
UNION ALL
|
||||
SELECT 'wired.engine.maxStepsPerStack', COALESCE((SELECT `value` FROM `emulator_settings` WHERE `key` = 'wired.engine.maxStepsPerStack' LIMIT 1), '100'), 'Maximum amount of internal processing steps allowed for a single wired stack execution.'
|
||||
UNION ALL
|
||||
SELECT 'wired.engine.debug', COALESCE((SELECT `value` FROM `emulator_settings` WHERE `key` = 'wired.engine.debug' LIMIT 1), '0'), 'Enable verbose debug logging for the new wired engine.'
|
||||
UNION ALL
|
||||
SELECT 'wired.custom.enabled', COALESCE((SELECT `value` FROM `emulator_settings` WHERE `key` = 'wired.custom.enabled' LIMIT 1), '0'), 'Enable custom legacy wired behaviour such as user-based cooldown exceptions and compatibility logic.'
|
||||
UNION ALL
|
||||
SELECT 'hotel.wired.furni.selection.count', COALESCE((SELECT `value` FROM `emulator_settings` WHERE `key` = 'hotel.wired.furni.selection.count' LIMIT 1), '5'), 'Maximum number of furni that a wired box can store or select.'
|
||||
UNION ALL
|
||||
SELECT 'hotel.wired.max_delay', COALESCE((SELECT `value` FROM `emulator_settings` WHERE `key` = 'hotel.wired.max_delay' LIMIT 1), '20'), 'Maximum delay value accepted by wired effects that support delayed execution.'
|
||||
UNION ALL
|
||||
SELECT 'hotel.wired.message.max_length', COALESCE((SELECT `value` FROM `emulator_settings` WHERE `key` = 'hotel.wired.message.max_length' LIMIT 1), '100'), 'Maximum length of text fields used by wired messages and bot text effects.'
|
||||
UNION ALL
|
||||
SELECT 'wired.effect.teleport.delay', COALESCE((SELECT `value` FROM `emulator_settings` WHERE `key` = 'wired.effect.teleport.delay' LIMIT 1), '500'), 'Delay in milliseconds used by wired teleport movement.'
|
||||
UNION ALL
|
||||
SELECT 'wired.place.under', COALESCE((SELECT `value` FROM `emulator_settings` WHERE `key` = 'wired.place.under' LIMIT 1), '0'), 'Allow placing wired furniture underneath other items when room rules permit it.'
|
||||
UNION ALL
|
||||
SELECT 'wired.tick.interval.ms', COALESCE((SELECT `value` FROM `emulator_settings` WHERE `key` = 'wired.tick.interval.ms' LIMIT 1), '50'), 'Global wired tick interval in milliseconds used by repeaters and other tick-driven wired items.'
|
||||
UNION ALL
|
||||
SELECT 'wired.tick.resolution', COALESCE((SELECT `value` FROM `emulator_settings` WHERE `key` = 'wired.tick.resolution' LIMIT 1), '100'), 'Legacy wired tick resolution value kept for compatibility with older wired timing setups.'
|
||||
UNION ALL
|
||||
SELECT 'wired.tick.debug', COALESCE((SELECT `value` FROM `emulator_settings` WHERE `key` = 'wired.tick.debug' LIMIT 1), '0'), 'Enable verbose logging for the wired tick service.'
|
||||
UNION ALL
|
||||
SELECT 'wired.tick.thread.priority', COALESCE((SELECT `value` FROM `emulator_settings` WHERE `key` = 'wired.tick.thread.priority' LIMIT 1), '6'), 'Java thread priority used by the wired tick service.'
|
||||
UNION ALL
|
||||
SELECT 'wired.highscores.displaycount', COALESCE((SELECT `value` FROM `emulator_settings` WHERE `key` = 'wired.highscores.displaycount' LIMIT 1), '25'), 'Maximum number of wired highscore entries shown to users when a highscore is displayed.'
|
||||
UNION ALL
|
||||
SELECT 'wired.abuse.max.recursion.depth', COALESCE((SELECT `value` FROM `emulator_settings` WHERE `key` = 'wired.abuse.max.recursion.depth' LIMIT 1), '10'), 'Maximum recursive wired depth allowed before execution is stopped.'
|
||||
UNION ALL
|
||||
SELECT 'wired.abuse.max.events.per.window', COALESCE((SELECT `value` FROM `emulator_settings` WHERE `key` = 'wired.abuse.max.events.per.window' LIMIT 1), '100'), 'Maximum amount of identical wired events allowed inside the abuse rate-limit window before a room ban is applied.'
|
||||
UNION ALL
|
||||
SELECT 'wired.abuse.rate.limit.window.ms', COALESCE((SELECT `value` FROM `emulator_settings` WHERE `key` = 'wired.abuse.rate.limit.window.ms' LIMIT 1), '10000'), 'Time window in milliseconds used by the wired abuse rate limiter.'
|
||||
UNION ALL
|
||||
SELECT 'wired.abuse.ban.duration.ms', COALESCE((SELECT `value` FROM `emulator_settings` WHERE `key` = 'wired.abuse.ban.duration.ms' LIMIT 1), '600000'), 'Duration in milliseconds of the temporary wired ban after abuse detection.'
|
||||
UNION ALL
|
||||
SELECT 'wired.monitor.usage.window.ms', COALESCE((SELECT `value` FROM `emulator_settings` WHERE `key` = 'wired.monitor.usage.window.ms' LIMIT 1), '1000'), 'Rolling window size in milliseconds used to calculate wired usage in the :wired monitor.'
|
||||
UNION ALL
|
||||
SELECT 'wired.monitor.usage.limit', COALESCE((SELECT `value` FROM `emulator_settings` WHERE `key` = 'wired.monitor.usage.limit' LIMIT 1), '1000'), 'Maximum wired usage budget allowed in one monitor window before EXECUTION_CAP is raised.'
|
||||
UNION ALL
|
||||
SELECT 'wired.monitor.delayed.events.limit', COALESCE((SELECT `value` FROM `emulator_settings` WHERE `key` = 'wired.monitor.delayed.events.limit' LIMIT 1), '100'), 'Maximum number of delayed wired events that can be queued in one room at the same time.'
|
||||
UNION ALL
|
||||
SELECT 'wired.monitor.overload.average.ms', COALESCE((SELECT `value` FROM `emulator_settings` WHERE `key` = 'wired.monitor.overload.average.ms' LIMIT 1), '50'), 'Average execution time threshold in milliseconds that starts overload tracking.'
|
||||
UNION ALL
|
||||
SELECT 'wired.monitor.overload.peak.ms', COALESCE((SELECT `value` FROM `emulator_settings` WHERE `key` = 'wired.monitor.overload.peak.ms' LIMIT 1), '150'), 'Peak single execution time threshold in milliseconds that starts overload tracking.'
|
||||
UNION ALL
|
||||
SELECT 'wired.monitor.overload.consecutive.windows', COALESCE((SELECT `value` FROM `emulator_settings` WHERE `key` = 'wired.monitor.overload.consecutive.windows' LIMIT 1), '2'), 'Number of consecutive overloaded monitor windows required before logging EXECUTOR_OVERLOAD.'
|
||||
UNION ALL
|
||||
SELECT 'wired.monitor.heavy.usage.percent', COALESCE((SELECT `value` FROM `emulator_settings` WHERE `key` = 'wired.monitor.heavy.usage.percent' LIMIT 1), '70'), 'Usage percentage threshold that contributes to marking a room as heavy in the :wired monitor.'
|
||||
UNION ALL
|
||||
SELECT 'wired.monitor.heavy.consecutive.windows', COALESCE((SELECT `value` FROM `emulator_settings` WHERE `key` = 'wired.monitor.heavy.consecutive.windows' LIMIT 1), '5'), 'Number of consecutive windows above the heavy usage threshold required before the room is marked as heavy.'
|
||||
UNION ALL
|
||||
SELECT 'wired.monitor.heavy.delayed.percent', COALESCE((SELECT `value` FROM `emulator_settings` WHERE `key` = 'wired.monitor.heavy.delayed.percent' LIMIT 1), '60'), 'Delayed queue percentage threshold that also contributes to the heavy-room calculation.'
|
||||
ON DUPLICATE KEY UPDATE
|
||||
`value` = VALUES(`value`),
|
||||
`comment` = VALUES(`comment`);
|
||||
|
||||
DELETE FROM `emulator_settings`
|
||||
WHERE `key` IN (
|
||||
'wired.engine.enabled',
|
||||
'wired.engine.exclusive',
|
||||
'wired.engine.maxStepsPerStack',
|
||||
'wired.engine.debug',
|
||||
'wired.custom.enabled',
|
||||
'hotel.wired.furni.selection.count',
|
||||
'hotel.wired.max_delay',
|
||||
'hotel.wired.message.max_length',
|
||||
'wired.effect.teleport.delay',
|
||||
'wired.place.under',
|
||||
'wired.tick.interval.ms',
|
||||
'wired.tick.resolution',
|
||||
'wired.tick.debug',
|
||||
'wired.tick.thread.priority',
|
||||
'wired.highscores.displaycount',
|
||||
'wired.abuse.max.recursion.depth',
|
||||
'wired.abuse.max.events.per.window',
|
||||
'wired.abuse.rate.limit.window.ms',
|
||||
'wired.abuse.ban.duration.ms',
|
||||
'wired.monitor.usage.window.ms',
|
||||
'wired.monitor.usage.limit',
|
||||
'wired.monitor.delayed.events.limit',
|
||||
'wired.monitor.overload.average.ms',
|
||||
'wired.monitor.overload.peak.ms',
|
||||
'wired.monitor.overload.consecutive.windows',
|
||||
'wired.monitor.heavy.usage.percent',
|
||||
'wired.monitor.heavy.consecutive.windows',
|
||||
'wired.monitor.heavy.delayed.percent'
|
||||
);
|
||||
|
||||
UPDATE `emulator_settings` SET `comment` = 'Allow whispering while a user stands inside a mute area.' WHERE `key` = 'room.chat.mutearea.allow_whisper';
|
||||
UPDATE `emulator_settings` SET `comment` = 'HTML or text format used for room chat prefixes.' WHERE `key` = 'room.chat.prefix.format';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Badge code displayed on promoted rooms.' WHERE `key` = 'room.promotion.badge';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Image used by Rosie bubble notifications.' WHERE `key` = 'rosie.bubble.image.url';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Currency type used by Rosie when buying a room or room package.' WHERE `key` = 'rosie.buyroom.currency.type';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Configuration value used by `runtime.threads`.' WHERE `key` = 'runtime.threads';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Configuration value used by `save.private.chats`.' WHERE `key` = 'save.private.chats';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Configuration value used by `save.room.chats`.' WHERE `key` = 'save.room.chats';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Expose moderation tickets to the scripter or automation tooling.' WHERE `key` = 'scripter.modtool.tickets';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Currency type ID used for diamonds.' WHERE `key` = 'seasonal.currency.diamond';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Currency type ID used for duckets.' WHERE `key` = 'seasonal.currency.ducket';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Semicolon-separated display names for seasonal currency types.' WHERE `key` = 'seasonal.currency.names';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Currency type ID used for pixels.' WHERE `key` = 'seasonal.currency.pixel';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Currency type ID used for shells.' WHERE `key` = 'seasonal.currency.shell';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Primary seasonal currency type ID.' WHERE `key` = 'seasonal.primary.type';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Semicolon-separated list of currency type IDs treated as seasonal currencies.' WHERE `key` = 'seasonal.types';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Achievement code granted for the HC subscription tier.' WHERE `key` = 'subscriptions.hc.achievement';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Number of days before expiry when HC discount offers become available.' WHERE `key` = 'subscriptions.hc.discount.days_before_end';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Enable discounted HC renewal offers.' WHERE `key` = 'subscriptions.hc.discount.enabled';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Reset tracked credits spent when the HC subscription expires.' WHERE `key` = 'subscriptions.hc.payday.creditsspent_reset_on_expire';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Currency rewarded by the HC payday system.' WHERE `key` = 'subscriptions.hc.payday.currency';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Enable the HC payday reward system.' WHERE `key` = 'subscriptions.hc.payday.enabled';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Date interval used between HC payday reward runs.' WHERE `key` = 'subscriptions.hc.payday.interval';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Next scheduled execution date for HC payday rewards.' WHERE `key` = 'subscriptions.hc.payday.next_date';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Percentage of eligible spending returned by HC payday.' WHERE `key` = 'subscriptions.hc.payday.percentage';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Semicolon-separated streak thresholds and rewards for HC payday.' WHERE `key` = 'subscriptions.hc.payday.streak';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Enable the subscription background scheduler.' WHERE `key` = 'subscriptions.scheduler.enabled';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Interval in minutes between subscription scheduler runs.' WHERE `key` = 'subscriptions.scheduler.interval';
|
||||
UPDATE `emulator_settings` SET `comment` = 'Compatibility marker used by the custom team wired implementation. Do not remove.' WHERE `key` = 'team.wired.update.rc-1';
|
||||
UPDATE `emulator_settings` SET `comment` = 'API key used by the YouTube integration.' WHERE `key` = 'youtube.apikey';
|
||||
|
||||
DROP VIEW IF EXISTS `permissions_matrix_view`;
|
||||
DROP PROCEDURE IF EXISTS `refresh_permissions_matrix_view`;
|
||||
DROP TABLE IF EXISTS `permission_rank_values`;
|
||||
DROP TABLE IF EXISTS `permission_nodes`;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `permission_ranks` (
|
||||
`id` int(11) NOT NULL,
|
||||
`rank_name` varchar(25) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL,
|
||||
`hidden_rank` tinyint(1) NOT NULL DEFAULT 0,
|
||||
`badge` varchar(12) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL DEFAULT '',
|
||||
`job_description` varchar(255) NOT NULL DEFAULT 'Here to help',
|
||||
`staff_color` varchar(8) NOT NULL DEFAULT '#327fa8',
|
||||
`staff_background` varchar(255) NOT NULL DEFAULT 'staff-bg.png',
|
||||
`level` int(11) NOT NULL DEFAULT 1,
|
||||
`room_effect` int(11) NOT NULL DEFAULT 0,
|
||||
`log_commands` enum('0','1') CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL DEFAULT '0',
|
||||
`prefix` varchar(5) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL DEFAULT '',
|
||||
`prefix_color` varchar(7) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL DEFAULT '',
|
||||
`auto_credits_amount` int(11) DEFAULT 0,
|
||||
`auto_pixels_amount` int(11) DEFAULT 0,
|
||||
`auto_gotw_amount` int(11) DEFAULT 0,
|
||||
`auto_points_amount` int(11) DEFAULT 0,
|
||||
PRIMARY KEY (`id`) USING BTREE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_uca1400_ai_ci ROW_FORMAT=DYNAMIC;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `permission_definitions` (
|
||||
`permission_key` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL,
|
||||
`max_value` tinyint(3) unsigned NOT NULL DEFAULT 1,
|
||||
`comment` text NOT NULL,
|
||||
PRIMARY KEY (`permission_key`) USING BTREE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_uca1400_ai_ci ROW_FORMAT=DYNAMIC;
|
||||
|
||||
ALTER TABLE `permission_definitions`
|
||||
DROP COLUMN IF EXISTS `category`,
|
||||
DROP COLUMN IF EXISTS `value_type`,
|
||||
DROP COLUMN IF EXISTS `sort_order`;
|
||||
|
||||
INSERT INTO `permission_ranks` (
|
||||
`id`,
|
||||
`rank_name`,
|
||||
`hidden_rank`,
|
||||
`badge`,
|
||||
`job_description`,
|
||||
`staff_color`,
|
||||
`staff_background`,
|
||||
`level`,
|
||||
`room_effect`,
|
||||
`log_commands`,
|
||||
`prefix`,
|
||||
`prefix_color`,
|
||||
`auto_credits_amount`,
|
||||
`auto_pixels_amount`,
|
||||
`auto_gotw_amount`,
|
||||
`auto_points_amount`
|
||||
)
|
||||
SELECT
|
||||
`id`,
|
||||
`rank_name`,
|
||||
`hidden_rank`,
|
||||
`badge`,
|
||||
`job_description`,
|
||||
`staff_color`,
|
||||
`staff_background`,
|
||||
`level`,
|
||||
`room_effect`,
|
||||
`log_commands`,
|
||||
`prefix`,
|
||||
`prefix_color`,
|
||||
`auto_credits_amount`,
|
||||
`auto_pixels_amount`,
|
||||
`auto_gotw_amount`,
|
||||
`auto_points_amount`
|
||||
FROM `permissions`
|
||||
ON DUPLICATE KEY UPDATE
|
||||
`rank_name` = VALUES(`rank_name`),
|
||||
`hidden_rank` = VALUES(`hidden_rank`),
|
||||
`badge` = VALUES(`badge`),
|
||||
`job_description` = VALUES(`job_description`),
|
||||
`staff_color` = VALUES(`staff_color`),
|
||||
`staff_background` = VALUES(`staff_background`),
|
||||
`level` = VALUES(`level`),
|
||||
`room_effect` = VALUES(`room_effect`),
|
||||
`log_commands` = VALUES(`log_commands`),
|
||||
`prefix` = VALUES(`prefix`),
|
||||
`prefix_color` = VALUES(`prefix_color`),
|
||||
`auto_credits_amount` = VALUES(`auto_credits_amount`),
|
||||
`auto_pixels_amount` = VALUES(`auto_pixels_amount`),
|
||||
`auto_gotw_amount` = VALUES(`auto_gotw_amount`),
|
||||
`auto_points_amount` = VALUES(`auto_points_amount`);
|
||||
|
||||
DROP PROCEDURE IF EXISTS `refresh_permission_definition_rank_columns`;
|
||||
|
||||
DELIMITER $$
|
||||
CREATE PROCEDURE `refresh_permission_definition_rank_columns`()
|
||||
BEGIN
|
||||
DECLARE done INT DEFAULT 0;
|
||||
DECLARE current_rank_id INT;
|
||||
DECLARE current_column_name VARCHAR(32);
|
||||
DECLARE column_exists INT DEFAULT 0;
|
||||
DECLARE rank_cursor CURSOR FOR SELECT `id` FROM `permission_ranks` ORDER BY `id` ASC;
|
||||
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
|
||||
|
||||
OPEN rank_cursor;
|
||||
|
||||
rank_loop: LOOP
|
||||
FETCH rank_cursor INTO current_rank_id;
|
||||
|
||||
IF done = 1 THEN
|
||||
LEAVE rank_loop;
|
||||
END IF;
|
||||
|
||||
SET current_column_name = CONCAT('rank_', current_rank_id);
|
||||
|
||||
SELECT COUNT(*)
|
||||
INTO column_exists
|
||||
FROM `information_schema`.`columns`
|
||||
WHERE `table_schema` = DATABASE()
|
||||
AND `table_name` = 'permission_definitions'
|
||||
AND `column_name` = current_column_name;
|
||||
|
||||
IF column_exists = 0 THEN
|
||||
SET @alter_permissions_column_sql = CONCAT(
|
||||
'ALTER TABLE `permission_definitions` ADD COLUMN `',
|
||||
current_column_name,
|
||||
'` tinyint(3) unsigned NOT NULL DEFAULT 0'
|
||||
);
|
||||
|
||||
PREPARE alter_permissions_column_stmt FROM @alter_permissions_column_sql;
|
||||
EXECUTE alter_permissions_column_stmt;
|
||||
DEALLOCATE PREPARE alter_permissions_column_stmt;
|
||||
END IF;
|
||||
END LOOP;
|
||||
|
||||
CLOSE rank_cursor;
|
||||
END$$
|
||||
DELIMITER ;
|
||||
|
||||
CALL `refresh_permission_definition_rank_columns`();
|
||||
|
||||
INSERT INTO `permission_definitions` (
|
||||
`permission_key`,
|
||||
`max_value`,
|
||||
`comment`
|
||||
)
|
||||
SELECT
|
||||
`column_name` AS `permission_key`,
|
||||
CASE
|
||||
WHEN `column_type` LIKE '%''2''%' THEN 2
|
||||
ELSE 1
|
||||
END AS `max_value`,
|
||||
CASE
|
||||
WHEN COALESCE(`column_comment`, '') <> '' THEN `column_comment`
|
||||
WHEN `column_name` LIKE 'cmd\_%' AND `column_type` LIKE '%''2''%' THEN CONCAT(
|
||||
'Controls access to the :',
|
||||
REPLACE(SUBSTRING(`column_name`, 5), '_', ' '),
|
||||
' command. Values: 0 = disabled, 1 = allowed, 2 = allowed only when room-owner rights may be used.'
|
||||
)
|
||||
WHEN `column_name` LIKE 'cmd\_%' THEN CONCAT(
|
||||
'Controls access to the :',
|
||||
REPLACE(SUBSTRING(`column_name`, 5), '_', ' '),
|
||||
' command. Values: 0 = disabled, 1 = allowed.'
|
||||
)
|
||||
WHEN `column_name` LIKE 'acc\_%' AND `column_type` LIKE '%''2''%' THEN CONCAT(
|
||||
'Controls the ',
|
||||
REPLACE(SUBSTRING(`column_name`, 5), '_', ' '),
|
||||
' capability for this rank. Values: 0 = disabled, 1 = enabled, 2 = enabled only when room-owner rights may be used.'
|
||||
)
|
||||
WHEN `column_name` LIKE 'acc\_%' THEN CONCAT(
|
||||
'Controls the ',
|
||||
REPLACE(SUBSTRING(`column_name`, 5), '_', ' '),
|
||||
' capability for this rank. Values: 0 = disabled, 1 = enabled.'
|
||||
)
|
||||
ELSE CONCAT(
|
||||
'Legacy permission-related value migrated from the old permissions table for ',
|
||||
`column_name`,
|
||||
'.'
|
||||
)
|
||||
END AS `comment`
|
||||
FROM `information_schema`.`columns`
|
||||
WHERE `table_schema` = DATABASE()
|
||||
AND `table_name` = 'permissions'
|
||||
AND `column_name` NOT IN (
|
||||
'id',
|
||||
'rank_name',
|
||||
'hidden_rank',
|
||||
'badge',
|
||||
'job_description',
|
||||
'staff_color',
|
||||
'staff_background',
|
||||
'level',
|
||||
'room_effect',
|
||||
'log_commands',
|
||||
'prefix',
|
||||
'prefix_color',
|
||||
'auto_credits_amount',
|
||||
'auto_pixels_amount',
|
||||
'auto_gotw_amount',
|
||||
'auto_points_amount'
|
||||
)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
`max_value` = VALUES(`max_value`),
|
||||
`comment` = VALUES(`comment`);
|
||||
|
||||
DROP TEMPORARY TABLE IF EXISTS `tmp_permission_comments`;
|
||||
|
||||
CREATE TEMPORARY TABLE `tmp_permission_comments` (
|
||||
`permission_key` varchar(64) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NOT NULL,
|
||||
`comment` text NOT NULL,
|
||||
PRIMARY KEY (`permission_key`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_uca1400_ai_ci;
|
||||
|
||||
INSERT INTO `tmp_permission_comments` (`permission_key`, `comment`) VALUES
|
||||
('cmd_about', 'Allows using :about to display emulator, revision, or hotel information exposed by the command.'),
|
||||
('cmd_alert', 'Allows using :alert to send a hotel alert popup to a specific user.'),
|
||||
('cmd_allow_trading', 'Allows using the trading-toggle command to enable or disable trading for a target user.'),
|
||||
('cmd_badge', 'Allows granting a badge code to a target user through a command.'),
|
||||
('cmd_ban', 'Allows banning users from the hotel.'),
|
||||
('cmd_blockalert', 'Allows sending the block-alert style moderation message.'),
|
||||
('cmd_bots', 'Allows using :bots to list the bots currently placed in the room.'),
|
||||
('cmd_bundle', 'Allows using :bundle / :roombundle to create a catalog room-bundle offer for the current room.'),
|
||||
('cmd_calendar', 'Allows using the hotel calendar command and any calendar actions wired to that command entry.'),
|
||||
('cmd_changename', 'Allows forcing a user-name change through the change-name command flow.'),
|
||||
('cmd_chatcolor', 'Allows changing the active chat bubble color through the chat-color command.'),
|
||||
('cmd_commands', 'Allows using :commands to list the command keys available to the current user.'),
|
||||
('cmd_connect_camera', 'Allows using the command that links the in-room camera feature to the current room session.'),
|
||||
('cmd_control', 'Allows using :control to take over another in-room user and stop controlling them later.'),
|
||||
('cmd_coords', 'Allows using :coords to inspect room coordinates for tiles, users, or furniture.'),
|
||||
('cmd_credits', 'Allows giving or removing credits from a user through the staff currency command.'),
|
||||
('cmd_subscription', 'Allows granting or editing subscription time through the subscription command.'),
|
||||
('cmd_danceall', 'Allows forcing every Habbo currently in the room to dance.'),
|
||||
('cmd_diagonal', 'Allows toggling diagonal walking for the current room.'),
|
||||
('cmd_disconnect', 'Allows disconnecting a user from the hotel immediately.'),
|
||||
('cmd_duckets', 'Allows giving or removing duckets from a user through the staff currency command.'),
|
||||
('cmd_ejectall', 'Allows ejecting all users from the current room.'),
|
||||
('cmd_empty', 'Allows clearing the current user furniture inventory through the empty-inventory command.'),
|
||||
('cmd_empty_bots', 'Allows clearing the current user bot inventory through the empty-bots command.'),
|
||||
('cmd_empty_pets', 'Allows clearing the current user pet inventory through the empty-pets command.'),
|
||||
('cmd_enable', 'Allows applying an avatar effect to yourself, or to another user when acc_enable_others is also granted.'),
|
||||
('cmd_event', 'Allows marking the current room as an event room through the event command.'),
|
||||
('cmd_faceless', 'Allows toggling the faceless avatar visual state on the executing room unit.'),
|
||||
('cmd_fastwalk', 'Allows toggling fast-walk mode for yourself or another in-room user.'),
|
||||
('cmd_filterword', 'Allows adding or removing entries from the configured word filter through command usage.'),
|
||||
('cmd_freeze', 'Allows freezing a target user in place.'),
|
||||
('cmd_freeze_bots', 'Allows freezing bots that are placed in the room.'),
|
||||
('cmd_gift', 'Allows sending a gift to a target user through the gift command.'),
|
||||
('cmd_give_rank', 'Allows setting another user rank through the give-rank command.'),
|
||||
('cmd_ha', 'Allows sending a hotel-wide alert.'),
|
||||
('acc_can_stalk', 'Allows following users even when they have disabled stalking.'),
|
||||
('cmd_hal', 'Allows sending a hotel-wide alert with a clickable link or extended content.'),
|
||||
('cmd_invisible', 'Allows toggling invisible staff mode.'),
|
||||
('cmd_ip_ban', 'Allows banning a user by IP address.'),
|
||||
('cmd_machine_ban', 'Allows banning a user by machine identifier.'),
|
||||
('cmd_hand_item', 'Allows spawning or changing the hand item currently held by a user.'),
|
||||
('cmd_happyhour', 'Allows starting or stopping the happy-hour event flow exposed by the happyhour command.'),
|
||||
('cmd_hidewired', 'Allows toggling whether wired furniture is visually hidden in the current room.'),
|
||||
('cmd_kickall', 'Allows kicking every user from the current room.'),
|
||||
('cmd_softkick', 'Allows soft-kicking a user back to the hotel view without a full sanction.'),
|
||||
('cmd_massbadge', 'Allows giving the same badge to many users at once.'),
|
||||
('cmd_roombadge', 'Allows setting or overriding the room badge shown to users.'),
|
||||
('cmd_masscredits', 'Allows giving credits to many users at once through the mass-credits command.'),
|
||||
('cmd_massduckets', 'Allows giving duckets to many users at once through the mass-duckets command.'),
|
||||
('cmd_massgift', 'Allows sending the same gift to many users at once.'),
|
||||
('cmd_masspoints', 'Allows giving activity points to many users at once through the mass-points command.'),
|
||||
('cmd_moonwalk', 'Allows toggling the moonwalk avatar effect for yourself while you are inside a room.'),
|
||||
('cmd_mimic', 'Allows copying another user appearance or presence state through the mimic command.'),
|
||||
('cmd_multi', 'Allows executing multiple chat commands from the special sticky/post-it scripting payload.'),
|
||||
('cmd_mute', 'Allows muting a target user.'),
|
||||
('cmd_pet_info', 'Allows opening the detailed pet-information view for a pet.'),
|
||||
('cmd_pickall', 'Allows picking up every furniture item from the current room.'),
|
||||
('cmd_plugins', 'Legacy key for the :plugins command, which currently lists loaded plugins without enforcing this dedicated permission node in code.'),
|
||||
('cmd_points', 'Allows giving or removing activity points from a user through the points command.'),
|
||||
('cmd_promote_offer', 'Allows using :promoteoffer to list active target offers or switch the globally promoted target offer.'),
|
||||
('cmd_pull', 'Allows pulling a nearby user onto the tile directly in front of you.'),
|
||||
('cmd_push', 'Allows pushing the user standing in front of you one tile farther in the direction you are facing.'),
|
||||
('cmd_redeem', 'Allows redeeming redeemable inventory items through the redeem command flow.'),
|
||||
('cmd_reload_room', 'Allows unloading and reloading the current room, then forwarding the occupants back into the fresh room instance.'),
|
||||
('cmd_roomalert', 'Allows sending the same alert message to everyone in the current room.'),
|
||||
('cmd_roomcredits', 'Allows giving credits to every Habbo currently in the room.'),
|
||||
('cmd_roomeffect', 'Allows applying the same avatar effect id to every Habbo currently in the room.'),
|
||||
('cmd_roomgift', 'Allows sending the same gift to every Habbo currently in the room.'),
|
||||
('cmd_roomitem', 'Allows setting the same hand-item id for every Habbo in the room; using 0 clears the hand item.'),
|
||||
('cmd_roommute', 'Allows muting every Habbo currently in the room.'),
|
||||
('cmd_roompixels', 'Allows giving duckets or pixels to every Habbo currently in the room.'),
|
||||
('cmd_roompoints', 'Allows giving activity points to every Habbo currently in the room.'),
|
||||
('cmd_say', 'Allows forcing another online user to say a custom message in their current room.'),
|
||||
('cmd_say_all', 'Allows making everyone in the room say a message.'),
|
||||
('cmd_setmax', 'Allows using :setmax to change the maximum user capacity of the current room.'),
|
||||
('cmd_set_poll', 'Allows using :setpoll to attach or remove a poll on the current room.'),
|
||||
('cmd_setpublic', 'Allows using :setpublic to change the room public/private visibility state.'),
|
||||
('cmd_setspeed', 'Allows using :setspeed to change the room walking speed setting.'),
|
||||
('cmd_shout', 'Allows forcing another online user to shout a custom message in their current room.'),
|
||||
('cmd_shout_all', 'Allows making everyone in the room shout a message.'),
|
||||
('cmd_shutdown', 'Allows using the shutdown command to stop the emulator process.'),
|
||||
('cmd_sitdown', 'Allows forcing users to sit down through the sitdown command.'),
|
||||
('cmd_staffalert', 'Allows sending an alert that is visible only to staff members.'),
|
||||
('cmd_staffonline', 'Allows viewing the current list of online staff members.'),
|
||||
('cmd_summon', 'Allows summoning a target user into the room where the staff member currently is.'),
|
||||
('cmd_summonrank', 'Allows summoning all online users of a given rank into the current room.'),
|
||||
('cmd_super_ban', 'Allows issuing the strongest ban command variant exposed by the super-ban command.'),
|
||||
('cmd_stalk', 'Allows following another user to their room.'),
|
||||
('cmd_superpull', 'Allows pulling a user to the tile in front of you without the short-range reach check used by :pull.'),
|
||||
('cmd_take_badge', 'Allows removing a badge code from a target user.'),
|
||||
('cmd_talk', 'Allows using the legacy :talk command to make another user speak a command-provided message.'),
|
||||
('cmd_teleport', 'Allows toggling the room-unit teleport mode used by the :teleport command.'),
|
||||
('cmd_trash', 'Allows deleting or trashing furniture/items through the trash command flow.'),
|
||||
('cmd_transform', 'Allows transforming your room unit into a chosen pet type, race, and color.'),
|
||||
('cmd_unban', 'Allows removing active bans.'),
|
||||
('cmd_unload', 'Allows disposing the current room instance immediately through :unload / :crash.'),
|
||||
('cmd_unmute', 'Allows removing an active mute from a target user.'),
|
||||
('cmd_update_achievements', 'Allows using :update_achievements to reload achievements configuration.'),
|
||||
('cmd_update_bots', 'Allows using :update_bots to reload bot data and bot configuration.'),
|
||||
('cmd_update_catalogue', 'Allows using :update_catalogue to reload catalogue pages and offers.'),
|
||||
('cmd_update_config', 'Allows using :update_config to reload emulator configuration settings.'),
|
||||
('cmd_update_guildparts', 'Allows using :update_guildparts to reload guild badge parts and guild configuration.'),
|
||||
('cmd_update_hotel_view', 'Allows using :update_hotel_view to reload hotel-view assets or settings.'),
|
||||
('cmd_update_items', 'Allows using :update_items to reload item data and furniture definitions.'),
|
||||
('cmd_update_navigator', 'Allows using :update_navigator to reload navigator configuration and listings.'),
|
||||
('cmd_update_permissions', 'Allows using :update_permissions to reload ranks and permissions from the database.'),
|
||||
('cmd_update_pet_data', 'Allows using :update_pet_data to reload pet types and pet races.'),
|
||||
('cmd_update_plugins', 'Allows using :update_plugins to reload plugin data or plugin metadata.'),
|
||||
('cmd_update_polls', 'Allows using :update_polls to reload poll and questionnaire data.'),
|
||||
('cmd_update_texts', 'Allows using :update_texts to reload external texts and localizations.'),
|
||||
('cmd_update_wordfilter', 'Allows using :update_wordfilter to reload the word-filter list.'),
|
||||
('cmd_userinfo', 'Allows opening the detailed user-information view used by staff tools.'),
|
||||
('cmd_word_quiz', 'Allows starting a room word-quiz event with a custom question and optional duration.'),
|
||||
('cmd_warp', 'Allows instantly warping your room unit to a target tile.'),
|
||||
('acc_anychatcolor', 'Allows selecting any chat bubble color, including normally restricted colors.'),
|
||||
('acc_anyroomowner', 'Treats the rank as room owner for owner-only checks such as room settings, wired saving, rights management, floorplan editing, and similar room-owner gates.'),
|
||||
('acc_empty_others', 'Allows :empty, :empty_bots, and :empty_pets to target another user inventory instead of only your own.'),
|
||||
('acc_enable_others', 'Allows :enable to apply avatar effects to another user instead of only to yourself.'),
|
||||
('acc_see_whispers', 'Allows seeing whispers sent between other users in the room.'),
|
||||
('acc_see_tentchat', 'Allows seeing tent chat or similar hidden chat channels that are normally not visible to everyone.'),
|
||||
('acc_superwired', 'Allows saving advanced wired data without the normal wordfilter and reward payload restrictions applied to regular users.'),
|
||||
('acc_supporttool', 'Allows opening and using the support/moderation tool interface.'),
|
||||
('acc_unkickable', 'Prevents the user from being kicked by normal moderation or room commands.'),
|
||||
('acc_guildgate', 'Allows bypassing guild gate access restrictions.'),
|
||||
('acc_moverotate', 'Allows moving, rotating, and saving wired furniture without the usual room-owner restriction checks.'),
|
||||
('acc_placefurni', 'Allows placing furniture, opening :wired, and passing room-right checks that normally require owner or controller rights.'),
|
||||
('acc_unlimited_bots', 'Removes both the bot inventory cap and the per-room bot placement cap for this rank.'),
|
||||
('acc_unlimited_pets', 'Removes both the pet inventory cap and the per-room pet placement cap for this rank.'),
|
||||
('acc_hide_ip', 'Hides the user IP address in staff tools and other staff-facing views.'),
|
||||
('acc_hide_mail', 'Hides the user email address in moderation tools and staff views.'),
|
||||
('acc_not_mimiced', 'Prevents other users from mimicking this account.'),
|
||||
('acc_chat_no_flood', 'Exempts the user from flood protection limits.'),
|
||||
('acc_staff_chat', 'Allows accessing staff-only chat channels and staff broadcasts.'),
|
||||
('acc_staff_pick', 'Allows using staff item pick-up actions that bypass normal room ownership restrictions.'),
|
||||
('acc_enteranyroom', 'Allows entering rooms regardless of door mode, bans, or normal access restrictions.'),
|
||||
('acc_fullrooms', 'Allows entering rooms even when they are at maximum user capacity.'),
|
||||
('acc_infinite_credits', 'Prevents credits from being consumed when a command or purchase checks credit balance.'),
|
||||
('acc_infinite_pixels', 'Prevents duckets or pixels from being consumed when the balance is checked.'),
|
||||
('acc_infinite_points', 'Prevents activity points from being consumed when the balance is checked.'),
|
||||
('acc_ambassador', 'Marks the rank as an ambassador for ambassador-only tools and visuals.'),
|
||||
('acc_debug', 'Allows using debug-only features, commands, or internal tooling.'),
|
||||
('acc_chat_no_limit', 'Lets the user hear and be heard regardless of room hearing distance limits.'),
|
||||
('acc_chat_no_filter', 'Bypasses the word filter for chat and staff-generated messages.'),
|
||||
('acc_nomute', 'Prevents the user from being muted by normal mute checks.'),
|
||||
('acc_guild_admin', 'Allows bypassing guild admin restrictions when managing guilds.'),
|
||||
('acc_catalog_ids', 'Allows seeing internal catalogue page ids, offer ids, or related technical catalogue identifiers.'),
|
||||
('acc_modtool_ticket_q', 'Allows seeing and handling the moderation ticket queue.'),
|
||||
('acc_modtool_user_logs', 'Allows reading user chat logs in the moderation tool.'),
|
||||
('acc_modtool_user_alert', 'Allows sending moderation alerts or cautions to users.'),
|
||||
('acc_modtool_user_kick', 'Allows kicking users from the moderation tool.'),
|
||||
('acc_modtool_user_ban', 'Allows banning users from the moderation tool.'),
|
||||
('acc_modtool_room_info', 'Allows viewing room information in the moderation tool.'),
|
||||
('acc_modtool_room_logs', 'Allows viewing room chat logs in the moderation tool.'),
|
||||
('acc_trade_anywhere', 'Allows starting trades outside the normal trade-enabled areas.'),
|
||||
('acc_update_notifications', 'Allows receiving update notifications emitted by the emulator.'),
|
||||
('acc_helper_use_guide_tool', 'Allows opening the helper guide tool.'),
|
||||
('acc_helper_give_guide_tours', 'Allows accepting and handling guide tour requests.'),
|
||||
('acc_helper_judge_chat_reviews', 'Allows reviewing helper or chat review tickets.'),
|
||||
('acc_floorplan_editor', 'Allows opening and saving the floorplan editor.'),
|
||||
('acc_camera', 'Allows using the in-room camera feature and related camera UI actions.'),
|
||||
('acc_ads_background', 'Allows editing room advertisement backgrounds.'),
|
||||
('cmd_wordquiz', 'Legacy alias of cmd_word_quiz for starting a room word-quiz event.'),
|
||||
('acc_room_staff_tags', 'Shows staff tags or markers above the user while inside rooms.'),
|
||||
('acc_infinite_friends', 'Removes the normal friend-list size limit.'),
|
||||
('acc_mimic_unredeemed', 'Allows mimicking looks even when they contain unreleased or restricted clothing.'),
|
||||
('cmd_update_youtube_playlists', 'Allows reloading YouTube playlist configuration for furniture integrations.'),
|
||||
('cmd_add_youtube_playlist', 'Allows adding a new YouTube playlist entry.'),
|
||||
('acc_mention', 'Allows using mention-related chat features beyond the normal rank restriction.'),
|
||||
('cmd_setstate', 'Legacy room-editor permission for :setstate / :ss, used to change the selected furni state or extradata value.'),
|
||||
('cmd_buildheight', 'Legacy room-editor permission for :buildheight / :bh, used to change the room build-height override.'),
|
||||
('cmd_setrotation', 'Legacy room-editor permission for :setrotation / :rot, used to change the rotation of the selected furni.'),
|
||||
('cmd_sellroom', 'Allows putting the current room up for sale through the sell-room command.'),
|
||||
('cmd_buyroom', 'Allows purchasing a room that is marked as for sale through the buy-room command.'),
|
||||
('cmd_pay', 'Allows transferring currency to another user through the pay command.'),
|
||||
('cmd_kill', 'Allows using the kill command effect exposed by the current command set.'),
|
||||
('cmd_hoverboard', 'Allows toggling the hoverboard effect or hoverboard movement mode.'),
|
||||
('cmd_kiss', 'Allows using the kiss interaction command on another user.'),
|
||||
('cmd_hug', 'Allows using the hug interaction command on another user.'),
|
||||
('cmd_welcome', 'Allows triggering the welcome command behavior defined by the current command set.'),
|
||||
('cmd_disable_effects', 'Allows disabling active avatar effects through the disable-effects command.'),
|
||||
('cmd_brb', 'Allows toggling the be-right-back status command.'),
|
||||
('cmd_nuke', 'Allows using the nuke command exposed by the current command set.'),
|
||||
('cmd_slime', 'Allows applying the slime command/effect exposed by the current command set.'),
|
||||
('cmd_explain', 'Allows using the explain command to send the predefined explanation/help flow to users.'),
|
||||
('cmd_closedice', 'Legacy essentials permission for :closedice, used to close dice items in the room or all dice at once.'),
|
||||
('acc_closedice_room', 'Legacy companion permission used by older closed-dice room checks.'),
|
||||
('cmd_set', 'Legacy essentials permission for :set / :changefurni, the generic furni editing command documented by :set info.'),
|
||||
('cmd_furnidata', 'Allows viewing technical furnidata information in-game for selected furniture.'),
|
||||
('kiss_cmd', 'Legacy alias used for the kiss command permission.'),
|
||||
('acc_calendar_force', 'Allows claiming calendar rewards even when the normal day-difference timing check would block the claim.'),
|
||||
('cmd_update_calendar', 'Allows using :update_calendar to reload calendar definitions and rewards.'),
|
||||
('cmd_update_all', 'Allows using :update_all to reload all supported runtime data sets in one command.'),
|
||||
('cms_dance', 'Legacy CMS-side permission kept for website integrations; no direct in-emulator command handler was found in the current tree.'),
|
||||
('acc_catalogfurni', 'Allows using catalogue administration features related to furniture pages and offers.'),
|
||||
('acc_unignorable', 'Prevents the account from being ignored by other users through the ignore system.'),
|
||||
('cmd_update_chat_bubbles', 'Allows using :update_chat_bubbles to reload chat-bubble definitions and assets.'),
|
||||
('cmd_calendar_staff', 'Allows the staff-only actions exposed by the calendar command flow.');
|
||||
|
||||
UPDATE `permission_definitions` pd
|
||||
INNER JOIN `tmp_permission_comments` tc ON tc.`permission_key` = pd.`permission_key`
|
||||
SET pd.`comment` = tc.`comment`;
|
||||
|
||||
DROP TEMPORARY TABLE IF EXISTS `tmp_permission_comments`;
|
||||
|
||||
DROP PROCEDURE IF EXISTS `refresh_permission_definition_values`;
|
||||
|
||||
DELIMITER $$
|
||||
|
||||
CREATE PROCEDURE `refresh_permission_definition_values`()
|
||||
BEGIN
|
||||
DECLARE done INT DEFAULT 0;
|
||||
DECLARE current_rank_id INT;
|
||||
DECLARE current_column_name VARCHAR(32);
|
||||
|
||||
DECLARE rank_cursor CURSOR FOR
|
||||
SELECT `id` FROM `permission_ranks` ORDER BY `id` ASC;
|
||||
|
||||
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
|
||||
|
||||
OPEN rank_cursor;
|
||||
|
||||
rank_loop: LOOP
|
||||
FETCH rank_cursor INTO current_rank_id;
|
||||
|
||||
IF done = 1 THEN
|
||||
LEAVE rank_loop;
|
||||
END IF;
|
||||
|
||||
SET current_column_name = CONCAT('rank_', current_rank_id);
|
||||
|
||||
SELECT GROUP_CONCAT(
|
||||
CONCAT(
|
||||
'SELECT ''',
|
||||
REPLACE(`column_name`, '''', ''''''),
|
||||
''' AS permission_key, ',
|
||||
'CAST(COALESCE(FLOOR(`',
|
||||
REPLACE(`column_name`, '`', '``'),
|
||||
'`), 0) AS UNSIGNED) AS permission_value ',
|
||||
'FROM `permissions` WHERE `id` = ',
|
||||
current_rank_id
|
||||
)
|
||||
ORDER BY `ordinal_position`
|
||||
SEPARATOR ' UNION ALL '
|
||||
) INTO @permission_rank_source_sql
|
||||
FROM `information_schema`.`columns`
|
||||
WHERE `table_schema` = DATABASE()
|
||||
AND `table_name` = 'permissions'
|
||||
AND `column_name` NOT IN (
|
||||
'id',
|
||||
'rank_name',
|
||||
'hidden_rank',
|
||||
'badge',
|
||||
'job_description',
|
||||
'staff_color',
|
||||
'staff_background',
|
||||
'level',
|
||||
'room_effect',
|
||||
'log_commands',
|
||||
'prefix',
|
||||
'prefix_color',
|
||||
'auto_credits_amount',
|
||||
'auto_pixels_amount',
|
||||
'auto_gotw_amount',
|
||||
'auto_points_amount'
|
||||
);
|
||||
|
||||
SET @permission_rank_update_sql = CONCAT(
|
||||
'UPDATE `permission_definitions` pd ',
|
||||
'INNER JOIN (',
|
||||
@permission_rank_source_sql,
|
||||
') src ON src.permission_key = pd.permission_key ',
|
||||
'SET pd.`',
|
||||
current_column_name,
|
||||
'` = src.permission_value'
|
||||
);
|
||||
|
||||
PREPARE stmt FROM @permission_rank_update_sql;
|
||||
EXECUTE stmt;
|
||||
DEALLOCATE PREPARE stmt;
|
||||
|
||||
END LOOP;
|
||||
|
||||
CLOSE rank_cursor;
|
||||
END$$
|
||||
|
||||
DELIMITER ;
|
||||
|
||||
CALL `refresh_permission_definition_values`();
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `room_wired_settings` (
|
||||
`room_id` int(11) NOT NULL,
|
||||
`inspect_mask` int(11) NOT NULL DEFAULT 0 COMMENT 'Bitmask for who can open and inspect Wired in the room. 1=everyone, 2=users with rights, 4=group members, 8=group admins.',
|
||||
`modify_mask` int(11) NOT NULL DEFAULT 0 COMMENT 'Bitmask for who can modify Wired in the room. 2=users with rights, 4=group members, 8=group admins.',
|
||||
PRIMARY KEY (`room_id`),
|
||||
CONSTRAINT `fk_room_wired_settings_room_id` FOREIGN KEY (`room_id`) REFERENCES `rooms` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `room_user_wired_variables` (
|
||||
`room_id` int(11) NOT NULL,
|
||||
`user_id` int(11) NOT NULL,
|
||||
`variable_item_id` int(11) NOT NULL,
|
||||
`value` int(11) DEFAULT NULL,
|
||||
`created_at` int(11) NOT NULL DEFAULT 0,
|
||||
`updated_at` int(11) NOT NULL DEFAULT 0,
|
||||
PRIMARY KEY (`room_id`, `user_id`, `variable_item_id`),
|
||||
KEY `idx_room_user_wired_variables_room_item` (`room_id`, `variable_item_id`),
|
||||
KEY `idx_room_user_wired_variables_user` (`user_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `room_furni_wired_variables` (
|
||||
`room_id` int(11) NOT NULL,
|
||||
`furni_id` int(11) NOT NULL,
|
||||
`variable_item_id` int(11) NOT NULL,
|
||||
`value` int(11) DEFAULT NULL,
|
||||
`created_at` int(11) NOT NULL DEFAULT 0,
|
||||
`updated_at` int(11) NOT NULL DEFAULT 0,
|
||||
PRIMARY KEY (`room_id`, `furni_id`, `variable_item_id`),
|
||||
KEY `idx_room_furni_wired_variables_room_item` (`room_id`, `variable_item_id`),
|
||||
KEY `idx_room_furni_wired_variables_furni` (`furni_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `room_wired_variables` (
|
||||
`room_id` int(11) NOT NULL,
|
||||
`variable_item_id` int(11) NOT NULL,
|
||||
`value` int(11) NOT NULL DEFAULT 0,
|
||||
`created_at` int(11) NOT NULL DEFAULT 0,
|
||||
`updated_at` int(11) NOT NULL DEFAULT 0,
|
||||
PRIMARY KEY (`room_id`, `variable_item_id`),
|
||||
KEY `idx_room_wired_variables_room_item` (`room_id`, `variable_item_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
|
||||
|
||||
ALTER TABLE `room_user_wired_variables`
|
||||
ADD COLUMN IF NOT EXISTS `created_at` int(11) NOT NULL DEFAULT 0 AFTER `value`;
|
||||
|
||||
ALTER TABLE `room_user_wired_variables`
|
||||
ADD COLUMN IF NOT EXISTS `updated_at` int(11) NOT NULL DEFAULT 0 AFTER `created_at`;
|
||||
|
||||
UPDATE `room_user_wired_variables`
|
||||
SET
|
||||
`created_at` = IF(`created_at` > 0, `created_at`, UNIX_TIMESTAMP()),
|
||||
`updated_at` = IF(`updated_at` > 0, `updated_at`, IF(`created_at` > 0, `created_at`, UNIX_TIMESTAMP()));
|
||||
|
||||
ALTER TABLE `room_furni_wired_variables`
|
||||
ADD COLUMN IF NOT EXISTS `created_at` int(11) NOT NULL DEFAULT 0 AFTER `value`;
|
||||
|
||||
ALTER TABLE `room_furni_wired_variables`
|
||||
ADD COLUMN IF NOT EXISTS `updated_at` int(11) NOT NULL DEFAULT 0 AFTER `created_at`;
|
||||
|
||||
UPDATE `room_furni_wired_variables`
|
||||
SET
|
||||
`created_at` = IF(`created_at` > 0, `created_at`, UNIX_TIMESTAMP()),
|
||||
`updated_at` = IF(`updated_at` > 0, `updated_at`, IF(`created_at` > 0, `created_at`, UNIX_TIMESTAMP()));
|
||||
|
||||
ALTER TABLE `room_wired_variables`
|
||||
ADD COLUMN IF NOT EXISTS `created_at` int(11) NOT NULL DEFAULT 0 AFTER `value`;
|
||||
|
||||
ALTER TABLE `room_wired_variables`
|
||||
ADD COLUMN IF NOT EXISTS `updated_at` int(11) NOT NULL DEFAULT 0 AFTER `created_at`;
|
||||
|
||||
UPDATE `room_wired_variables`
|
||||
SET
|
||||
`created_at` = 0,
|
||||
`updated_at` = IF(`updated_at` > 0, `updated_at`, UNIX_TIMESTAMP());
|
||||
|
||||
INSERT INTO `chat_bubbles` (`type`, `name`, `permission`, `overridable`, `triggers_talking_furniture`) VALUES
|
||||
(200, 'SHOW_MESSAGE_RED', '', 1, 0),
|
||||
(201, 'SHOW_MESSAGE_GREEN', '', 1, 0),
|
||||
(202, 'SHOW_MESSAGE_BLUE', '', 1, 0),
|
||||
(210, 'SHOW_MESSAGE_ALERT', '', 1, 0),
|
||||
(211, 'SHOW_MESSAGE_INFO', '', 1, 0),
|
||||
(212, 'SHOW_MESSAGE_WARNING', '', 1, 0),
|
||||
(220, 'SHOW_MESSAGE_WRONG', '', 1, 0),
|
||||
(221, 'SHOW_MESSAGE_WRONG_CIRCLED', '', 1, 0),
|
||||
(222, 'SHOW_MESSAGE_CORRECT', '', 1, 0),
|
||||
(223, 'SHOW_MESSAGE_CORRECT_CIRCLED', '', 1, 0),
|
||||
(224, 'SHOW_MESSAGE_QUESTION', '', 1, 0),
|
||||
(225, 'SHOW_MESSAGE_QUESTION_CIRCLED', '', 1, 0),
|
||||
(226, 'SHOW_MESSAGE_ARROW_UP', '', 1, 0),
|
||||
(227, 'SHOW_MESSAGE_ARROW_UP_CIRCLED', '', 1, 0),
|
||||
(228, 'SHOW_MESSAGE_ARROW_DOWN', '', 1, 0),
|
||||
(229, 'SHOW_MESSAGE_ARROW_DOWN_CIRCLED', '', 1, 0),
|
||||
(250, 'SHOW_MESSAGE_SKULL', '', 1, 0),
|
||||
(251, 'SHOW_MESSAGE_SKULL_ALT', '', 1, 0),
|
||||
(252, 'SHOW_MESSAGE_MAGNIFIER', '', 1, 0)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
`name` = VALUES(`name`),
|
||||
`permission` = VALUES(`permission`),
|
||||
`overridable` = VALUES(`overridable`),
|
||||
`triggers_talking_furniture` = VALUES(`triggers_talking_furniture`);
|
||||
|
||||
ALTER TABLE `catalog_club_offers`
|
||||
MODIFY COLUMN `type` ENUM('HC', 'VIP', 'BUILDERS_CLUB', 'BUILDERS_CLUB_ADDON') NOT NULL DEFAULT 'HC';
|
||||
|
||||
ALTER TABLE `catalog_pages`
|
||||
MODIFY COLUMN `page_layout` ENUM(
|
||||
'default_3x3',
|
||||
'club_buy',
|
||||
'club_gift',
|
||||
'frontpage',
|
||||
'spaces',
|
||||
'recycler',
|
||||
'recycler_info',
|
||||
'recycler_prizes',
|
||||
'trophies',
|
||||
'plasto',
|
||||
'marketplace',
|
||||
'marketplace_own_items',
|
||||
'spaces_new',
|
||||
'soundmachine',
|
||||
'guilds',
|
||||
'guild_furni',
|
||||
'info_duckets',
|
||||
'info_rentables',
|
||||
'info_pets',
|
||||
'roomads',
|
||||
'single_bundle',
|
||||
'sold_ltd_items',
|
||||
'badge_display',
|
||||
'bots',
|
||||
'pets',
|
||||
'pets2',
|
||||
'pets3',
|
||||
'productpage1',
|
||||
'room_bundle',
|
||||
'recent_purchases',
|
||||
'default_3x3_color_grouping',
|
||||
'guild_forum',
|
||||
'vip_buy',
|
||||
'info_loyalty',
|
||||
'loyalty_vip_buy',
|
||||
'collectibles',
|
||||
'petcustomization',
|
||||
'frontpage_featured',
|
||||
'builders_club_frontpage',
|
||||
'builders_club_addons',
|
||||
'builders_club_loyalty'
|
||||
) NOT NULL DEFAULT 'default_3x3';
|
||||
|
||||
ALTER TABLE `catalog_pages`
|
||||
ADD COLUMN IF NOT EXISTS `catalog_mode` ENUM('NORMAL', 'BUILDER', 'BOTH') NOT NULL DEFAULT 'NORMAL' AFTER `club_only`;
|
||||
|
||||
ALTER TABLE `rooms`
|
||||
ADD COLUMN IF NOT EXISTS `builders_club_trial_locked` TINYINT(1) NOT NULL DEFAULT 0 AFTER `allow_underpass`,
|
||||
ADD COLUMN IF NOT EXISTS `builders_club_original_state` VARCHAR(16) NOT NULL DEFAULT 'open' AFTER `builders_club_trial_locked`;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `builders_club_items` (
|
||||
`item_id` INT(11) NOT NULL,
|
||||
`user_id` INT(11) NOT NULL,
|
||||
`room_id` INT(11) NOT NULL DEFAULT 0,
|
||||
PRIMARY KEY (`item_id`),
|
||||
KEY `idx_builders_club_items_user_id` (`user_id`),
|
||||
KEY `idx_builders_club_items_room_id` (`room_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci;
|
||||
|
||||
ALTER TABLE `catalog_pages_bc`
|
||||
MODIFY COLUMN `page_layout` ENUM(
|
||||
'default_3x3',
|
||||
'club_buy',
|
||||
'club_gift',
|
||||
'frontpage',
|
||||
'spaces',
|
||||
'recycler',
|
||||
'recycler_info',
|
||||
'recycler_prizes',
|
||||
'trophies',
|
||||
'plasto',
|
||||
'marketplace',
|
||||
'marketplace_own_items',
|
||||
'spaces_new',
|
||||
'soundmachine',
|
||||
'guilds',
|
||||
'guild_furni',
|
||||
'info_duckets',
|
||||
'info_rentables',
|
||||
'info_pets',
|
||||
'roomads',
|
||||
'single_bundle',
|
||||
'sold_ltd_items',
|
||||
'badge_display',
|
||||
'bots',
|
||||
'pets',
|
||||
'pets2',
|
||||
'pets3',
|
||||
'productpage1',
|
||||
'room_bundle',
|
||||
'recent_purchases',
|
||||
'default_3x3_color_grouping',
|
||||
'guild_forum',
|
||||
'vip_buy',
|
||||
'info_loyalty',
|
||||
'loyalty_vip_buy',
|
||||
'collectibles',
|
||||
'petcustomization',
|
||||
'frontpage_featured',
|
||||
'builders_club_frontpage',
|
||||
'builders_club_addons',
|
||||
'builders_club_loyalty'
|
||||
) NOT NULL DEFAULT 'default_3x3';
|
||||
|
||||
@@ -2,6 +2,8 @@ UPDATE `items_base` SET `interaction_type` = 'wf_cnd_time_more_than' WHERE `publ
|
||||
UPDATE `items_base` SET `interaction_type` = 'wf_cnd_time_less_than' WHERE `public_name` = 'wf_cnd_time_less_than';
|
||||
UPDATE `items_base` SET `interaction_type` = 'wf_act_give_reward' WHERE `public_name` = 'wf_act_give_reward';
|
||||
UPDATE `items_base` SET `interaction_type` = 'wf_act_call_stacks' WHERE `public_name` = 'wf_act_call_stacks';
|
||||
UPDATE `items_base` SET `interaction_type` = 'wf_act_neg_call_stack' WHERE `public_name` = 'wf_act_neg_call_stack';
|
||||
UPDATE `items_base` SET `interaction_type` = 'wf_act_neg_call_stacks' WHERE `public_name` = 'wf_act_neg_call_stacks';
|
||||
UPDATE `items_base` SET `interaction_type` = 'default' WHERE `public_name` = 'wf_maze';
|
||||
UPDATE `items_base` SET `interaction_type` = 'wf_act_give_score_tm' WHERE `public_name` = 'wf_act_give_score_tm';
|
||||
UPDATE `items_base` SET `interaction_type` = 'wf_act_move_to_dir' WHERE `public_name` = 'wf_act_move_to_dir';
|
||||
@@ -111,6 +113,7 @@ UPDATE `items_base` SET `interaction_type` = 'wf_act_furni_to_furni' WHERE `publ
|
||||
UPDATE `items_base` SET `interaction_type` = 'wf_act_furni_to_user' WHERE `public_name` = 'wf_act_furni_to_user';
|
||||
UPDATE `items_base` SET `interaction_type` = 'wf_act_rel_mov' WHERE `public_name` = 'wf_act_rel_mov';
|
||||
UPDATE `items_base` SET `interaction_type` = 'wf_act_send_signal' WHERE `public_name` = 'wf_act_send_signal';
|
||||
UPDATE `items_base` SET `interaction_type` = 'wf_act_neg_send_signal' WHERE `public_name` = 'wf_act_neg_send_signal';
|
||||
UPDATE `items_base` SET `interaction_type` = 'wf_act_set_altitude' WHERE `public_name` = 'wf_act_set_altitude';
|
||||
UPDATE `items_base` SET `interaction_type` = 'wf_act_unfreeze' WHERE `public_name` = 'wf_act_unfreeze';
|
||||
UPDATE `items_base` SET `interaction_type` = 'antenna' WHERE `public_name` = 'wf_antenna1';
|
||||
|
||||
@@ -1530,7 +1530,7 @@ CREATE TABLE `catalog_club_offers` (
|
||||
`credits` int(0) NOT NULL DEFAULT 10,
|
||||
`points` int(0) NOT NULL DEFAULT 0,
|
||||
`points_type` int(0) NOT NULL DEFAULT 0,
|
||||
`type` enum('HC','VIP') CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL DEFAULT 'HC',
|
||||
`type` enum('HC','VIP','BUILDERS_CLUB','BUILDERS_CLUB_ADDON') CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL DEFAULT 'HC',
|
||||
`deal` enum('0','1') CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL DEFAULT '0',
|
||||
`giftable` enum('1','0') CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL DEFAULT '0',
|
||||
PRIMARY KEY (`id`) USING BTREE
|
||||
@@ -13499,7 +13499,7 @@ CREATE TABLE `catalog_pages_bc` (
|
||||
`id` int(0) NOT NULL AUTO_INCREMENT,
|
||||
`parent_id` int(0) NOT NULL DEFAULT -1,
|
||||
`caption` varchar(128) CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL,
|
||||
`page_layout` enum('default_3x3','club_buy','club_gift','frontpage','spaces','recycler','recycler_info','recycler_prizes','trophies','plasto','marketplace','marketplace_own_items','spaces_new','soundmachine','guilds','guild_furni','info_duckets','info_rentables','info_pets','roomads','single_bundle','sold_ltd_items','badge_display','bots','pets','pets2','pets3','productpage1','room_bundle','recent_purchases','default_3x3_color_grouping','guild_forum','vip_buy','info_loyalty','loyalty_vip_buy','collectibles','petcustomization','frontpage_featured') CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL DEFAULT 'default_3x3',
|
||||
`page_layout` enum('default_3x3','club_buy','club_gift','frontpage','spaces','recycler','recycler_info','recycler_prizes','trophies','plasto','marketplace','marketplace_own_items','spaces_new','soundmachine','guilds','guild_furni','info_duckets','info_rentables','info_pets','roomads','single_bundle','sold_ltd_items','badge_display','bots','pets','pets2','pets3','productpage1','room_bundle','recent_purchases','default_3x3_color_grouping','guild_forum','vip_buy','info_loyalty','loyalty_vip_buy','collectibles','petcustomization','frontpage_featured','builders_club_frontpage','builders_club_addons','builders_club_loyalty') CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL DEFAULT 'default_3x3',
|
||||
`icon_color` int(0) NOT NULL DEFAULT 1,
|
||||
`icon_image` int(0) NOT NULL DEFAULT 1,
|
||||
`order_num` int(0) NOT NULL DEFAULT 1,
|
||||
@@ -30209,6 +30209,7 @@ CREATE TABLE `users_settings` (
|
||||
`ui_flags` int(0) NOT NULL DEFAULT 1,
|
||||
`has_gotten_default_saved_searches` tinyint(1) NOT NULL DEFAULT 0,
|
||||
`hc_gifts_claimed` int(0) NULL DEFAULT 0,
|
||||
`builders_club_bonus_furni` int(0) NOT NULL DEFAULT 0,
|
||||
`last_hc_payday` int(0) NULL DEFAULT 0,
|
||||
`max_rooms` int(0) NULL DEFAULT 50,
|
||||
`max_friends` int(0) NULL DEFAULT 300,
|
||||
@@ -30223,7 +30224,7 @@ CREATE TABLE `users_settings` (
|
||||
-- ----------------------------
|
||||
-- Records of users_settings
|
||||
-- ----------------------------
|
||||
INSERT INTO `users_settings` VALUES (1, 1, 0, 0, 3, 3, 0, 0, 0, '0', '1', '0', 0, 0, 0, 0, 0, 0, 0, '0', '0', '0', 100, 100, 100, '0', '0', 0, 0, 0, 'Arcturus Emulator;', 0, 0, 0, 0, 0, '0', -1, -1, '0', '0', '0', 0, '0', '0', 0, 1, 1, 0, 0, 50, 300);
|
||||
INSERT INTO `users_settings` VALUES (1, 1, 0, 0, 3, 3, 0, 0, 0, '0', '1', '0', 0, 0, 0, 0, 0, 0, 0, '0', '0', '0', 100, 100, 100, '0', '0', 0, 0, 0, 'Arcturus Emulator;', 0, 0, 0, 0, 0, '0', -1, -1, '0', '0', '0', 0, '0', '0', 0, 1, 1, 0, 0, 0, 50, 300);
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for users_subscriptions
|
||||
@@ -30449,3 +30450,50 @@ INSERT INTO `youtube_playlists` VALUES (6587, 'PL4YfV2mXS8WXOkxFly7YsGL8cKtqp873
|
||||
INSERT INTO `youtube_playlists` VALUES (6587, 'PL80F08DAE1B614BA9', 0);
|
||||
|
||||
SET FOREIGN_KEY_CHECKS = 1;
|
||||
ALTER TABLE `catalog_pages`
|
||||
MODIFY COLUMN `page_layout` ENUM(
|
||||
'default_3x3',
|
||||
'club_buy',
|
||||
'club_gift',
|
||||
'frontpage',
|
||||
'spaces',
|
||||
'recycler',
|
||||
'recycler_info',
|
||||
'recycler_prizes',
|
||||
'trophies',
|
||||
'plasto',
|
||||
'marketplace',
|
||||
'marketplace_own_items',
|
||||
'spaces_new',
|
||||
'soundmachine',
|
||||
'guilds',
|
||||
'guild_furni',
|
||||
'info_duckets',
|
||||
'info_rentables',
|
||||
'info_pets',
|
||||
'roomads',
|
||||
'single_bundle',
|
||||
'sold_ltd_items',
|
||||
'badge_display',
|
||||
'bots',
|
||||
'pets',
|
||||
'pets2',
|
||||
'pets3',
|
||||
'productpage1',
|
||||
'room_bundle',
|
||||
'recent_purchases',
|
||||
'default_3x3_color_grouping',
|
||||
'guild_forum',
|
||||
'vip_buy',
|
||||
'info_loyalty',
|
||||
'loyalty_vip_buy',
|
||||
'collectibles',
|
||||
'petcustomization',
|
||||
'frontpage_featured',
|
||||
'builders_club_frontpage',
|
||||
'builders_club_addons',
|
||||
'builders_club_loyalty'
|
||||
) CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL DEFAULT 'default_3x3';
|
||||
|
||||
ALTER TABLE `catalog_pages`
|
||||
ADD COLUMN `catalog_mode` ENUM('NORMAL','BUILDER','BOTH') CHARACTER SET latin1 COLLATE latin1_swedish_ci NOT NULL DEFAULT 'NORMAL' AFTER `club_only`;
|
||||
|
||||
+3
-3
@@ -10,8 +10,8 @@
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<maven.compiler.source>21</maven.compiler.source>
|
||||
<maven.compiler.target>21</maven.compiler.target>
|
||||
<maven.compiler.source>25</maven.compiler.source>
|
||||
<maven.compiler.target>25</maven.compiler.target>
|
||||
</properties>
|
||||
|
||||
<build>
|
||||
@@ -19,7 +19,7 @@
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.13.0</version>
|
||||
<version>3.15.0</version>
|
||||
<configuration>
|
||||
<source>19</source>
|
||||
<target>19</target>
|
||||
|
||||
@@ -17,14 +17,18 @@ import java.util.Properties;
|
||||
public class ConfigurationManager {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(ConfigurationManager.class);
|
||||
private static final String EMULATOR_SETTINGS_TABLE = "emulator_settings";
|
||||
private static final String WIRED_SETTINGS_TABLE = "wired_emulator_settings";
|
||||
|
||||
private final Properties properties;
|
||||
private final Properties wiredProperties;
|
||||
private final String configurationPath;
|
||||
public boolean loaded = false;
|
||||
public boolean isLoading = false;
|
||||
|
||||
public ConfigurationManager(String configurationPath) {
|
||||
this.properties = new Properties();
|
||||
this.wiredProperties = new Properties();
|
||||
this.configurationPath = configurationPath;
|
||||
this.reload();
|
||||
}
|
||||
@@ -32,6 +36,7 @@ public class ConfigurationManager {
|
||||
public void reload() {
|
||||
this.isLoading = true;
|
||||
this.properties.clear();
|
||||
this.wiredProperties.clear();
|
||||
|
||||
InputStream input = null;
|
||||
|
||||
@@ -116,31 +121,15 @@ public class ConfigurationManager {
|
||||
LOGGER.info("Loading configuration from database...");
|
||||
|
||||
long millis = System.currentTimeMillis();
|
||||
try (Connection connection = Emulator.getDatabase().getDataSource().getConnection(); Statement statement = connection.createStatement()) {
|
||||
if (statement.execute("SELECT * FROM emulator_settings")) {
|
||||
try (ResultSet set = statement.getResultSet()) {
|
||||
while (set.next()) {
|
||||
this.properties.put(set.getString("key"), set.getString("value"));
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
LOGGER.error("Caught SQL exception", e);
|
||||
}
|
||||
this.loadSettingsTable(EMULATOR_SETTINGS_TABLE, this.properties, false);
|
||||
this.loadSettingsTable(WIRED_SETTINGS_TABLE, this.wiredProperties, true);
|
||||
|
||||
LOGGER.info("Configuration -> loaded! ({} MS)", System.currentTimeMillis() - millis);
|
||||
}
|
||||
|
||||
public void saveToDatabase() {
|
||||
try (Connection connection = Emulator.getDatabase().getDataSource().getConnection(); PreparedStatement statement = connection.prepareStatement("UPDATE emulator_settings SET `value` = ? WHERE `key` = ? LIMIT 1")) {
|
||||
for (Map.Entry<Object, Object> entry : this.properties.entrySet()) {
|
||||
statement.setString(1, entry.getValue().toString());
|
||||
statement.setString(2, entry.getKey().toString());
|
||||
statement.executeUpdate();
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
LOGGER.error("Caught SQL exception", e);
|
||||
}
|
||||
this.saveSettingsTable(EMULATOR_SETTINGS_TABLE, this.properties);
|
||||
this.saveSettingsTable(WIRED_SETTINGS_TABLE, this.wiredProperties);
|
||||
}
|
||||
|
||||
|
||||
@@ -153,10 +142,21 @@ public class ConfigurationManager {
|
||||
if (this.isLoading)
|
||||
return defaultValue;
|
||||
|
||||
if (!this.properties.containsKey(key)) {
|
||||
Properties targetProperties = this.resolveProperties(key);
|
||||
|
||||
if (targetProperties.containsKey(key)) {
|
||||
return targetProperties.getProperty(key, defaultValue);
|
||||
}
|
||||
|
||||
if (this.isWiredSettingKey(key) && this.properties.containsKey(key)) {
|
||||
return this.properties.getProperty(key, defaultValue);
|
||||
}
|
||||
|
||||
if (!targetProperties.containsKey(key)) {
|
||||
LOGGER.error("Config key not found {}", key);
|
||||
}
|
||||
return this.properties.getProperty(key, defaultValue);
|
||||
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
public boolean getBoolean(String key) {
|
||||
@@ -209,21 +209,91 @@ public class ConfigurationManager {
|
||||
}
|
||||
|
||||
public void update(String key, String value) {
|
||||
this.properties.setProperty(key, value);
|
||||
this.resolveProperties(key).setProperty(key, value);
|
||||
}
|
||||
|
||||
public void register(String key, String value) {
|
||||
if (this.properties.getProperty(key, null) != null)
|
||||
this.register(key, value, "");
|
||||
}
|
||||
|
||||
public void register(String key, String value, String comment) {
|
||||
Properties targetProperties = this.resolveProperties(key);
|
||||
|
||||
if (targetProperties.getProperty(key, null) != null)
|
||||
return;
|
||||
|
||||
try (Connection connection = Emulator.getDatabase().getDataSource().getConnection(); PreparedStatement statement = connection.prepareStatement("INSERT INTO emulator_settings VALUES (?, ?)")) {
|
||||
statement.setString(1, key);
|
||||
statement.setString(2, value);
|
||||
statement.execute();
|
||||
} catch (SQLException e) {
|
||||
LOGGER.error("Caught SQL exception", e);
|
||||
}
|
||||
|
||||
this.insertSetting(key, value, comment);
|
||||
this.update(key, value);
|
||||
}
|
||||
|
||||
private void loadSettingsTable(String tableName, Properties targetProperties, boolean optional) {
|
||||
try (Connection connection = Emulator.getDatabase().getDataSource().getConnection();
|
||||
Statement statement = connection.createStatement()) {
|
||||
if (statement.execute("SELECT * FROM " + tableName)) {
|
||||
try (ResultSet set = statement.getResultSet()) {
|
||||
while (set.next()) {
|
||||
targetProperties.put(set.getString("key"), set.getString("value"));
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
if (optional) {
|
||||
LOGGER.warn("Skipping optional config table {}: {}", tableName, e.getMessage());
|
||||
} else {
|
||||
LOGGER.error("Caught SQL exception", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void saveSettingsTable(String tableName, Properties sourceProperties) {
|
||||
String sql = "UPDATE " + tableName + " SET `value` = ? WHERE `key` = ? LIMIT 1";
|
||||
|
||||
try (Connection connection = Emulator.getDatabase().getDataSource().getConnection();
|
||||
PreparedStatement statement = connection.prepareStatement(sql)) {
|
||||
for (Map.Entry<Object, Object> entry : sourceProperties.entrySet()) {
|
||||
statement.setString(1, entry.getValue().toString());
|
||||
statement.setString(2, entry.getKey().toString());
|
||||
statement.executeUpdate();
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
if (WIRED_SETTINGS_TABLE.equals(tableName)) {
|
||||
LOGGER.warn("Skipping wired config save for table {}: {}", tableName, e.getMessage());
|
||||
} else {
|
||||
LOGGER.error("Caught SQL exception", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void insertSetting(String key, String value, String comment) {
|
||||
String tableName = this.isWiredSettingKey(key) ? WIRED_SETTINGS_TABLE : EMULATOR_SETTINGS_TABLE;
|
||||
String sql = this.isWiredSettingKey(key)
|
||||
? "INSERT INTO " + tableName + " (`key`, `value`, `comment`) VALUES (?, ?, ?)"
|
||||
: "INSERT INTO " + tableName + " (`key`, `value`) VALUES (?, ?)";
|
||||
|
||||
try (Connection connection = Emulator.getDatabase().getDataSource().getConnection();
|
||||
PreparedStatement statement = connection.prepareStatement(sql)) {
|
||||
statement.setString(1, key);
|
||||
statement.setString(2, value);
|
||||
|
||||
if (this.isWiredSettingKey(key)) {
|
||||
statement.setString(3, comment == null ? "" : comment);
|
||||
}
|
||||
|
||||
statement.execute();
|
||||
} catch (SQLException e) {
|
||||
if (this.isWiredSettingKey(key)) {
|
||||
LOGGER.warn("Unable to insert wired setting {} into {}: {}", key, tableName, e.getMessage());
|
||||
} else {
|
||||
LOGGER.error("Caught SQL exception", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Properties resolveProperties(String key) {
|
||||
return this.isWiredSettingKey(key) ? this.wiredProperties : this.properties;
|
||||
}
|
||||
|
||||
private boolean isWiredSettingKey(String key) {
|
||||
return key != null && (key.startsWith("wired.") || key.startsWith("hotel.wired."));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -387,4 +387,4 @@ public class AchievementManager {
|
||||
public TalentTrackLevel getTalentTrackLevel(TalentTrackType type, int level) {
|
||||
return this.talentTrackLevels.get(type).get(level);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -188,6 +188,7 @@ public class CatalogManager {
|
||||
public static int PURCHASE_COOLDOWN = 1;
|
||||
public static boolean SORT_USING_ORDERNUM = false;
|
||||
public final TIntObjectMap<CatalogPage> catalogPages;
|
||||
public final TIntObjectMap<CatalogPage> buildersClubCatalogPages;
|
||||
public final TIntObjectMap<CatalogFeaturedPage> catalogFeaturedPages;
|
||||
public final THashMap<Integer, THashSet<Item>> prizes;
|
||||
public final THashMap<Integer, Integer> giftWrappers;
|
||||
@@ -197,6 +198,7 @@ public class CatalogManager {
|
||||
public final THashMap<Integer, TargetOffer> targetOffers;
|
||||
public final THashMap<Integer, ClothItem> clothing;
|
||||
public final TIntIntHashMap offerDefs;
|
||||
public final TIntIntHashMap buildersClubOfferDefs;
|
||||
public final Item ecotronItem;
|
||||
public final THashMap<Integer, CatalogLimitedConfiguration> limitedNumbers;
|
||||
private final List<Voucher> vouchers;
|
||||
@@ -204,6 +206,7 @@ public class CatalogManager {
|
||||
public CatalogManager() {
|
||||
long millis = System.currentTimeMillis();
|
||||
this.catalogPages = TCollections.synchronizedMap(new TIntObjectHashMap<>());
|
||||
this.buildersClubCatalogPages = TCollections.synchronizedMap(new TIntObjectHashMap<>());
|
||||
this.catalogFeaturedPages = new TIntObjectHashMap<>();
|
||||
this.prizes = new THashMap<>();
|
||||
this.giftWrappers = new THashMap<>();
|
||||
@@ -213,6 +216,7 @@ public class CatalogManager {
|
||||
this.targetOffers = new THashMap<>();
|
||||
this.clothing = new THashMap<>();
|
||||
this.offerDefs = new TIntIntHashMap();
|
||||
this.buildersClubOfferDefs = new TIntIntHashMap();
|
||||
this.vouchers = new ArrayList<>();
|
||||
this.limitedNumbers = new THashMap<>();
|
||||
|
||||
@@ -229,8 +233,10 @@ public class CatalogManager {
|
||||
|
||||
this.loadLimitedNumbers();
|
||||
this.loadCatalogPages();
|
||||
this.loadBuildersClubCatalogPages();
|
||||
this.loadCatalogFeaturedPages();
|
||||
this.loadCatalogItems();
|
||||
this.loadBuildersClubCatalogItems();
|
||||
this.loadClubOffers();
|
||||
this.loadTargetOffers();
|
||||
this.loadVouchers();
|
||||
@@ -315,6 +321,57 @@ public class CatalogManager {
|
||||
LOGGER.info("Loaded {} Catalog Pages!", this.catalogPages.size());
|
||||
}
|
||||
|
||||
private synchronized void loadBuildersClubCatalogPages() {
|
||||
this.buildersClubCatalogPages.clear();
|
||||
|
||||
final THashMap<Integer, CatalogPage> pages = new THashMap<>();
|
||||
pages.put(-1, new CatalogRootLayout());
|
||||
|
||||
String query = "SELECT id, parent_id, caption, caption AS caption_save, page_layout, icon_color, icon_image, 1 AS min_rank, order_num, visible, enabled, '0' AS club_only, 'BUILDERS_CLUB' AS catalog_mode, page_headline, page_teaser, page_special, page_text1, page_text2, page_text_details, page_text_teaser, '' AS includes FROM catalog_pages_bc ORDER BY parent_id, id";
|
||||
|
||||
try (Connection connection = Emulator.getDatabase().getDataSource().getConnection();
|
||||
PreparedStatement statement = connection.prepareStatement(query)) {
|
||||
try (ResultSet set = statement.executeQuery()) {
|
||||
while (set.next()) {
|
||||
Class<? extends CatalogPage> pageClazz = pageDefinitions.get(set.getString("page_layout"));
|
||||
|
||||
if (pageClazz == null) {
|
||||
LOGGER.info("Unknown Builders Club Page Layout: {}", set.getString("page_layout"));
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
CatalogPage page = pageClazz.getConstructor(ResultSet.class).newInstance(set);
|
||||
pages.put(page.getId(), page);
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("Failed to load Builders Club layout: {}", set.getString("page_layout"));
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
LOGGER.error("Caught SQL exception", e);
|
||||
}
|
||||
|
||||
pages.forEachValue((object) -> {
|
||||
CatalogPage page = pages.get(object.parentId);
|
||||
|
||||
if (page != null) {
|
||||
if (page.id != object.id) {
|
||||
page.addChildPage(object);
|
||||
}
|
||||
} else {
|
||||
if (object.parentId != -2) {
|
||||
LOGGER.info("Builders Club parent page not found for {} (ID: {}, parent_id: {})", object.getPageName(), object.id, object.parentId);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
this.buildersClubCatalogPages.putAll(pages);
|
||||
|
||||
LOGGER.info("Loaded {} Builders Club Catalog Pages!", this.buildersClubCatalogPages.size());
|
||||
}
|
||||
|
||||
|
||||
private synchronized void loadCatalogFeaturedPages() {
|
||||
this.catalogFeaturedPages.clear();
|
||||
@@ -391,6 +448,53 @@ public class CatalogManager {
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized void loadBuildersClubCatalogItems() {
|
||||
this.buildersClubOfferDefs.clear();
|
||||
|
||||
String query = "SELECT id, item_ids, page_id, catalog_name, 0 AS cost_credits, 0 AS cost_points, 0 AS points_type, 1 AS amount, 0 AS limited_stack, 0 AS limited_sells, extradata, '0' AS club_only, '1' AS have_offer, id AS offer_id, order_number FROM catalog_items_bc";
|
||||
|
||||
try (Connection connection = Emulator.getDatabase().getDataSource().getConnection();
|
||||
Statement statement = connection.createStatement();
|
||||
ResultSet set = statement.executeQuery(query)) {
|
||||
CatalogItem item;
|
||||
|
||||
while (set.next()) {
|
||||
if (set.getString("item_ids").equals("0")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
CatalogPage page = this.buildersClubCatalogPages.get(set.getInt("page_id"));
|
||||
|
||||
if (page == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
item = page.getCatalogItem(set.getInt("id"));
|
||||
|
||||
if (item == null) {
|
||||
item = new CatalogItem(set);
|
||||
page.addItem(item);
|
||||
page.addOfferId(item.getOfferId());
|
||||
this.buildersClubOfferDefs.put(item.getOfferId(), item.getId());
|
||||
} else {
|
||||
item.update(set);
|
||||
}
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
LOGGER.error("Caught SQL exception", e);
|
||||
}
|
||||
|
||||
for (CatalogPage page : this.buildersClubCatalogPages.valueCollection()) {
|
||||
for (Integer id : page.getIncluded()) {
|
||||
CatalogPage includedPage = this.buildersClubCatalogPages.get(id);
|
||||
|
||||
if (includedPage != null) {
|
||||
page.getCatalogItems().putAll(includedPage.getCatalogItems());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void loadClubOffers() {
|
||||
this.clubOffers.clear();
|
||||
|
||||
@@ -585,6 +689,10 @@ public class CatalogManager {
|
||||
return this.catalogPages.get(pageId);
|
||||
}
|
||||
|
||||
public CatalogPage getCatalogPage(int pageId, CatalogPageType pageType) {
|
||||
return this.getCatalogPagesMap(pageType).get(pageId);
|
||||
}
|
||||
|
||||
public CatalogPage getCatalogPage(String captionSafe) {
|
||||
return this.catalogPages.valueCollection().stream()
|
||||
.filter(p -> p != null && p.getPageName() != null && p.getPageName().equalsIgnoreCase(captionSafe))
|
||||
@@ -603,9 +711,15 @@ public class CatalogManager {
|
||||
}
|
||||
|
||||
public CatalogItem getCatalogItem(int id) {
|
||||
return this.getCatalogItem(id, CatalogPageType.NORMAL);
|
||||
}
|
||||
|
||||
public CatalogItem getCatalogItem(int id, CatalogPageType pageType) {
|
||||
final CatalogItem[] item = {null};
|
||||
synchronized (this.catalogPages) {
|
||||
this.catalogPages.forEachValue(new TObjectProcedure<CatalogPage>() {
|
||||
final TIntObjectMap<CatalogPage> pagesMap = this.getCatalogPagesMap(pageType);
|
||||
|
||||
synchronized (pagesMap) {
|
||||
pagesMap.forEachValue(new TObjectProcedure<CatalogPage>() {
|
||||
@Override
|
||||
public boolean execute(CatalogPage object) {
|
||||
item[0] = object.getCatalogItem(id);
|
||||
@@ -620,17 +734,28 @@ public class CatalogManager {
|
||||
|
||||
|
||||
public List<CatalogPage> getCatalogPages(int parentId, final Habbo habbo) {
|
||||
final List<CatalogPage> pages = new ArrayList<>();
|
||||
return this.getCatalogPages(parentId, habbo, CatalogPageType.NORMAL);
|
||||
}
|
||||
|
||||
this.catalogPages.get(parentId).childPages.forEachValue(new TObjectProcedure<CatalogPage>() {
|
||||
public List<CatalogPage> getCatalogPages(int parentId, final Habbo habbo, final CatalogPageType pageType) {
|
||||
final List<CatalogPage> pages = new ArrayList<>();
|
||||
final TIntObjectMap<CatalogPage> pagesMap = this.getCatalogPagesMap(pageType);
|
||||
CatalogPage parentPage = pagesMap.get(parentId);
|
||||
|
||||
if (parentPage == null) {
|
||||
return pages;
|
||||
}
|
||||
|
||||
parentPage.childPages.forEachValue(new TObjectProcedure<CatalogPage>() {
|
||||
@Override
|
||||
public boolean execute(CatalogPage object) {
|
||||
|
||||
boolean isVisiblePage = object.visible;
|
||||
boolean hasRightRank = object.getRank() <= habbo.getHabboInfo().getRank().getId();
|
||||
boolean clubRightsOkay = !object.isClubOnly() || habbo.getHabboInfo().getHabboStats().hasActiveClub();
|
||||
boolean pageTypeMatches = (pageType == CatalogPageType.BUILDER) || object.getCatalogPageType().matches(pageType);
|
||||
|
||||
if (isVisiblePage && hasRightRank && clubRightsOkay) {
|
||||
if (isVisiblePage && hasRightRank && clubRightsOkay && pageTypeMatches) {
|
||||
pages.add(object);
|
||||
}
|
||||
return true;
|
||||
@@ -704,22 +829,42 @@ public class CatalogManager {
|
||||
}
|
||||
|
||||
|
||||
public CatalogPage createCatalogPage(String caption, String captionSave, int roomId, int icon, CatalogPageLayouts layout, int minRank, int parentId) {
|
||||
public CatalogPage createCatalogPage(String caption, String captionSave, int roomId, int icon, CatalogPageLayouts layout, int minRank, int parentId, CatalogPageType pageType, CatalogPageType catalogMode) {
|
||||
CatalogPage catalogPage = null;
|
||||
try (Connection connection = Emulator.getDatabase().getDataSource().getConnection(); PreparedStatement statement = connection.prepareStatement("INSERT INTO catalog_pages (parent_id, caption, caption_save, icon_image, visible, enabled, min_rank, page_layout, room_id) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)", Statement.RETURN_GENERATED_KEYS)) {
|
||||
boolean buildersClubPage = (pageType == CatalogPageType.BUILDER);
|
||||
String insertQuery = buildersClubPage
|
||||
? "INSERT INTO catalog_pages_bc (parent_id, caption, page_layout, icon_color, icon_image, order_num, visible, enabled) VALUES (?, ?, ?, ?, ?, ?, ?, ?)"
|
||||
: "INSERT INTO catalog_pages (parent_id, caption, caption_save, icon_image, visible, enabled, min_rank, page_layout, room_id, catalog_mode) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
|
||||
String selectQuery = buildersClubPage
|
||||
? "SELECT id, parent_id, caption, caption AS caption_save, page_layout, icon_color, icon_image, 1 AS min_rank, order_num, visible, enabled, '0' AS club_only, 'BUILDERS_CLUB' AS catalog_mode, page_headline, page_teaser, page_special, page_text1, page_text2, page_text_details, page_text_teaser, '' AS includes FROM catalog_pages_bc WHERE id = ?"
|
||||
: "SELECT * FROM catalog_pages WHERE id = ?";
|
||||
|
||||
try (Connection connection = Emulator.getDatabase().getDataSource().getConnection();
|
||||
PreparedStatement statement = connection.prepareStatement(insertQuery, Statement.RETURN_GENERATED_KEYS)) {
|
||||
statement.setInt(1, parentId);
|
||||
statement.setString(2, caption);
|
||||
statement.setString(3, captionSave);
|
||||
statement.setInt(4, icon);
|
||||
statement.setString(5, "1");
|
||||
statement.setString(6, "1");
|
||||
statement.setInt(7, minRank);
|
||||
statement.setString(8, layout.name());
|
||||
statement.setInt(9, roomId);
|
||||
|
||||
if (buildersClubPage) {
|
||||
statement.setString(3, layout.name());
|
||||
statement.setInt(4, 1);
|
||||
statement.setInt(5, icon);
|
||||
statement.setInt(6, 1);
|
||||
statement.setString(7, "1");
|
||||
statement.setString(8, "1");
|
||||
} else {
|
||||
statement.setString(3, captionSave);
|
||||
statement.setInt(4, icon);
|
||||
statement.setString(5, "1");
|
||||
statement.setString(6, "1");
|
||||
statement.setInt(7, minRank);
|
||||
statement.setString(8, layout.name());
|
||||
statement.setInt(9, roomId);
|
||||
statement.setString(10, catalogMode.name());
|
||||
}
|
||||
statement.execute();
|
||||
try (ResultSet set = statement.getGeneratedKeys()) {
|
||||
if (set.next()) {
|
||||
try (PreparedStatement stmt = connection.prepareStatement("SELECT * FROM catalog_pages WHERE id = ?")) {
|
||||
try (PreparedStatement stmt = connection.prepareStatement(selectQuery)) {
|
||||
stmt.setInt(1, set.getInt(1));
|
||||
try (ResultSet page = stmt.executeQuery()) {
|
||||
if (page.next()) {
|
||||
@@ -744,7 +889,7 @@ public class CatalogManager {
|
||||
}
|
||||
|
||||
if (catalogPage != null) {
|
||||
this.catalogPages.put(catalogPage.getId(), catalogPage);
|
||||
this.getCatalogPagesMap(pageType).put(catalogPage.getId(), catalogPage);
|
||||
}
|
||||
|
||||
return catalogPage;
|
||||
@@ -991,7 +1136,7 @@ public class CatalogManager {
|
||||
if (extradata.length() > Emulator.getConfig().getInt("hotel.trophies.length.max", 300)) {
|
||||
extradata = extradata.substring(0, Emulator.getConfig().getInt("hotel.trophies.length.max", 300));
|
||||
}
|
||||
|
||||
|
||||
extradata = habbo.getClient().getHabbo().getHabboInfo().getUsername() + (char) 9 + Calendar.getInstance().get(Calendar.DAY_OF_MONTH) + "-" + (Calendar.getInstance().get(Calendar.MONTH) + 1) + "-" + Calendar.getInstance().get(Calendar.YEAR) + (char) 9 + Emulator.getGameEnvironment().getWordFilter().filter(extradata.replace(((char) 9) + "", ""), habbo);
|
||||
}
|
||||
|
||||
@@ -1060,7 +1205,7 @@ public class CatalogManager {
|
||||
|
||||
if (badgeFound && item.getBaseItems().size() == 1) {
|
||||
habbo.getClient().sendResponse(new AlertPurchaseFailedComposer(AlertPurchaseFailedComposer.ALREADY_HAVE_BADGE));
|
||||
return;
|
||||
return;
|
||||
}
|
||||
|
||||
UserCatalogItemPurchasedEvent purchasedEvent = new UserCatalogItemPurchasedEvent(habbo, item, itemsList, totalCredits, totalPoints, badges);
|
||||
@@ -1144,14 +1289,23 @@ public class CatalogManager {
|
||||
}
|
||||
|
||||
public List<ClubOffer> getClubOffers() {
|
||||
return this.getClubOffers(ClubOffer.WINDOW_HABBO_CLUB);
|
||||
}
|
||||
|
||||
public TIntObjectMap<CatalogPage> getCatalogPagesMap(CatalogPageType pageType) {
|
||||
return (pageType == CatalogPageType.BUILDER) ? this.buildersClubCatalogPages : this.catalogPages;
|
||||
}
|
||||
|
||||
public List<ClubOffer> getClubOffers(int windowId) {
|
||||
List<ClubOffer> offers = new ArrayList<>();
|
||||
|
||||
for (Map.Entry<Integer, ClubOffer> entry : this.clubOffers.entrySet()) {
|
||||
if (!entry.getValue().isDeal()) {
|
||||
if (!entry.getValue().isDeal() && entry.getValue().belongsToWindow(windowId)) {
|
||||
offers.add(entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
offers.sort(Comparator.comparingInt(ClubOffer::getId));
|
||||
return offers;
|
||||
}
|
||||
|
||||
|
||||
@@ -32,6 +32,7 @@ public abstract class CatalogPage implements Comparable<CatalogPage>, ISerialize
|
||||
protected boolean visible;
|
||||
protected boolean enabled;
|
||||
protected boolean clubOnly;
|
||||
protected CatalogPageType catalogPageType = CatalogPageType.NORMAL;
|
||||
protected String layout;
|
||||
protected String headerImage;
|
||||
protected String teaserImage;
|
||||
@@ -59,6 +60,11 @@ public abstract class CatalogPage implements Comparable<CatalogPage>, ISerialize
|
||||
this.visible = set.getBoolean("visible");
|
||||
this.enabled = set.getBoolean("enabled");
|
||||
this.clubOnly = set.getBoolean("club_only");
|
||||
try {
|
||||
this.catalogPageType = CatalogPageType.fromString(set.getString("catalog_mode"));
|
||||
} catch (SQLException ignored) {
|
||||
this.catalogPageType = CatalogPageType.NORMAL;
|
||||
}
|
||||
this.layout = set.getString("page_layout");
|
||||
this.headerImage = set.getString("page_headline");
|
||||
this.teaserImage = set.getString("page_teaser");
|
||||
@@ -68,8 +74,9 @@ public abstract class CatalogPage implements Comparable<CatalogPage>, ISerialize
|
||||
this.textDetails = set.getString("page_text_details");
|
||||
this.textTeaser = set.getString("page_text_teaser");
|
||||
|
||||
if (!set.getString("includes").isEmpty()) {
|
||||
for (String id : set.getString("includes").split(";")) {
|
||||
String includes = set.getString("includes");
|
||||
if (includes != null && !includes.isEmpty()) {
|
||||
for (String id : includes.split(";")) {
|
||||
try {
|
||||
this.included.add(Integer.valueOf(id));
|
||||
} catch (Exception e) {
|
||||
@@ -128,6 +135,10 @@ public abstract class CatalogPage implements Comparable<CatalogPage>, ISerialize
|
||||
return this.clubOnly;
|
||||
}
|
||||
|
||||
public CatalogPageType getCatalogPageType() {
|
||||
return this.catalogPageType;
|
||||
}
|
||||
|
||||
public String getLayout() {
|
||||
return this.layout;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,33 @@ public enum CatalogPageType {
|
||||
|
||||
NORMAL,
|
||||
|
||||
BUILDER,
|
||||
|
||||
BUILDER
|
||||
BOTH;
|
||||
|
||||
public static CatalogPageType fromString(String value) {
|
||||
if (value == null || value.isEmpty()) {
|
||||
return NORMAL;
|
||||
}
|
||||
|
||||
switch (value.trim().toUpperCase()) {
|
||||
case "BUILDERS_CLUB":
|
||||
case "BUILDER":
|
||||
case "BC":
|
||||
return BUILDER;
|
||||
case "BOTH":
|
||||
return BOTH;
|
||||
case "NORMAL":
|
||||
default:
|
||||
return NORMAL;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean matches(CatalogPageType requestedType) {
|
||||
if (this == BOTH || requestedType == BOTH) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return this == requestedType;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,6 +10,30 @@ import java.util.Calendar;
|
||||
import java.util.TimeZone;
|
||||
|
||||
public class ClubOffer implements ISerialize {
|
||||
public static final int WINDOW_HABBO_CLUB = 1;
|
||||
public static final int WINDOW_BUILDERS_CLUB = 2;
|
||||
public static final int WINDOW_BUILDERS_CLUB_ADDONS = 3;
|
||||
|
||||
public enum OfferType {
|
||||
HC,
|
||||
VIP,
|
||||
BUILDERS_CLUB,
|
||||
BUILDERS_CLUB_ADDON;
|
||||
|
||||
public static OfferType fromDatabase(String value) {
|
||||
if (value == null) {
|
||||
return HC;
|
||||
}
|
||||
|
||||
for (OfferType type : OfferType.values()) {
|
||||
if (type.name().equalsIgnoreCase(value)) {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
return HC;
|
||||
}
|
||||
}
|
||||
|
||||
private final int id;
|
||||
|
||||
@@ -28,12 +52,16 @@ public class ClubOffer implements ISerialize {
|
||||
|
||||
private final int pointsType;
|
||||
|
||||
private final OfferType type;
|
||||
|
||||
|
||||
private final boolean vip;
|
||||
|
||||
|
||||
private final boolean deal;
|
||||
|
||||
private final boolean giftable;
|
||||
|
||||
public ClubOffer(ResultSet set) throws SQLException {
|
||||
this.id = set.getInt("id");
|
||||
this.name = set.getString("name");
|
||||
@@ -41,8 +69,10 @@ public class ClubOffer implements ISerialize {
|
||||
this.credits = set.getInt("credits");
|
||||
this.points = set.getInt("points");
|
||||
this.pointsType = set.getInt("points_type");
|
||||
this.vip = set.getString("type").equalsIgnoreCase("vip");
|
||||
this.type = OfferType.fromDatabase(set.getString("type"));
|
||||
this.vip = this.type == OfferType.VIP;
|
||||
this.deal = set.getString("deal").equals("1");
|
||||
this.giftable = set.getString("giftable").equals("1");
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
@@ -69,6 +99,10 @@ public class ClubOffer implements ISerialize {
|
||||
return this.pointsType;
|
||||
}
|
||||
|
||||
public OfferType getType() {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
public boolean isVip() {
|
||||
return this.vip;
|
||||
}
|
||||
@@ -77,13 +111,49 @@ public class ClubOffer implements ISerialize {
|
||||
return this.deal;
|
||||
}
|
||||
|
||||
public boolean isGiftable() {
|
||||
return this.giftable;
|
||||
}
|
||||
|
||||
public boolean isBuildersClubSubscription() {
|
||||
return this.type == OfferType.BUILDERS_CLUB;
|
||||
}
|
||||
|
||||
public boolean isBuildersClubAddon() {
|
||||
return this.type == OfferType.BUILDERS_CLUB_ADDON;
|
||||
}
|
||||
|
||||
public boolean isHabboClubOffer() {
|
||||
return this.type == OfferType.HC || this.type == OfferType.VIP;
|
||||
}
|
||||
|
||||
public boolean isSubscriptionOffer() {
|
||||
return !this.isBuildersClubAddon();
|
||||
}
|
||||
|
||||
public int getWindowId() {
|
||||
if (this.isBuildersClubAddon()) {
|
||||
return WINDOW_BUILDERS_CLUB_ADDONS;
|
||||
}
|
||||
|
||||
if (this.isBuildersClubSubscription()) {
|
||||
return WINDOW_BUILDERS_CLUB;
|
||||
}
|
||||
|
||||
return WINDOW_HABBO_CLUB;
|
||||
}
|
||||
|
||||
public boolean belongsToWindow(int windowId) {
|
||||
return this.getWindowId() == windowId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serialize(ServerMessage message) {
|
||||
serialize(message, Emulator.getIntUnixTimestamp());
|
||||
}
|
||||
|
||||
public void serialize(ServerMessage message, int hcExpireTimestamp) {
|
||||
hcExpireTimestamp = Math.max(Emulator.getIntUnixTimestamp(), hcExpireTimestamp);
|
||||
public void serialize(ServerMessage message, int expireTimestamp) {
|
||||
expireTimestamp = Math.max(Emulator.getIntUnixTimestamp(), expireTimestamp);
|
||||
message.appendInt(this.id);
|
||||
message.appendString(this.name);
|
||||
message.appendBoolean(false); //unused
|
||||
@@ -96,27 +166,29 @@ public class ClubOffer implements ISerialize {
|
||||
|
||||
long secondsTotal = seconds;
|
||||
|
||||
int totalYears = (int) Math.floor((int) seconds / (86400.0 * 31 * 12));
|
||||
int totalYears = (int) Math.floor(seconds / (86400.0 * 31 * 12));
|
||||
seconds -= totalYears * (86400 * 31 * 12);
|
||||
|
||||
int totalMonths = (int) Math.floor((int) seconds / (86400.0 * 31));
|
||||
int totalMonths = (int) Math.floor(seconds / (86400.0 * 31));
|
||||
seconds -= totalMonths * (86400 * 31);
|
||||
|
||||
int totalDays = (int) Math.floor((int) seconds / 86400.0);
|
||||
int totalDays = (int) Math.floor(seconds / 86400.0);
|
||||
seconds -= totalDays * 86400L;
|
||||
|
||||
message.appendInt((int) secondsTotal / 86400 / 31);
|
||||
message.appendInt((int) seconds);
|
||||
message.appendBoolean(false); //giftable
|
||||
message.appendInt((int) seconds);
|
||||
message.appendInt(totalMonths);
|
||||
message.appendInt(totalDays);
|
||||
message.appendBoolean(this.giftable);
|
||||
message.appendInt(totalDays);
|
||||
|
||||
hcExpireTimestamp += secondsTotal;
|
||||
if (this.isSubscriptionOffer()) {
|
||||
expireTimestamp += secondsTotal;
|
||||
}
|
||||
|
||||
Calendar cal = Calendar.getInstance();
|
||||
cal.setTimeZone(TimeZone.getTimeZone("UTC"));
|
||||
cal.setTimeInMillis(hcExpireTimestamp * 1000L);
|
||||
cal.setTimeInMillis(expireTimestamp * 1000L);
|
||||
message.appendInt(cal.get(Calendar.YEAR));
|
||||
message.appendInt(cal.get(Calendar.MONTH) + 1);
|
||||
message.appendInt(cal.get(Calendar.DAY_OF_MONTH));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import com.eu.habbo.Emulator;
|
||||
import com.eu.habbo.habbohotel.catalog.CatalogItem;
|
||||
import com.eu.habbo.habbohotel.catalog.CatalogPage;
|
||||
import com.eu.habbo.habbohotel.catalog.CatalogPageLayouts;
|
||||
import com.eu.habbo.habbohotel.catalog.CatalogPageType;
|
||||
import com.eu.habbo.habbohotel.catalog.layouts.RoomBundleLayout;
|
||||
import com.eu.habbo.habbohotel.gameclients.GameClient;
|
||||
import com.eu.habbo.habbohotel.rooms.RoomChatMessageBubbles;
|
||||
@@ -41,7 +42,7 @@ public class RoomBundleCommand extends Command {
|
||||
points = Integer.parseInt(params[3]);
|
||||
pointsType = Integer.parseInt(params[4]);
|
||||
|
||||
CatalogPage page = Emulator.getGameEnvironment().getCatalogManager().createCatalogPage("Room Bundle: " + gameClient.getHabbo().getHabboInfo().getCurrentRoom().getName(), "room_bundle_" + gameClient.getHabbo().getHabboInfo().getCurrentRoom().getId(), gameClient.getHabbo().getHabboInfo().getCurrentRoom().getId(), 0, CatalogPageLayouts.room_bundle, gameClient.getHabbo().getHabboInfo().getRank().getId(), parentId);
|
||||
CatalogPage page = Emulator.getGameEnvironment().getCatalogManager().createCatalogPage("Room Bundle: " + gameClient.getHabbo().getHabboInfo().getCurrentRoom().getName(), "room_bundle_" + gameClient.getHabbo().getHabboInfo().getCurrentRoom().getId(), gameClient.getHabbo().getHabboInfo().getCurrentRoom().getId(), 0, CatalogPageLayouts.room_bundle, gameClient.getHabbo().getHabboInfo().getRank().getId(), parentId, CatalogPageType.NORMAL, CatalogPageType.NORMAL);
|
||||
|
||||
if (page instanceof RoomBundleLayout) {
|
||||
try (Connection connection = Emulator.getDatabase().getDataSource().getConnection(); PreparedStatement statement = connection.prepareStatement("INSERT INTO catalog_items (page_id, item_ids, catalog_name, cost_credits, cost_points, points_type ) VALUES (?, ?, ?, ?, ?, ?)", Statement.RETURN_GENERATED_KEYS)) {
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
package com.eu.habbo.habbohotel.commands;
|
||||
|
||||
import com.eu.habbo.habbohotel.gameclients.GameClient;
|
||||
import com.eu.habbo.habbohotel.permissions.Permission;
|
||||
import com.eu.habbo.habbohotel.rooms.Room;
|
||||
import com.eu.habbo.habbohotel.rooms.RoomChatMessageBubbles;
|
||||
import com.eu.habbo.messages.outgoing.users.InClientLinkComposer;
|
||||
|
||||
public class WiredCommand extends Command {
|
||||
public WiredCommand() {
|
||||
super(Permission.ACC_PLACEFURNI, new String[]{"wired"});
|
||||
super(null, new String[]{"wired"});
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -20,12 +19,8 @@ public class WiredCommand extends Command {
|
||||
return true;
|
||||
}
|
||||
|
||||
boolean hasRights = room.hasRights(gameClient.getHabbo())
|
||||
|| room.isOwner(gameClient.getHabbo())
|
||||
|| gameClient.getHabbo().hasPermission(Permission.ACC_ANYROOMOWNER);
|
||||
|
||||
if (!hasRights) {
|
||||
gameClient.getHabbo().whisper("You need room rights to open the Wired Creator Tools.", RoomChatMessageBubbles.ALERT);
|
||||
if (!room.canInspectWired(gameClient.getHabbo())) {
|
||||
gameClient.sendResponse(new InClientLinkComposer("wired-tools/invalid"));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -91,7 +91,23 @@ public class Item implements ISerialize {
|
||||
this.allowGift = set.getBoolean("allow_gift");
|
||||
this.allowInventoryStack = set.getBoolean("allow_inventory_stack");
|
||||
|
||||
this.interactionType = Emulator.getGameEnvironment().getItemManager().getItemInteraction(set.getString("interaction_type").toLowerCase());
|
||||
String interactionTypeName = set.getString("interaction_type");
|
||||
if (interactionTypeName == null) {
|
||||
interactionTypeName = "default";
|
||||
}
|
||||
|
||||
this.interactionType = Emulator.getGameEnvironment().getItemManager().getItemInteraction(interactionTypeName.toLowerCase());
|
||||
|
||||
if ((this.interactionType != null)
|
||||
&& "default".equalsIgnoreCase(this.interactionType.getName())
|
||||
&& (this.fullName != null)
|
||||
&& this.fullName.toLowerCase().startsWith("wf_")) {
|
||||
ItemInteraction fallbackInteraction = Emulator.getGameEnvironment().getItemManager().getItemInteraction(this.fullName.toLowerCase());
|
||||
|
||||
if ((fallbackInteraction != null) && !"default".equalsIgnoreCase(fallbackInteraction.getName())) {
|
||||
this.interactionType = fallbackInteraction;
|
||||
}
|
||||
}
|
||||
|
||||
this.stateCount = set.getShort("interaction_modes_count");
|
||||
this.effectM = set.getShort("effect_id_male");
|
||||
|
||||
@@ -52,7 +52,10 @@ import com.eu.habbo.habbohotel.items.interactions.wired.effects.*;
|
||||
import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredBlob;
|
||||
import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredExtraAnimationTime;
|
||||
import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredExtraFilterFurni;
|
||||
import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredExtraFilterFurniByVariable;
|
||||
import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredExtraFilterUser;
|
||||
import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredExtraFilterUsersByVariable;
|
||||
import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredExtraFurniVariable;
|
||||
import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredExtraMoveCarryUsers;
|
||||
import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredExtraExecuteInOrder;
|
||||
import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredExtraExecutionLimit;
|
||||
@@ -60,9 +63,18 @@ import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredExtraMovePhys
|
||||
import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredExtraMoveNoAnimation;
|
||||
import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredExtraOrEval;
|
||||
import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredExtraRandom;
|
||||
import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredExtraRoomVariable;
|
||||
import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredExtraTextOutputFurniName;
|
||||
import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredExtraTextInputVariable;
|
||||
import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredExtraTextOutputUsername;
|
||||
import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredExtraTextOutputVariable;
|
||||
import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredExtraContextVariable;
|
||||
import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredExtraUserVariable;
|
||||
import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredExtraVariableEcho;
|
||||
import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredExtraUnseen;
|
||||
import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredExtraVariableReference;
|
||||
import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredExtraVariableLevelUpSystem;
|
||||
import com.eu.habbo.habbohotel.items.interactions.wired.extra.WiredExtraVariableTextConnector;
|
||||
import com.eu.habbo.habbohotel.items.interactions.wired.selector.*;
|
||||
import com.eu.habbo.habbohotel.items.interactions.wired.triggers.*;
|
||||
import com.eu.habbo.habbohotel.users.Habbo;
|
||||
@@ -157,6 +169,7 @@ public class ItemManager {
|
||||
this.interactionsList.add(new ItemInteraction("monsterplant_seed", InteractionMonsterPlantSeed.class));
|
||||
this.interactionsList.add(new ItemInteraction("gift", InteractionGift.class));
|
||||
this.interactionsList.add(new ItemInteraction("stack_helper", InteractionStackHelper.class));
|
||||
this.interactionsList.add(new ItemInteraction("stack_walk_helper", InteractionStackWalkHelper.class));
|
||||
this.interactionsList.add(new ItemInteraction("puzzle_box", InteractionPuzzleBox.class));
|
||||
this.interactionsList.add(new ItemInteraction("hopper", InteractionHopper.class));
|
||||
this.interactionsList.add(new ItemInteraction("costume_hopper", InteractionCostumeHopper.class));
|
||||
@@ -186,6 +199,13 @@ public class ItemManager {
|
||||
this.interactionsList.add(new ItemInteraction("youtube", InteractionYoutubeTV.class));
|
||||
this.interactionsList.add(new ItemInteraction("jukebox", InteractionJukeBox.class));
|
||||
this.interactionsList.add(new ItemInteraction("switch", InteractionSwitch.class));
|
||||
this.interactionsList.add(new ItemInteraction("conf_invis_control", InteractionConfInvisControl.class));
|
||||
this.interactionsList.add(new ItemInteraction("wf_conf_invis_control", InteractionConfInvisControl.class));
|
||||
this.interactionsList.add(new ItemInteraction("wf_conf_area_hide", InteractionAreaHideControl.class));
|
||||
this.interactionsList.add(new ItemInteraction("conf_area_hide", InteractionAreaHideControl.class));
|
||||
this.interactionsList.add(new ItemInteraction("wf_conf_handitem_block", InteractionHanditemBlockControl.class));
|
||||
this.interactionsList.add(new ItemInteraction("wf_conf_queue_speed", InteractionQueueSpeedControl.class));
|
||||
this.interactionsList.add(new ItemInteraction("wf_conf_wired_disable", InteractionWiredDisableControl.class));
|
||||
this.interactionsList.add(new ItemInteraction("switch_remote_control", InteractionSwitchRemoteControl.class));
|
||||
this.interactionsList.add(new ItemInteraction("fx_box", InteractionFXBox.class));
|
||||
this.interactionsList.add(new ItemInteraction("blackhole", InteractionBlackHole.class));
|
||||
@@ -225,6 +245,7 @@ public class ItemManager {
|
||||
this.interactionsList.add(new ItemInteraction("wf_trg_leave_room", WiredTriggerHabboLeavesRoom.class));
|
||||
this.interactionsList.add(new ItemInteraction("wf_trg_says_something", WiredTriggerHabboSaysKeyword.class));
|
||||
this.interactionsList.add(new ItemInteraction("wf_trg_clock_counter", WiredTriggerClockCounter.class));
|
||||
this.interactionsList.add(new ItemInteraction("wf_trg_var_changed", WiredTriggerVariableChanged.class));
|
||||
this.interactionsList.add(new ItemInteraction("wf_trg_periodically", WiredTriggerRepeater.class));
|
||||
this.interactionsList.add(new ItemInteraction("wf_trg_period_short", WiredTriggerRepeaterShort.class));
|
||||
this.interactionsList.add(new ItemInteraction("wf_trg_period_long", WiredTriggerRepeaterLong.class));
|
||||
@@ -260,6 +281,8 @@ public class ItemManager {
|
||||
this.interactionsList.add(new ItemInteraction("wf_act_move_furni_to", WiredEffectMoveFurniTo.class));
|
||||
this.interactionsList.add(new ItemInteraction("wf_act_give_reward", WiredEffectGiveReward.class));
|
||||
this.interactionsList.add(new ItemInteraction("wf_act_call_stacks", WiredEffectTriggerStacks.class));
|
||||
this.interactionsList.add(new ItemInteraction("wf_act_neg_call_stack", WiredEffectNegativeTriggerStacks.class));
|
||||
this.interactionsList.add(new ItemInteraction("wf_act_neg_call_stacks", WiredEffectNegativeTriggerStacks.class));
|
||||
this.interactionsList.add(new ItemInteraction("wf_act_kick_user", WiredEffectKickHabbo.class));
|
||||
this.interactionsList.add(new ItemInteraction("wf_act_mute_triggerer", WiredEffectMuteHabbo.class));
|
||||
this.interactionsList.add(new ItemInteraction("wf_act_bot_teleport", WiredEffectBotTeleport.class));
|
||||
@@ -300,7 +323,13 @@ public class ItemManager {
|
||||
this.interactionsList.add(new ItemInteraction("wf_slc_users_handitem", WiredEffectUsersHandItem.class));
|
||||
this.interactionsList.add(new ItemInteraction("wf_slc_users_onfurni", WiredEffectUsersOnFurni.class));
|
||||
this.interactionsList.add(new ItemInteraction("wf_slc_users_group", WiredEffectUsersGroup.class));
|
||||
this.interactionsList.add(new ItemInteraction("wf_slc_furni_with_var", WiredEffectFurniWithVariable.class));
|
||||
this.interactionsList.add(new ItemInteraction("wf_slc_users_with_var", WiredEffectUsersWithVariable.class));
|
||||
this.interactionsList.add(new ItemInteraction("wf_act_send_signal", WiredEffectSendSignal.class));
|
||||
this.interactionsList.add(new ItemInteraction("wf_act_neg_send_signal", WiredEffectNegativeSendSignal.class));
|
||||
this.interactionsList.add(new ItemInteraction("wf_act_give_var", WiredEffectGiveVariable.class));
|
||||
this.interactionsList.add(new ItemInteraction("wf_act_remove_var", WiredEffectRemoveVariable.class));
|
||||
this.interactionsList.add(new ItemInteraction("wf_act_change_var_val", WiredEffectChangeVariableValue.class));
|
||||
|
||||
this.interactionsList.add(new ItemInteraction("wf_cnd_has_furni_on", WiredConditionFurniHaveFurni.class));
|
||||
this.interactionsList.add(new ItemInteraction("wf_cnd_furnis_hv_avtrs", WiredConditionFurniHaveHabbo.class));
|
||||
@@ -340,6 +369,10 @@ public class ItemManager {
|
||||
this.interactionsList.add(new ItemInteraction("wf_cnd_not_triggerer_match", WiredConditionNotTriggererMatch.class));
|
||||
this.interactionsList.add(new ItemInteraction("wf_cnd_team_has_score", WiredConditionTeamHasScore.class));
|
||||
this.interactionsList.add(new ItemInteraction("wf_cnd_team_has_rank", WiredConditionTeamHasRank.class));
|
||||
this.interactionsList.add(new ItemInteraction("wf_cnd_has_var", WiredConditionHasVariable.class));
|
||||
this.interactionsList.add(new ItemInteraction("wf_cnd_neg_has_var", WiredConditionNotHasVariable.class));
|
||||
this.interactionsList.add(new ItemInteraction("wf_cnd_var_val_match", WiredConditionVariableValueMatch.class));
|
||||
this.interactionsList.add(new ItemInteraction("wf_cnd_var_age_match", WiredConditionVariableAgeMatch.class));
|
||||
|
||||
|
||||
this.interactionsList.add(new ItemInteraction("wf_xtra_random", WiredExtraRandom.class));
|
||||
@@ -349,6 +382,8 @@ public class ItemManager {
|
||||
this.interactionsList.add(new ItemInteraction("wf_xtra_filter_furni", WiredExtraFilterFurni.class));
|
||||
this.interactionsList.add(new ItemInteraction("wf_xtra_filter_user", WiredExtraFilterUser.class));
|
||||
this.interactionsList.add(new ItemInteraction("wf_xtra_filter_users", WiredExtraFilterUser.class));
|
||||
this.interactionsList.add(new ItemInteraction("wf_xtra_filter_furni_by_var", WiredExtraFilterFurniByVariable.class));
|
||||
this.interactionsList.add(new ItemInteraction("wf_xtra_filter_users_by_var", WiredExtraFilterUsersByVariable.class));
|
||||
this.interactionsList.add(new ItemInteraction("wf_xtra_mov_carry_users", WiredExtraMoveCarryUsers.class));
|
||||
this.interactionsList.add(new ItemInteraction("wf_xtra_mov_no_animation", WiredExtraMoveNoAnimation.class));
|
||||
this.interactionsList.add(new ItemInteraction("wf_xtra_anim_time", WiredExtraAnimationTime.class));
|
||||
@@ -357,6 +392,16 @@ public class ItemManager {
|
||||
this.interactionsList.add(new ItemInteraction("wf_xtra_execution_limit", WiredExtraExecutionLimit.class));
|
||||
this.interactionsList.add(new ItemInteraction("wf_xtra_text_output_username", WiredExtraTextOutputUsername.class));
|
||||
this.interactionsList.add(new ItemInteraction("wf_xtra_text_output_furni_name", WiredExtraTextOutputFurniName.class));
|
||||
this.interactionsList.add(new ItemInteraction("wf_xtra_text_output_variable", WiredExtraTextOutputVariable.class));
|
||||
this.interactionsList.add(new ItemInteraction("wf_xtra_text_input_variable", WiredExtraTextInputVariable.class));
|
||||
this.interactionsList.add(new ItemInteraction("wf_xtra_var_text_connector", WiredExtraVariableTextConnector.class));
|
||||
this.interactionsList.add(new ItemInteraction("wf_xtra_var_lvlup_system", WiredExtraVariableLevelUpSystem.class));
|
||||
this.interactionsList.add(new ItemInteraction("wf_var_user", WiredExtraUserVariable.class));
|
||||
this.interactionsList.add(new ItemInteraction("wf_var_furni", WiredExtraFurniVariable.class));
|
||||
this.interactionsList.add(new ItemInteraction("wf_var_room", WiredExtraRoomVariable.class));
|
||||
this.interactionsList.add(new ItemInteraction("wf_var_context", WiredExtraContextVariable.class));
|
||||
this.interactionsList.add(new ItemInteraction("wf_var_reference", WiredExtraVariableReference.class));
|
||||
this.interactionsList.add(new ItemInteraction("wf_var_echo", WiredExtraVariableEcho.class));
|
||||
|
||||
|
||||
this.interactionsList.add(new ItemInteraction("wf_highscore", InteractionWiredHighscore.class));
|
||||
|
||||
+172
@@ -0,0 +1,172 @@
|
||||
package com.eu.habbo.habbohotel.items.interactions;
|
||||
|
||||
import com.eu.habbo.Emulator;
|
||||
import com.eu.habbo.habbohotel.gameclients.GameClient;
|
||||
import com.eu.habbo.habbohotel.items.Item;
|
||||
import com.eu.habbo.habbohotel.rooms.Room;
|
||||
import com.eu.habbo.habbohotel.rooms.RoomAreaHideSupport;
|
||||
import com.eu.habbo.habbohotel.rooms.RoomLayout;
|
||||
import com.eu.habbo.habbohotel.users.Habbo;
|
||||
import com.eu.habbo.habbohotel.users.HabboItem;
|
||||
import com.eu.habbo.habbohotel.wired.WiredEffectType;
|
||||
import com.eu.habbo.messages.ServerMessage;
|
||||
import gnu.trove.map.hash.THashMap;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
public class InteractionAreaHideControl extends InteractionCustomValues {
|
||||
public static final THashMap<String, String> defaultValues = new THashMap<String, String>() {
|
||||
{
|
||||
this.put("state", "0");
|
||||
}
|
||||
{
|
||||
this.put("rootX", "0");
|
||||
}
|
||||
{
|
||||
this.put("rootY", "0");
|
||||
}
|
||||
{
|
||||
this.put("width", "0");
|
||||
}
|
||||
{
|
||||
this.put("length", "0");
|
||||
}
|
||||
{
|
||||
this.put("invisibility", "0");
|
||||
}
|
||||
{
|
||||
this.put("wallItems", "0");
|
||||
}
|
||||
{
|
||||
this.put("invert", "0");
|
||||
}
|
||||
};
|
||||
|
||||
public InteractionAreaHideControl(ResultSet set, Item baseItem) throws SQLException {
|
||||
super(set, baseItem, defaultValues);
|
||||
this.normalizeValues();
|
||||
}
|
||||
|
||||
public InteractionAreaHideControl(int id, int userId, Item item, String extradata, int limitedStack, int limitedSells) {
|
||||
super(id, userId, item, extradata, limitedStack, limitedSells, defaultValues);
|
||||
this.normalizeValues();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serializeExtradata(ServerMessage serverMessage) {
|
||||
this.normalizeValues();
|
||||
|
||||
serverMessage.appendInt(5 + (this.isLimited() ? 256 : 0));
|
||||
serverMessage.appendInt(8);
|
||||
serverMessage.appendInt(RoomAreaHideSupport.getState(this));
|
||||
serverMessage.appendInt(RoomAreaHideSupport.getRootX(this));
|
||||
serverMessage.appendInt(RoomAreaHideSupport.getRootY(this));
|
||||
serverMessage.appendInt(RoomAreaHideSupport.getWidth(this));
|
||||
serverMessage.appendInt(RoomAreaHideSupport.getLength(this));
|
||||
serverMessage.appendInt(RoomAreaHideSupport.isInvisibilityEnabled(this) ? 1 : 0);
|
||||
serverMessage.appendInt(RoomAreaHideSupport.includesWallItems(this) ? 1 : 0);
|
||||
serverMessage.appendInt(RoomAreaHideSupport.isInverted(this) ? 1 : 0);
|
||||
|
||||
if (this.isLimited()) {
|
||||
serverMessage.appendInt(this.getLimitedSells());
|
||||
serverMessage.appendInt(this.getLimitedStack());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUsable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean allowWiredResetState() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(GameClient client, Room room, Object[] objects) throws Exception {
|
||||
if (room == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
boolean wiredToggle = objects != null
|
||||
&& objects.length >= 2
|
||||
&& objects[1] instanceof WiredEffectType;
|
||||
|
||||
if (!wiredToggle) {
|
||||
if (client == null || !this.canToggle(client.getHabbo(), room)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
this.values.put("state", (RoomAreaHideSupport.getState(this) == 1) ? "0" : "1");
|
||||
this.normalizeValues();
|
||||
this.needsUpdate(true);
|
||||
Emulator.getThreading().run(this);
|
||||
room.updateItem(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCustomValuesSaved(Room room, GameClient client, THashMap<String, String> oldValues) {
|
||||
this.normalizeValues();
|
||||
}
|
||||
|
||||
public boolean canToggle(Habbo habbo, Room room) {
|
||||
if (habbo == null || room == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (room.hasRights(habbo)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!habbo.getHabboStats().isRentingSpace()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
HabboItem rentedItem = room.getHabboItem(habbo.getHabboStats().rentedItemId);
|
||||
|
||||
return room.getLayout() != null
|
||||
&& rentedItem != null
|
||||
&& RoomLayout.squareInSquare(
|
||||
RoomLayout.getRectangle(
|
||||
rentedItem.getX(),
|
||||
rentedItem.getY(),
|
||||
rentedItem.getBaseItem().getWidth(),
|
||||
rentedItem.getBaseItem().getLength(),
|
||||
rentedItem.getRotation()
|
||||
),
|
||||
RoomLayout.getRectangle(
|
||||
this.getX(),
|
||||
this.getY(),
|
||||
this.getBaseItem().getWidth(),
|
||||
this.getBaseItem().getLength(),
|
||||
this.getRotation()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private void normalizeValues() {
|
||||
this.values.put("state", booleanFlag(this.values.get("state")));
|
||||
this.values.put("rootX", Integer.toString(nonNegative(this.values.get("rootX"))));
|
||||
this.values.put("rootY", Integer.toString(nonNegative(this.values.get("rootY"))));
|
||||
this.values.put("width", Integer.toString(nonNegative(this.values.get("width"))));
|
||||
this.values.put("length", Integer.toString(nonNegative(this.values.get("length"))));
|
||||
this.values.put("invisibility", booleanFlag(this.values.get("invisibility")));
|
||||
this.values.put("wallItems", booleanFlag(this.values.get("wallItems")));
|
||||
this.values.put("invert", booleanFlag(this.values.get("invert")));
|
||||
}
|
||||
|
||||
private static int nonNegative(String value) {
|
||||
try {
|
||||
return Math.max(0, Integer.parseInt(value));
|
||||
} catch (Exception ignored) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
private static String booleanFlag(String value) {
|
||||
return ("1".equals(value) || "true".equalsIgnoreCase(value)) ? "1" : "0";
|
||||
}
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
package com.eu.habbo.habbohotel.items.interactions;
|
||||
|
||||
import com.eu.habbo.habbohotel.items.Item;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
public class InteractionConfInvisControl extends InteractionRemoteSwitchControl {
|
||||
public InteractionConfInvisControl(ResultSet set, Item baseItem) throws SQLException {
|
||||
super(set, baseItem);
|
||||
}
|
||||
|
||||
public InteractionConfInvisControl(int id, int userId, Item item, String extradata, int limitedStack, int limitedSells) {
|
||||
super(id, userId, item, extradata, limitedStack, limitedSells);
|
||||
}
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
package com.eu.habbo.habbohotel.items.interactions;
|
||||
|
||||
import com.eu.habbo.habbohotel.items.Item;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
public class InteractionHanditemBlockControl extends InteractionRemoteSwitchControl {
|
||||
public InteractionHanditemBlockControl(ResultSet set, Item baseItem) throws SQLException {
|
||||
super(set, baseItem);
|
||||
}
|
||||
|
||||
public InteractionHanditemBlockControl(int id, int userId, Item item, String extradata, int limitedStack, int limitedSells) {
|
||||
super(id, userId, item, extradata, limitedStack, limitedSells);
|
||||
}
|
||||
}
|
||||
+186
@@ -0,0 +1,186 @@
|
||||
package com.eu.habbo.habbohotel.items.interactions;
|
||||
|
||||
import com.eu.habbo.Emulator;
|
||||
import com.eu.habbo.habbohotel.gameclients.GameClient;
|
||||
import com.eu.habbo.habbohotel.items.Item;
|
||||
import com.eu.habbo.habbohotel.rooms.Room;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
public class InteractionQueueSpeedControl extends InteractionRemoteSwitchControl {
|
||||
private static final int[] MODE_STATES = new int[]{0, 3, 6, 9};
|
||||
private static final int MODE_FRAME_COUNT = 3;
|
||||
private static final int BASE_FRAME_DURATION_MS = 500;
|
||||
|
||||
private transient volatile int animationRevision = 0;
|
||||
private transient volatile int animationRoomId = 0;
|
||||
private transient volatile int animationModeState = Integer.MIN_VALUE;
|
||||
|
||||
public InteractionQueueSpeedControl(ResultSet set, Item baseItem) throws SQLException {
|
||||
super(set, baseItem);
|
||||
}
|
||||
|
||||
public InteractionQueueSpeedControl(int id, int userId, Item item, String extradata, int limitedStack, int limitedSells) {
|
||||
super(id, userId, item, extradata, limitedStack, limitedSells);
|
||||
}
|
||||
|
||||
public static int toModeState(String extradata) {
|
||||
int state = 0;
|
||||
|
||||
try {
|
||||
state = Integer.parseInt(extradata);
|
||||
} catch (NumberFormatException ignored) {
|
||||
}
|
||||
|
||||
if (state >= 9) {
|
||||
return 9;
|
||||
}
|
||||
|
||||
if (state >= 6) {
|
||||
return 6;
|
||||
}
|
||||
|
||||
if (state >= 3) {
|
||||
return 3;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static int toRollerSpeed(String extradata) {
|
||||
int modeState = toModeState(extradata);
|
||||
|
||||
if (modeState >= 9) {
|
||||
return 3;
|
||||
}
|
||||
|
||||
if (modeState >= 6) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
if (modeState >= 3) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static int toRollerIntervalMs(String extradata) {
|
||||
return BASE_FRAME_DURATION_MS * (toRollerSpeed(extradata) + 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClick(GameClient client, Room room, Object[] objects) throws Exception {
|
||||
if (room == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
boolean wiredToggle = objects != null
|
||||
&& objects.length >= 2
|
||||
&& objects[1] instanceof com.eu.habbo.habbohotel.wired.WiredEffectType;
|
||||
|
||||
if (!wiredToggle) {
|
||||
if (client == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.canToggle(client.getHabbo(), room)) {
|
||||
super.onClick(client, room, new Object[]{"QUEUE_SPEED_USE"});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
int nextModeState = getNextModeState(this.getExtradata());
|
||||
applyModeState(room, nextModeState, true);
|
||||
|
||||
if (client != null) {
|
||||
super.onClick(client, room, new Object[]{"TOGGLE_OVERRIDE"});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlace(Room room) {
|
||||
super.onPlace(room);
|
||||
this.ensureAnimationLoop(room);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPickUp(Room room) {
|
||||
this.animationRevision++;
|
||||
this.animationRoomId = 0;
|
||||
this.animationModeState = Integer.MIN_VALUE;
|
||||
super.onPickUp(room);
|
||||
}
|
||||
|
||||
public void ensureAnimationLoop(Room room) {
|
||||
if (room == null || !room.isLoaded() || this.getRoomId() != room.getId()) {
|
||||
return;
|
||||
}
|
||||
|
||||
int modeState = toModeState(this.getExtradata());
|
||||
|
||||
if (this.animationRoomId == room.getId() && this.animationModeState == modeState) {
|
||||
return;
|
||||
}
|
||||
|
||||
applyModeState(room, modeState, false);
|
||||
}
|
||||
|
||||
private void applyModeState(Room room, int modeState, boolean persistSelection) {
|
||||
if (room == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.animationRevision++;
|
||||
this.animationRoomId = room.getId();
|
||||
this.animationModeState = modeState;
|
||||
|
||||
this.setExtradata(Integer.toString(modeState));
|
||||
if (persistSelection) {
|
||||
this.needsUpdate(true);
|
||||
}
|
||||
room.updateItemState(this);
|
||||
|
||||
int revision = this.animationRevision;
|
||||
int nextFrame = modeState + 1;
|
||||
long delay = toRollerIntervalMs(Integer.toString(modeState));
|
||||
|
||||
Emulator.getThreading().run(() -> this.animateNextFrame(room, modeState, nextFrame, revision), delay);
|
||||
}
|
||||
|
||||
private void animateNextFrame(Room room, int modeState, int nextFrame, int revision) {
|
||||
if (room == null || !room.isLoaded() || this.getRoomId() != room.getId()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (revision != this.animationRevision || modeState != this.animationModeState) {
|
||||
return;
|
||||
}
|
||||
|
||||
int maxFrame = modeState + (MODE_FRAME_COUNT - 1);
|
||||
int frame = (nextFrame > maxFrame) ? modeState : nextFrame;
|
||||
|
||||
this.setExtradata(Integer.toString(frame));
|
||||
room.updateItemState(this);
|
||||
|
||||
int followingFrame = (frame >= maxFrame) ? modeState : (frame + 1);
|
||||
long delay = toRollerIntervalMs(Integer.toString(modeState));
|
||||
|
||||
Emulator.getThreading().run(() -> this.animateNextFrame(room, modeState, followingFrame, revision), delay);
|
||||
}
|
||||
|
||||
private static int getNextModeState(String extradata) {
|
||||
int currentModeState = toModeState(extradata);
|
||||
|
||||
for (int index = 0; index < MODE_STATES.length; index++) {
|
||||
if (MODE_STATES[index] != currentModeState) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return MODE_STATES[(index + 1) % MODE_STATES.length];
|
||||
}
|
||||
|
||||
return MODE_STATES[0];
|
||||
}
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
package com.eu.habbo.habbohotel.items.interactions;
|
||||
|
||||
import com.eu.habbo.habbohotel.items.Item;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
public class InteractionRemoteSwitchControl extends InteractionDefault {
|
||||
public InteractionRemoteSwitchControl(ResultSet set, Item baseItem) throws SQLException {
|
||||
super(set, baseItem);
|
||||
}
|
||||
|
||||
public InteractionRemoteSwitchControl(int id, int userId, Item item, String extradata, int limitedStack, int limitedSells) {
|
||||
super(id, userId, item, extradata, limitedStack, limitedSells);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUsable() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
package com.eu.habbo.habbohotel.items.interactions;
|
||||
|
||||
import com.eu.habbo.habbohotel.items.Item;
|
||||
import com.eu.habbo.habbohotel.rooms.Room;
|
||||
import com.eu.habbo.habbohotel.rooms.RoomUnit;
|
||||
import com.eu.habbo.habbohotel.users.HabboItem;
|
||||
import com.eu.habbo.messages.ServerMessage;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
public class InteractionStackWalkHelper extends HabboItem {
|
||||
public InteractionStackWalkHelper(ResultSet set, Item baseItem) throws SQLException {
|
||||
super(set, baseItem);
|
||||
}
|
||||
|
||||
public InteractionStackWalkHelper(int id, int userId, Item item, String extradata, int limitedStack, int limitedSells) {
|
||||
super(id, userId, item, extradata, limitedStack, limitedSells);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canWalkOn(RoomUnit roomUnit, Room room, Object[] objects) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWalkable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWalk(RoomUnit roomUnit, Room room, Object[] objects) throws Exception {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serializeExtradata(ServerMessage serverMessage) {
|
||||
serverMessage.appendInt((this.isLimited() ? 256 : 0));
|
||||
serverMessage.appendString(this.getExtradata());
|
||||
|
||||
super.serializeExtradata(serverMessage);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUsable() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -43,7 +43,7 @@ public abstract class InteractionWiredCondition extends InteractionWired impleme
|
||||
@Override
|
||||
public void onClick(GameClient client, Room room, Object[] objects) throws Exception {
|
||||
if (client != null) {
|
||||
if (room.hasRights(client.getHabbo())) {
|
||||
if (room.canInspectWired(client.getHabbo())) {
|
||||
client.sendResponse(new WiredConditionDataComposer(this, room));
|
||||
this.activateBox(room);
|
||||
}
|
||||
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
package com.eu.habbo.habbohotel.items.interactions;
|
||||
|
||||
import com.eu.habbo.habbohotel.items.Item;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
public class InteractionWiredDisableControl extends InteractionRemoteSwitchControl {
|
||||
public InteractionWiredDisableControl(ResultSet set, Item baseItem) throws SQLException {
|
||||
super(set, baseItem);
|
||||
}
|
||||
|
||||
public InteractionWiredDisableControl(int id, int userId, Item item, String extradata, int limitedStack, int limitedSells) {
|
||||
super(id, userId, item, extradata, limitedStack, limitedSells);
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -80,7 +80,7 @@ public abstract class InteractionWiredEffect extends InteractionWired implements
|
||||
@Override
|
||||
public void onClick(GameClient client, Room room, Object[] objects) throws Exception {
|
||||
if (client != null) {
|
||||
if (room.hasRights(client.getHabbo())) {
|
||||
if (room.canInspectWired(client.getHabbo())) {
|
||||
client.sendResponse(new WiredEffectDataComposer(this, room));
|
||||
this.activateBox(room);
|
||||
}
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@ public abstract class InteractionWiredExtra extends InteractionWired {
|
||||
@Override
|
||||
public void onClick(GameClient client, Room room, Object[] objects) throws Exception {
|
||||
if (client != null) {
|
||||
if (room.hasRights(client.getHabbo())) {
|
||||
if (room.canInspectWired(client.getHabbo())) {
|
||||
if (this.hasConfiguration()) {
|
||||
client.sendResponse(new WiredExtraDataComposer(this, room));
|
||||
}
|
||||
|
||||
+1
-1
@@ -45,7 +45,7 @@ public abstract class InteractionWiredTrigger extends InteractionWired implement
|
||||
@Override
|
||||
public void onClick(GameClient client, Room room, Object[] objects) throws Exception {
|
||||
if (client != null) {
|
||||
if (room.hasRights(client.getHabbo())) {
|
||||
if (room.canInspectWired(client.getHabbo())) {
|
||||
client.sendResponse(new WiredTriggerDataComposer(this, room));
|
||||
this.activateBox(room);
|
||||
}
|
||||
|
||||
+4
@@ -177,6 +177,10 @@ public class WiredConditionFurniHaveFurni extends InteractionWiredCondition {
|
||||
int count = settings.getFurniIds().length;
|
||||
if (count > Emulator.getConfig().getInt("hotel.wired.furni.selection.count")) return false;
|
||||
|
||||
if (count > 0 && this.furniSource == WiredSourceUtil.SOURCE_TRIGGER) {
|
||||
this.furniSource = WiredSourceUtil.SOURCE_SELECTED;
|
||||
}
|
||||
|
||||
this.items.clear();
|
||||
|
||||
if (this.furniSource == WiredSourceUtil.SOURCE_SELECTED) {
|
||||
|
||||
+4
@@ -164,6 +164,10 @@ public class WiredConditionFurniHaveHabbo extends InteractionWiredCondition {
|
||||
this.all = (params.length > 0) && (params[0] == 1);
|
||||
this.furniSource = (params.length > 1) ? params[1] : ((params.length > 0 && params[0] > 1) ? params[0] : WiredSourceUtil.SOURCE_TRIGGER);
|
||||
|
||||
if (count > 0 && this.furniSource == WiredSourceUtil.SOURCE_TRIGGER) {
|
||||
this.furniSource = WiredSourceUtil.SOURCE_SELECTED;
|
||||
}
|
||||
|
||||
this.items.clear();
|
||||
|
||||
if (this.furniSource == WiredSourceUtil.SOURCE_SELECTED) {
|
||||
|
||||
+4
@@ -240,6 +240,10 @@ public class WiredConditionFurniTypeMatch extends InteractionWiredCondition {
|
||||
this.quantifier = (params.length > 2) ? this.normalizeQuantifier(params[2]) : QUANTIFIER_ALL;
|
||||
}
|
||||
|
||||
if (count > 0 && this.furniSource == WiredSourceUtil.SOURCE_TRIGGER) {
|
||||
this.furniSource = WiredSourceUtil.SOURCE_SELECTED;
|
||||
}
|
||||
|
||||
Room room = Emulator.getGameEnvironment().getRoomManager().getRoom(this.getRoomId());
|
||||
if (room == null) {
|
||||
return false;
|
||||
|
||||
+4
@@ -171,6 +171,10 @@ public class WiredConditionHasAltitude extends InteractionWiredCondition {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (count > 0 && this.furniSource == WiredSourceUtil.SOURCE_TRIGGER) {
|
||||
this.furniSource = WiredSourceUtil.SOURCE_SELECTED;
|
||||
}
|
||||
|
||||
this.items.clear();
|
||||
|
||||
if (this.furniSource == WiredSourceUtil.SOURCE_SELECTED) {
|
||||
|
||||
+506
@@ -0,0 +1,506 @@
|
||||
package com.eu.habbo.habbohotel.items.interactions.wired.conditions;
|
||||
|
||||
import com.eu.habbo.Emulator;
|
||||
import com.eu.habbo.habbohotel.bots.Bot;
|
||||
import com.eu.habbo.habbohotel.items.FurnitureType;
|
||||
import com.eu.habbo.habbohotel.items.Item;
|
||||
import com.eu.habbo.habbohotel.items.interactions.InteractionWiredCondition;
|
||||
import com.eu.habbo.habbohotel.items.interactions.wired.WiredSettings;
|
||||
import com.eu.habbo.habbohotel.pets.Pet;
|
||||
import com.eu.habbo.habbohotel.rooms.Room;
|
||||
import com.eu.habbo.habbohotel.rooms.RoomRightLevels;
|
||||
import com.eu.habbo.habbohotel.rooms.RoomUnit;
|
||||
import com.eu.habbo.habbohotel.rooms.RoomUnitStatus;
|
||||
import com.eu.habbo.habbohotel.users.DanceType;
|
||||
import com.eu.habbo.habbohotel.users.Habbo;
|
||||
import com.eu.habbo.habbohotel.users.HabboItem;
|
||||
import com.eu.habbo.habbohotel.wired.WiredConditionType;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredContext;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredContextVariableSupport;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredFreezeUtil;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredInternalVariableSupport;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredManager;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredSourceUtil;
|
||||
import com.eu.habbo.messages.ServerMessage;
|
||||
import gnu.trove.set.hash.THashSet;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class WiredConditionHasVariable extends InteractionWiredCondition {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(WiredConditionHasVariable.class);
|
||||
|
||||
protected static final int TARGET_USER = 0;
|
||||
protected static final int TARGET_FURNI = 1;
|
||||
protected static final int TARGET_CONTEXT = 2;
|
||||
protected static final int TARGET_ROOM = 3;
|
||||
protected static final int QUANTIFIER_ALL = 0;
|
||||
protected static final int QUANTIFIER_ANY = 1;
|
||||
private static final String CUSTOM_TOKEN_PREFIX = "custom:";
|
||||
private static final String INTERNAL_TOKEN_PREFIX = "internal:";
|
||||
|
||||
public static final WiredConditionType type = WiredConditionType.HAS_VAR;
|
||||
|
||||
protected final THashSet<HabboItem> selectedItems = new THashSet<>();
|
||||
protected int targetType = TARGET_USER;
|
||||
protected int userSource = WiredSourceUtil.SOURCE_TRIGGER;
|
||||
protected int furniSource = WiredSourceUtil.SOURCE_TRIGGER;
|
||||
protected int quantifier = QUANTIFIER_ALL;
|
||||
protected String variableToken = "";
|
||||
protected int variableItemId = 0;
|
||||
|
||||
public WiredConditionHasVariable(ResultSet set, Item baseItem) throws SQLException {
|
||||
super(set, baseItem);
|
||||
}
|
||||
|
||||
public WiredConditionHasVariable(int id, int userId, Item item, String extradata, int limitedStack, int limitedSells) {
|
||||
super(id, userId, item, extradata, limitedStack, limitedSells);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WiredConditionType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serializeWiredData(ServerMessage message, Room room) {
|
||||
this.refresh();
|
||||
|
||||
List<HabboItem> serializedItems = new ArrayList<>();
|
||||
if (this.targetType == TARGET_FURNI && this.furniSource == WiredSourceUtil.SOURCE_SELECTED) {
|
||||
serializedItems.addAll(this.selectedItems);
|
||||
}
|
||||
|
||||
message.appendBoolean(false);
|
||||
message.appendInt(WiredManager.MAXIMUM_FURNI_SELECTION);
|
||||
message.appendInt(serializedItems.size());
|
||||
|
||||
for (HabboItem item : serializedItems) {
|
||||
message.appendInt(item.getId());
|
||||
}
|
||||
|
||||
message.appendInt(this.getBaseItem().getSpriteId());
|
||||
message.appendInt(this.getId());
|
||||
message.appendString(this.variableToken == null ? "" : this.variableToken);
|
||||
message.appendInt(4);
|
||||
message.appendInt(this.targetType);
|
||||
message.appendInt(this.userSource);
|
||||
message.appendInt(this.furniSource);
|
||||
message.appendInt(this.quantifier);
|
||||
message.appendInt(0);
|
||||
message.appendInt(this.getType().code);
|
||||
message.appendInt(0);
|
||||
message.appendInt(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean saveData(WiredSettings settings) {
|
||||
int[] params = settings.getIntParams();
|
||||
Room room = Emulator.getGameEnvironment().getRoomManager().getRoom(this.getRoomId());
|
||||
|
||||
this.targetType = (params.length > 0) ? normalizeTargetType(params[0]) : TARGET_USER;
|
||||
this.userSource = (params.length > 1) ? normalizeUserSource(params[1]) : WiredSourceUtil.SOURCE_TRIGGER;
|
||||
this.furniSource = (params.length > 2) ? normalizeFurniSource(params[2]) : WiredSourceUtil.SOURCE_TRIGGER;
|
||||
this.quantifier = (params.length > 3) ? normalizeQuantifier(params[3]) : QUANTIFIER_ALL;
|
||||
this.setVariableToken(normalizeVariableToken(settings.getStringParam()));
|
||||
|
||||
if (this.variableToken.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
this.selectedItems.clear();
|
||||
|
||||
if (this.targetType == TARGET_FURNI && this.furniSource == WiredSourceUtil.SOURCE_SELECTED && room != null) {
|
||||
int[] furniIds = settings.getFurniIds();
|
||||
if (furniIds.length > Emulator.getConfig().getInt("hotel.wired.furni.selection.count")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int furniId : furniIds) {
|
||||
HabboItem item = room.getHabboItem(furniId);
|
||||
|
||||
if (item != null) {
|
||||
this.selectedItems.add(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean evaluate(WiredContext ctx) {
|
||||
return this.evaluateWithNegation(ctx, false);
|
||||
}
|
||||
|
||||
protected boolean evaluateWithNegation(WiredContext ctx, boolean negative) {
|
||||
Room room = ctx.room();
|
||||
|
||||
if (room == null || this.variableToken == null || this.variableToken.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return switch (this.targetType) {
|
||||
case TARGET_FURNI -> this.evaluateFurniTargets(ctx, room, negative);
|
||||
case TARGET_CONTEXT -> {
|
||||
boolean contextMatch = this.matchesContext(ctx, room);
|
||||
yield negative ? !contextMatch : contextMatch;
|
||||
}
|
||||
case TARGET_ROOM -> {
|
||||
boolean roomMatch = this.matchesRoom(room);
|
||||
yield negative ? !roomMatch : roomMatch;
|
||||
}
|
||||
default -> this.evaluateUserTargets(ctx, room, negative);
|
||||
};
|
||||
}
|
||||
|
||||
private boolean evaluateUserTargets(WiredContext ctx, Room room, boolean negative) {
|
||||
List<RoomUnit> targets = WiredSourceUtil.resolveUsers(ctx, this.userSource);
|
||||
if (targets.isEmpty()) return false;
|
||||
|
||||
boolean match = (this.quantifier == QUANTIFIER_ANY)
|
||||
? this.matchesAnyUser(room, targets)
|
||||
: this.matchesAllUsers(room, targets);
|
||||
|
||||
return negative ? !match : match;
|
||||
}
|
||||
|
||||
private boolean evaluateFurniTargets(WiredContext ctx, Room room, boolean negative) {
|
||||
this.refresh();
|
||||
|
||||
List<HabboItem> targets = WiredSourceUtil.resolveItems(ctx, this.furniSource, this.selectedItems);
|
||||
if (targets.isEmpty()) return false;
|
||||
|
||||
boolean match = (this.quantifier == QUANTIFIER_ANY)
|
||||
? this.matchesAnyFurni(room, targets)
|
||||
: this.matchesAllFurni(room, targets);
|
||||
|
||||
return negative ? !match : match;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@Override
|
||||
public boolean execute(RoomUnit roomUnit, Room room, Object[] stuff) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getWiredData() {
|
||||
this.refresh();
|
||||
|
||||
List<Integer> itemIds = new ArrayList<>();
|
||||
for (HabboItem item : this.selectedItems) {
|
||||
if (item != null) itemIds.add(item.getId());
|
||||
}
|
||||
|
||||
return WiredManager.getGson().toJson(new JsonData(
|
||||
itemIds,
|
||||
this.targetType,
|
||||
this.variableToken,
|
||||
this.variableItemId,
|
||||
this.userSource,
|
||||
this.furniSource,
|
||||
this.quantifier
|
||||
));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadWiredData(ResultSet set, Room room) throws SQLException {
|
||||
this.onPickUp();
|
||||
|
||||
String wiredData = set.getString("wired_data");
|
||||
if (wiredData == null || wiredData.isEmpty()) return;
|
||||
|
||||
try {
|
||||
if (wiredData.startsWith("{")) {
|
||||
JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class);
|
||||
|
||||
if (data == null) return;
|
||||
|
||||
this.targetType = normalizeTargetType(data.targetType);
|
||||
this.userSource = normalizeUserSource(data.userSource);
|
||||
this.furniSource = normalizeFurniSource(data.furniSource);
|
||||
this.quantifier = normalizeQuantifier(data.quantifier);
|
||||
this.setVariableToken(normalizeVariableToken((data.variableToken != null) ? data.variableToken : ((data.variableItemId > 0) ? String.valueOf(data.variableItemId) : "")));
|
||||
|
||||
if (room != null && data.itemIds != null) {
|
||||
for (Integer itemId : data.itemIds) {
|
||||
if (itemId == null || itemId <= 0) continue;
|
||||
|
||||
HabboItem item = room.getHabboItem(itemId);
|
||||
if (item != null) this.selectedItems.add(item);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.setVariableToken(normalizeVariableToken(wiredData));
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("Failed to load wired variable condition data for item {}", this.getId(), e);
|
||||
this.onPickUp();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPickUp() {
|
||||
this.targetType = TARGET_USER;
|
||||
this.userSource = WiredSourceUtil.SOURCE_TRIGGER;
|
||||
this.furniSource = WiredSourceUtil.SOURCE_TRIGGER;
|
||||
this.quantifier = QUANTIFIER_ALL;
|
||||
this.selectedItems.clear();
|
||||
this.setVariableToken("");
|
||||
}
|
||||
|
||||
protected boolean matchesAnyUser(Room room, List<RoomUnit> targets) {
|
||||
for (RoomUnit roomUnit : targets) {
|
||||
if (this.matchesUser(room, roomUnit)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected boolean matchesAllUsers(Room room, List<RoomUnit> targets) {
|
||||
for (RoomUnit roomUnit : targets) {
|
||||
if (!this.matchesUser(room, roomUnit)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected boolean matchesAnyFurni(Room room, List<HabboItem> targets) {
|
||||
for (HabboItem item : targets) {
|
||||
if (this.matchesFurni(room, item)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected boolean matchesAllFurni(Room room, List<HabboItem> targets) {
|
||||
for (HabboItem item : targets) {
|
||||
if (!this.matchesFurni(room, item)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected boolean matchesUser(Room room, RoomUnit roomUnit) {
|
||||
if (room == null || roomUnit == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isCustomVariableToken(this.variableToken)) {
|
||||
Habbo habbo = room.getHabbo(roomUnit);
|
||||
|
||||
return habbo != null && room.getUserVariableManager().hasVariable(habbo.getHabboInfo().getId(), this.variableItemId);
|
||||
}
|
||||
|
||||
if (isInternalVariableToken(this.variableToken)) {
|
||||
return this.hasUserInternalVariable(room, roomUnit, getInternalVariableKey(this.variableToken));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected boolean matchesFurni(Room room, HabboItem item) {
|
||||
if (room == null || item == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isCustomVariableToken(this.variableToken)) {
|
||||
return room.getFurniVariableManager().hasVariable(item.getId(), this.variableItemId);
|
||||
}
|
||||
|
||||
if (isInternalVariableToken(this.variableToken)) {
|
||||
return this.hasFurniInternalVariable(item, getInternalVariableKey(this.variableToken));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected boolean matchesContext(WiredContext ctx, Room room) {
|
||||
if (ctx == null || room == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isCustomVariableToken(this.variableToken)) {
|
||||
return WiredContextVariableSupport.hasVariable(ctx, this.variableItemId);
|
||||
}
|
||||
|
||||
if (isInternalVariableToken(this.variableToken)) {
|
||||
return WiredInternalVariableSupport.readContextValue(ctx, getInternalVariableKey(this.variableToken)) != null;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected boolean matchesRoom(Room room) {
|
||||
if (room == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isCustomVariableToken(this.variableToken)) {
|
||||
return room.getRoomVariableManager().hasVariable(this.variableItemId);
|
||||
}
|
||||
|
||||
if (isInternalVariableToken(this.variableToken)) {
|
||||
return this.hasRoomInternalVariable(getInternalVariableKey(this.variableToken));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected boolean hasUserInternalVariable(Room room, RoomUnit roomUnit, String key) {
|
||||
return WiredInternalVariableSupport.hasUserValue(room, roomUnit, key);
|
||||
}
|
||||
|
||||
protected boolean hasFurniInternalVariable(HabboItem item, String key) {
|
||||
return WiredInternalVariableSupport.hasFurniValue(item, key);
|
||||
}
|
||||
|
||||
protected boolean hasRoomInternalVariable(String key) {
|
||||
return WiredInternalVariableSupport.hasRoomValue(Emulator.getGameEnvironment().getRoomManager().getRoom(this.getRoomId()), key);
|
||||
}
|
||||
|
||||
protected void refresh() {
|
||||
THashSet<HabboItem> staleItems = new THashSet<>();
|
||||
Room room = Emulator.getGameEnvironment().getRoomManager().getRoom(this.getRoomId());
|
||||
|
||||
if (room == null) {
|
||||
staleItems.addAll(this.selectedItems);
|
||||
} else {
|
||||
for (HabboItem item : this.selectedItems) {
|
||||
if (item == null || item.getRoomId() != room.getId()) {
|
||||
staleItems.add(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.selectedItems.removeAll(staleItems);
|
||||
}
|
||||
|
||||
protected void setVariableToken(String token) {
|
||||
this.variableToken = normalizeVariableToken(token);
|
||||
this.variableItemId = getCustomItemId(this.variableToken);
|
||||
}
|
||||
|
||||
protected boolean hasRoomEntryMethod(Habbo habbo) {
|
||||
if (habbo == null) return false;
|
||||
|
||||
String roomEntryMethod = habbo.getHabboInfo().getRoomEntryMethod();
|
||||
|
||||
return roomEntryMethod != null && !roomEntryMethod.trim().isEmpty() && !"unknown".equalsIgnoreCase(roomEntryMethod);
|
||||
}
|
||||
|
||||
protected TeamEffectData getTeamEffectData(int effectValue) {
|
||||
if (effectValue <= 0) return null;
|
||||
|
||||
if (effectValue >= 223 && effectValue <= 226) return new TeamEffectData(effectValue - 222, 0);
|
||||
if (effectValue >= 33 && effectValue <= 36) return new TeamEffectData(effectValue - 32, 1);
|
||||
if (effectValue >= 40 && effectValue <= 43) return new TeamEffectData(effectValue - 39, 2);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
protected static int normalizeTargetType(int value) {
|
||||
return switch (value) {
|
||||
case TARGET_FURNI, TARGET_CONTEXT, TARGET_ROOM -> value;
|
||||
default -> TARGET_USER;
|
||||
};
|
||||
}
|
||||
|
||||
protected static int normalizeQuantifier(int value) {
|
||||
return (value == QUANTIFIER_ANY) ? QUANTIFIER_ANY : QUANTIFIER_ALL;
|
||||
}
|
||||
|
||||
protected static int normalizeUserSource(int value) {
|
||||
return WiredSourceUtil.isDefaultUserSource(value) ? value : WiredSourceUtil.SOURCE_TRIGGER;
|
||||
}
|
||||
|
||||
protected static int normalizeFurniSource(int value) {
|
||||
return switch (value) {
|
||||
case WiredSourceUtil.SOURCE_SELECTED, WiredSourceUtil.SOURCE_SELECTOR, WiredSourceUtil.SOURCE_SIGNAL -> value;
|
||||
default -> WiredSourceUtil.SOURCE_TRIGGER;
|
||||
};
|
||||
}
|
||||
|
||||
protected static boolean isCustomVariableToken(String token) {
|
||||
return token != null && token.startsWith(CUSTOM_TOKEN_PREFIX);
|
||||
}
|
||||
|
||||
protected static boolean isInternalVariableToken(String token) {
|
||||
return token != null && token.startsWith(INTERNAL_TOKEN_PREFIX);
|
||||
}
|
||||
|
||||
protected static int getCustomItemId(String token) {
|
||||
if (!isCustomVariableToken(token)) return 0;
|
||||
|
||||
try {
|
||||
return Integer.parseInt(token.substring(CUSTOM_TOKEN_PREFIX.length()));
|
||||
} catch (NumberFormatException e) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
protected static String getInternalVariableKey(String token) {
|
||||
return isInternalVariableToken(token) ? WiredInternalVariableSupport.normalizeKey(token.substring(INTERNAL_TOKEN_PREFIX.length())) : "";
|
||||
}
|
||||
|
||||
protected static String normalizeVariableToken(String token) {
|
||||
if (token == null) return "";
|
||||
|
||||
String normalized = token.trim();
|
||||
if (normalized.isEmpty()) return "";
|
||||
if (isCustomVariableToken(normalized)) return normalized;
|
||||
if (isInternalVariableToken(normalized)) return INTERNAL_TOKEN_PREFIX + WiredInternalVariableSupport.normalizeKey(normalized.substring(INTERNAL_TOKEN_PREFIX.length()));
|
||||
|
||||
try {
|
||||
int parsed = Integer.parseInt(normalized);
|
||||
return (parsed > 0) ? (CUSTOM_TOKEN_PREFIX + parsed) : "";
|
||||
} catch (NumberFormatException e) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
protected static class JsonData {
|
||||
List<Integer> itemIds;
|
||||
int targetType;
|
||||
String variableToken;
|
||||
int variableItemId;
|
||||
int userSource;
|
||||
int furniSource;
|
||||
int quantifier;
|
||||
|
||||
public JsonData(List<Integer> itemIds, int targetType, String variableToken, int variableItemId, int userSource, int furniSource, int quantifier) {
|
||||
this.itemIds = itemIds;
|
||||
this.targetType = targetType;
|
||||
this.variableToken = variableToken;
|
||||
this.variableItemId = variableItemId;
|
||||
this.userSource = userSource;
|
||||
this.furniSource = furniSource;
|
||||
this.quantifier = quantifier;
|
||||
}
|
||||
}
|
||||
|
||||
protected static class TeamEffectData {
|
||||
final int colorId;
|
||||
final int typeId;
|
||||
|
||||
protected TeamEffectData(int colorId, int typeId) {
|
||||
this.colorId = colorId;
|
||||
this.typeId = typeId;
|
||||
}
|
||||
}
|
||||
}
|
||||
+4
@@ -177,6 +177,10 @@ public class WiredConditionNotFurniHaveFurni extends InteractionWiredCondition {
|
||||
int count = settings.getFurniIds().length;
|
||||
if (count > Emulator.getConfig().getInt("hotel.wired.furni.selection.count")) return false;
|
||||
|
||||
if (count > 0 && this.furniSource == WiredSourceUtil.SOURCE_TRIGGER) {
|
||||
this.furniSource = WiredSourceUtil.SOURCE_SELECTED;
|
||||
}
|
||||
|
||||
this.items.clear();
|
||||
|
||||
if (this.furniSource == WiredSourceUtil.SOURCE_SELECTED) {
|
||||
|
||||
+4
@@ -163,6 +163,10 @@ public class WiredConditionNotFurniHaveHabbo extends InteractionWiredCondition {
|
||||
this.all = (params.length > 0) && (params[0] == 1);
|
||||
this.furniSource = (params.length > 1) ? params[1] : ((params.length > 0 && params[0] > 1) ? params[0] : WiredSourceUtil.SOURCE_TRIGGER);
|
||||
|
||||
if (count > 0 && this.furniSource == WiredSourceUtil.SOURCE_TRIGGER) {
|
||||
this.furniSource = WiredSourceUtil.SOURCE_SELECTED;
|
||||
}
|
||||
|
||||
this.items.clear();
|
||||
|
||||
if (this.furniSource == WiredSourceUtil.SOURCE_SELECTED) {
|
||||
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
package com.eu.habbo.habbohotel.items.interactions.wired.conditions;
|
||||
|
||||
import com.eu.habbo.habbohotel.items.Item;
|
||||
import com.eu.habbo.habbohotel.wired.WiredConditionType;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredContext;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
public class WiredConditionNotHasVariable extends WiredConditionHasVariable {
|
||||
public static final WiredConditionType type = WiredConditionType.NOT_HAS_VAR;
|
||||
|
||||
public WiredConditionNotHasVariable(ResultSet set, Item baseItem) throws SQLException {
|
||||
super(set, baseItem);
|
||||
}
|
||||
|
||||
public WiredConditionNotHasVariable(int id, int userId, Item item, String extradata, int limitedStack, int limitedSells) {
|
||||
super(id, userId, item, extradata, limitedStack, limitedSells);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WiredConditionType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean evaluate(WiredContext ctx) {
|
||||
return this.evaluateWithNegation(ctx, true);
|
||||
}
|
||||
}
|
||||
+4
@@ -186,6 +186,10 @@ public class WiredConditionTriggerOnFurni extends InteractionWiredCondition {
|
||||
this.userSource = (params.length > 1) ? params[1] : WiredSourceUtil.SOURCE_TRIGGER;
|
||||
this.quantifier = (params.length > 2) ? this.normalizeQuantifier(params[2]) : QUANTIFIER_ALL;
|
||||
|
||||
if (count > 0 && this.furniSource == WiredSourceUtil.SOURCE_TRIGGER) {
|
||||
this.furniSource = WiredSourceUtil.SOURCE_SELECTED;
|
||||
}
|
||||
|
||||
this.items.clear();
|
||||
|
||||
if (this.furniSource == WiredSourceUtil.SOURCE_SELECTED) {
|
||||
|
||||
+420
@@ -0,0 +1,420 @@
|
||||
package com.eu.habbo.habbohotel.items.interactions.wired.conditions;
|
||||
|
||||
import com.eu.habbo.Emulator;
|
||||
import com.eu.habbo.habbohotel.items.Item;
|
||||
import com.eu.habbo.habbohotel.items.interactions.wired.WiredSettings;
|
||||
import com.eu.habbo.habbohotel.rooms.Room;
|
||||
import com.eu.habbo.habbohotel.rooms.RoomUnit;
|
||||
import com.eu.habbo.habbohotel.rooms.WiredVariableDefinitionInfo;
|
||||
import com.eu.habbo.habbohotel.users.Habbo;
|
||||
import com.eu.habbo.habbohotel.users.HabboItem;
|
||||
import com.eu.habbo.habbohotel.wired.WiredConditionType;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredContext;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredContextVariableSupport;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredManager;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredSourceUtil;
|
||||
import com.eu.habbo.messages.ServerMessage;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class WiredConditionVariableAgeMatch extends WiredConditionHasVariable {
|
||||
public static final WiredConditionType type = WiredConditionType.VAR_AGE_MATCH;
|
||||
|
||||
private static final int TARGET_CONTEXT = 2;
|
||||
private static final int COMPARE_VALUE_CREATED = 0;
|
||||
private static final int COMPARE_VALUE_UPDATED = 1;
|
||||
private static final int COMPARISON_LOWER_THAN = 0;
|
||||
private static final int COMPARISON_HIGHER_THAN = 2;
|
||||
private static final int DURATION_UNIT_MILLISECONDS = 0;
|
||||
private static final int DURATION_UNIT_SECONDS = 1;
|
||||
private static final int DURATION_UNIT_MINUTES = 2;
|
||||
private static final int DURATION_UNIT_HOURS = 3;
|
||||
private static final int DURATION_UNIT_DAYS = 4;
|
||||
private static final int DURATION_UNIT_WEEKS = 5;
|
||||
private static final int DURATION_UNIT_MONTHS = 6;
|
||||
private static final int DURATION_UNIT_YEARS = 7;
|
||||
|
||||
protected int compareValue = COMPARE_VALUE_CREATED;
|
||||
protected int comparison = COMPARISON_LOWER_THAN;
|
||||
protected int durationAmount = 0;
|
||||
protected int durationUnit = DURATION_UNIT_SECONDS;
|
||||
|
||||
public WiredConditionVariableAgeMatch(ResultSet set, Item baseItem) throws SQLException {
|
||||
super(set, baseItem);
|
||||
}
|
||||
|
||||
public WiredConditionVariableAgeMatch(int id, int userId, Item item, String extradata, int limitedStack, int limitedSells) {
|
||||
super(id, userId, item, extradata, limitedStack, limitedSells);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WiredConditionType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serializeWiredData(ServerMessage message, Room room) {
|
||||
this.refresh();
|
||||
|
||||
List<HabboItem> serializedItems = new ArrayList<>();
|
||||
if (this.targetType == TARGET_FURNI && this.furniSource == WiredSourceUtil.SOURCE_SELECTED) {
|
||||
serializedItems.addAll(this.selectedItems);
|
||||
}
|
||||
|
||||
message.appendBoolean(false);
|
||||
message.appendInt(WiredManager.MAXIMUM_FURNI_SELECTION);
|
||||
message.appendInt(serializedItems.size());
|
||||
|
||||
for (HabboItem item : serializedItems) {
|
||||
message.appendInt(item.getId());
|
||||
}
|
||||
|
||||
message.appendInt(this.getBaseItem().getSpriteId());
|
||||
message.appendInt(this.getId());
|
||||
message.appendString(this.variableToken == null ? "" : this.variableToken);
|
||||
message.appendInt(8);
|
||||
message.appendInt(this.targetType);
|
||||
message.appendInt(this.compareValue);
|
||||
message.appendInt(this.comparison);
|
||||
message.appendInt(this.durationAmount);
|
||||
message.appendInt(this.durationUnit);
|
||||
message.appendInt(this.userSource);
|
||||
message.appendInt(this.furniSource);
|
||||
message.appendInt(this.quantifier);
|
||||
message.appendInt(0);
|
||||
message.appendInt(this.getType().code);
|
||||
message.appendInt(0);
|
||||
message.appendInt(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean saveData(WiredSettings settings) {
|
||||
int[] params = settings.getIntParams();
|
||||
Room room = Emulator.getGameEnvironment().getRoomManager().getRoom(this.getRoomId());
|
||||
|
||||
this.targetType = (params.length > 0) ? normalizeTargetTypeExtended(params[0]) : TARGET_USER;
|
||||
this.compareValue = (params.length > 1) ? normalizeCompareValue(params[1]) : COMPARE_VALUE_CREATED;
|
||||
this.comparison = (params.length > 2) ? normalizeComparison(params[2]) : COMPARISON_LOWER_THAN;
|
||||
this.durationAmount = Math.max(0, (params.length > 3) ? params[3] : 0);
|
||||
this.durationUnit = (params.length > 4) ? normalizeDurationUnit(params[4]) : DURATION_UNIT_SECONDS;
|
||||
this.userSource = (params.length > 5) ? normalizeUserSource(params[5]) : WiredSourceUtil.SOURCE_TRIGGER;
|
||||
this.furniSource = (params.length > 6) ? normalizeFurniSource(params[6]) : WiredSourceUtil.SOURCE_TRIGGER;
|
||||
this.quantifier = (params.length > 7) ? normalizeQuantifier(params[7]) : QUANTIFIER_ALL;
|
||||
this.setVariableToken(normalizeVariableToken(settings.getStringParam()));
|
||||
|
||||
if (!this.isValidSource(room)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
this.selectedItems.clear();
|
||||
|
||||
if (this.targetType == TARGET_FURNI && this.furniSource == WiredSourceUtil.SOURCE_SELECTED && room != null) {
|
||||
int[] furniIds = settings.getFurniIds();
|
||||
if (furniIds.length > Emulator.getConfig().getInt("hotel.wired.furni.selection.count")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int furniId : furniIds) {
|
||||
HabboItem item = room.getHabboItem(furniId);
|
||||
|
||||
if (item != null) {
|
||||
this.selectedItems.add(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean evaluate(WiredContext ctx) {
|
||||
Room room = ctx.room();
|
||||
|
||||
if (room == null || this.variableToken == null || this.variableToken.isEmpty() || !isCustomVariableToken(this.variableToken)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
long thresholdMs = durationToMillis(this.durationAmount, this.durationUnit);
|
||||
|
||||
return switch (this.targetType) {
|
||||
case TARGET_FURNI -> this.evaluateFurniTargets(ctx, room, thresholdMs);
|
||||
case TARGET_ROOM -> this.evaluateRoomTarget(room, thresholdMs);
|
||||
case TARGET_CONTEXT -> this.evaluateContextTarget(ctx, room, thresholdMs);
|
||||
default -> this.evaluateUserTargets(ctx, room, thresholdMs);
|
||||
};
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@Override
|
||||
public boolean execute(RoomUnit roomUnit, Room room, Object[] stuff) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getWiredData() {
|
||||
this.refresh();
|
||||
|
||||
List<Integer> itemIds = new ArrayList<>();
|
||||
for (HabboItem item : this.selectedItems) {
|
||||
if (item != null) itemIds.add(item.getId());
|
||||
}
|
||||
|
||||
return WiredManager.getGson().toJson(new JsonData(
|
||||
itemIds,
|
||||
this.targetType,
|
||||
this.variableToken,
|
||||
this.variableItemId,
|
||||
this.compareValue,
|
||||
this.comparison,
|
||||
this.durationAmount,
|
||||
this.durationUnit,
|
||||
this.userSource,
|
||||
this.furniSource,
|
||||
this.quantifier
|
||||
));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadWiredData(ResultSet set, Room room) throws SQLException {
|
||||
this.onPickUp();
|
||||
|
||||
String wiredData = set.getString("wired_data");
|
||||
if (wiredData == null || wiredData.isEmpty()) return;
|
||||
|
||||
try {
|
||||
if (wiredData.startsWith("{")) {
|
||||
JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class);
|
||||
|
||||
if (data == null) return;
|
||||
|
||||
this.targetType = normalizeTargetTypeExtended(data.targetType);
|
||||
this.compareValue = normalizeCompareValue(data.compareValue);
|
||||
this.comparison = normalizeComparison(data.comparison);
|
||||
this.durationAmount = Math.max(0, data.durationAmount);
|
||||
this.durationUnit = normalizeDurationUnit(data.durationUnit);
|
||||
this.userSource = normalizeUserSource(data.userSource);
|
||||
this.furniSource = normalizeFurniSource(data.furniSource);
|
||||
this.quantifier = normalizeQuantifier(data.quantifier);
|
||||
this.setVariableToken(normalizeVariableToken((data.variableToken != null) ? data.variableToken : ((data.variableItemId > 0) ? String.valueOf(data.variableItemId) : "")));
|
||||
|
||||
if (room != null && data.itemIds != null) {
|
||||
for (Integer itemId : data.itemIds) {
|
||||
if (itemId == null || itemId <= 0) continue;
|
||||
|
||||
HabboItem item = room.getHabboItem(itemId);
|
||||
if (item != null) this.selectedItems.add(item);
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.setVariableToken(normalizeVariableToken(wiredData));
|
||||
} catch (Exception e) {
|
||||
this.onPickUp();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPickUp() {
|
||||
super.onPickUp();
|
||||
this.compareValue = COMPARE_VALUE_CREATED;
|
||||
this.comparison = COMPARISON_LOWER_THAN;
|
||||
this.durationAmount = 0;
|
||||
this.durationUnit = DURATION_UNIT_SECONDS;
|
||||
}
|
||||
|
||||
private boolean evaluateUserTargets(WiredContext ctx, Room room, long thresholdMs) {
|
||||
List<RoomUnit> targets = WiredSourceUtil.resolveUsers(ctx, this.userSource);
|
||||
if (targets.isEmpty()) return false;
|
||||
|
||||
if (this.quantifier == QUANTIFIER_ANY) {
|
||||
for (RoomUnit roomUnit : targets) {
|
||||
if (this.matchesAge(this.readUserAgeMs(room, roomUnit), thresholdMs)) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
for (RoomUnit roomUnit : targets) {
|
||||
if (!this.matchesAge(this.readUserAgeMs(room, roomUnit), thresholdMs)) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean evaluateFurniTargets(WiredContext ctx, Room room, long thresholdMs) {
|
||||
this.refresh();
|
||||
|
||||
List<HabboItem> targets = WiredSourceUtil.resolveItems(ctx, this.furniSource, this.selectedItems);
|
||||
if (targets.isEmpty()) return false;
|
||||
|
||||
if (this.quantifier == QUANTIFIER_ANY) {
|
||||
for (HabboItem item : targets) {
|
||||
if (this.matchesAge(this.readFurniAgeMs(room, item), thresholdMs)) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
for (HabboItem item : targets) {
|
||||
if (!this.matchesAge(this.readFurniAgeMs(room, item), thresholdMs)) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean evaluateRoomTarget(Room room, long thresholdMs) {
|
||||
return this.matchesAge(this.readRoomAgeMs(room), thresholdMs);
|
||||
}
|
||||
|
||||
private boolean evaluateContextTarget(WiredContext ctx, Room room, long thresholdMs) {
|
||||
return this.matchesAge(this.readContextAgeMs(ctx, room), thresholdMs);
|
||||
}
|
||||
|
||||
private Long readUserAgeMs(Room room, RoomUnit roomUnit) {
|
||||
if (room == null || roomUnit == null) return null;
|
||||
|
||||
Habbo habbo = room.getHabbo(roomUnit);
|
||||
if (habbo == null || !room.getUserVariableManager().hasVariable(habbo.getHabboInfo().getId(), this.variableItemId)) return null;
|
||||
|
||||
int timestamp = (this.compareValue == COMPARE_VALUE_UPDATED)
|
||||
? room.getUserVariableManager().getUpdatedAt(habbo.getHabboInfo().getId(), this.variableItemId)
|
||||
: room.getUserVariableManager().getCreatedAt(habbo.getHabboInfo().getId(), this.variableItemId);
|
||||
|
||||
return timestampToAgeMs(timestamp);
|
||||
}
|
||||
|
||||
private Long readFurniAgeMs(Room room, HabboItem item) {
|
||||
if (room == null || item == null || !room.getFurniVariableManager().hasVariable(item.getId(), this.variableItemId)) return null;
|
||||
|
||||
int timestamp = (this.compareValue == COMPARE_VALUE_UPDATED)
|
||||
? room.getFurniVariableManager().getUpdatedAt(item.getId(), this.variableItemId)
|
||||
: room.getFurniVariableManager().getCreatedAt(item.getId(), this.variableItemId);
|
||||
|
||||
return timestampToAgeMs(timestamp);
|
||||
}
|
||||
|
||||
private Long readRoomAgeMs(Room room) {
|
||||
if (room == null) return null;
|
||||
if (this.compareValue == COMPARE_VALUE_CREATED) return null;
|
||||
|
||||
int timestamp = room.getRoomVariableManager().getUpdatedAt(this.variableItemId);
|
||||
return timestampToAgeMs(timestamp);
|
||||
}
|
||||
|
||||
private Long readContextAgeMs(WiredContext ctx, Room room) {
|
||||
if (ctx == null || room == null || !WiredContextVariableSupport.hasVariable(ctx, this.variableItemId)) return null;
|
||||
|
||||
int timestamp = (this.compareValue == COMPARE_VALUE_UPDATED)
|
||||
? WiredContextVariableSupport.getUpdatedAt(ctx, this.variableItemId)
|
||||
: WiredContextVariableSupport.getCreatedAt(ctx, this.variableItemId);
|
||||
|
||||
return timestampToAgeMs(timestamp);
|
||||
}
|
||||
|
||||
private boolean matchesAge(Long ageMs, long thresholdMs) {
|
||||
if (ageMs == null) return false;
|
||||
|
||||
return switch (this.comparison) {
|
||||
case COMPARISON_HIGHER_THAN -> ageMs > thresholdMs;
|
||||
default -> ageMs < thresholdMs;
|
||||
};
|
||||
}
|
||||
|
||||
private boolean isValidSource(Room room) {
|
||||
if (room == null || !isCustomVariableToken(this.variableToken)) return false;
|
||||
|
||||
return switch (this.targetType) {
|
||||
case TARGET_FURNI -> room.getFurniVariableManager().getDefinitionInfo(this.variableItemId) != null;
|
||||
case TARGET_CONTEXT -> WiredContextVariableSupport.getDefinitionInfo(room, this.variableItemId) != null;
|
||||
case TARGET_ROOM -> {
|
||||
WiredVariableDefinitionInfo definition = room.getRoomVariableManager().getDefinitionInfo(this.variableItemId);
|
||||
yield this.compareValue == COMPARE_VALUE_UPDATED && definition != null;
|
||||
}
|
||||
default -> room.getUserVariableManager().getDefinitionInfo(this.variableItemId) != null;
|
||||
};
|
||||
}
|
||||
|
||||
private static Long timestampToAgeMs(int timestampSeconds) {
|
||||
if (timestampSeconds <= 0) return null;
|
||||
|
||||
long timestampMs = (timestampSeconds * 1000L);
|
||||
return Math.max(0L, System.currentTimeMillis() - timestampMs);
|
||||
}
|
||||
|
||||
private static long durationToMillis(int amount, int unit) {
|
||||
long normalizedAmount = Math.max(0L, amount);
|
||||
|
||||
return switch (unit) {
|
||||
case DURATION_UNIT_MILLISECONDS -> normalizedAmount;
|
||||
case DURATION_UNIT_MINUTES -> safeMultiply(normalizedAmount, 60_000L);
|
||||
case DURATION_UNIT_HOURS -> safeMultiply(normalizedAmount, 3_600_000L);
|
||||
case DURATION_UNIT_DAYS -> safeMultiply(normalizedAmount, 86_400_000L);
|
||||
case DURATION_UNIT_WEEKS -> safeMultiply(normalizedAmount, 604_800_000L);
|
||||
case DURATION_UNIT_MONTHS -> safeMultiply(normalizedAmount, 2_592_000_000L);
|
||||
case DURATION_UNIT_YEARS -> safeMultiply(normalizedAmount, 31_536_000_000L);
|
||||
default -> safeMultiply(normalizedAmount, 1_000L);
|
||||
};
|
||||
}
|
||||
|
||||
private static long safeMultiply(long left, long right) {
|
||||
if (left <= 0 || right <= 0) return 0L;
|
||||
if (left > (Long.MAX_VALUE / right)) return Long.MAX_VALUE;
|
||||
|
||||
return left * right;
|
||||
}
|
||||
|
||||
private static int normalizeTargetTypeExtended(int value) {
|
||||
return switch (value) {
|
||||
case TARGET_FURNI, TARGET_CONTEXT, TARGET_ROOM -> value;
|
||||
default -> TARGET_USER;
|
||||
};
|
||||
}
|
||||
|
||||
private static int normalizeCompareValue(int value) {
|
||||
return (value == COMPARE_VALUE_UPDATED) ? COMPARE_VALUE_UPDATED : COMPARE_VALUE_CREATED;
|
||||
}
|
||||
|
||||
private static int normalizeComparison(int value) {
|
||||
return (value == COMPARISON_HIGHER_THAN) ? COMPARISON_HIGHER_THAN : COMPARISON_LOWER_THAN;
|
||||
}
|
||||
|
||||
private static int normalizeDurationUnit(int value) {
|
||||
return switch (value) {
|
||||
case DURATION_UNIT_MILLISECONDS, DURATION_UNIT_SECONDS, DURATION_UNIT_MINUTES, DURATION_UNIT_HOURS,
|
||||
DURATION_UNIT_DAYS, DURATION_UNIT_WEEKS, DURATION_UNIT_MONTHS, DURATION_UNIT_YEARS -> value;
|
||||
default -> DURATION_UNIT_SECONDS;
|
||||
};
|
||||
}
|
||||
|
||||
protected static class JsonData {
|
||||
List<Integer> itemIds;
|
||||
int targetType;
|
||||
String variableToken;
|
||||
int variableItemId;
|
||||
int compareValue;
|
||||
int comparison;
|
||||
int durationAmount;
|
||||
int durationUnit;
|
||||
int userSource;
|
||||
int furniSource;
|
||||
int quantifier;
|
||||
|
||||
JsonData(List<Integer> itemIds, int targetType, String variableToken, int variableItemId, int compareValue, int comparison, int durationAmount, int durationUnit, int userSource, int furniSource, int quantifier) {
|
||||
this.itemIds = itemIds;
|
||||
this.targetType = targetType;
|
||||
this.variableToken = variableToken;
|
||||
this.variableItemId = variableItemId;
|
||||
this.compareValue = compareValue;
|
||||
this.comparison = comparison;
|
||||
this.durationAmount = durationAmount;
|
||||
this.durationUnit = durationUnit;
|
||||
this.userSource = userSource;
|
||||
this.furniSource = furniSource;
|
||||
this.quantifier = quantifier;
|
||||
}
|
||||
}
|
||||
}
|
||||
+814
@@ -0,0 +1,814 @@
|
||||
package com.eu.habbo.habbohotel.items.interactions.wired.conditions;
|
||||
|
||||
import com.eu.habbo.Emulator;
|
||||
import com.eu.habbo.habbohotel.bots.Bot;
|
||||
import com.eu.habbo.habbohotel.games.Game;
|
||||
import com.eu.habbo.habbohotel.games.GamePlayer;
|
||||
import com.eu.habbo.habbohotel.games.GameTeam;
|
||||
import com.eu.habbo.habbohotel.games.GameTeamColors;
|
||||
import com.eu.habbo.habbohotel.games.battlebanzai.BattleBanzaiGame;
|
||||
import com.eu.habbo.habbohotel.games.freeze.FreezeGame;
|
||||
import com.eu.habbo.habbohotel.games.wired.WiredGame;
|
||||
import com.eu.habbo.habbohotel.items.Item;
|
||||
import com.eu.habbo.habbohotel.items.interactions.wired.WiredSettings;
|
||||
import com.eu.habbo.habbohotel.pets.Pet;
|
||||
import com.eu.habbo.habbohotel.rooms.Room;
|
||||
import com.eu.habbo.habbohotel.rooms.RoomUnit;
|
||||
import com.eu.habbo.habbohotel.rooms.WiredVariableDefinitionInfo;
|
||||
import com.eu.habbo.habbohotel.users.Habbo;
|
||||
import com.eu.habbo.habbohotel.users.HabboItem;
|
||||
import com.eu.habbo.habbohotel.wired.WiredConditionType;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredContext;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredContextVariableSupport;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredInternalVariableSupport;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredManager;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredSourceUtil;
|
||||
import com.eu.habbo.messages.ServerMessage;
|
||||
import com.eu.habbo.util.HotelDateTimeUtil;
|
||||
import gnu.trove.set.hash.THashSet;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.temporal.WeekFields;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
public class WiredConditionVariableValueMatch extends WiredConditionHasVariable {
|
||||
public static final WiredConditionType type = WiredConditionType.VAR_VAL_MATCH;
|
||||
|
||||
private static final int TARGET_CONTEXT = 2;
|
||||
private static final int SOURCE_SECONDARY_SELECTED = 101;
|
||||
private static final int REFERENCE_CONSTANT = 0;
|
||||
private static final int REFERENCE_VARIABLE = 1;
|
||||
private static final int COMPARISON_GREATER_THAN = 0;
|
||||
private static final int COMPARISON_GREATER_THAN_OR_EQUAL = 1;
|
||||
private static final int COMPARISON_EQUAL = 2;
|
||||
private static final int COMPARISON_LESS_THAN_OR_EQUAL = 3;
|
||||
private static final int COMPARISON_LESS_THAN = 4;
|
||||
private static final int COMPARISON_NOT_EQUAL = 5;
|
||||
private static final String DELIM = "\t";
|
||||
private static final String FURNI_DELIM = ";";
|
||||
|
||||
protected int comparison = COMPARISON_EQUAL;
|
||||
protected int referenceMode = REFERENCE_CONSTANT;
|
||||
protected int referenceConstantValue = 0;
|
||||
protected int referenceTargetType = TARGET_USER;
|
||||
protected int referenceUserSource = WiredSourceUtil.SOURCE_TRIGGER;
|
||||
protected int referenceFurniSource = WiredSourceUtil.SOURCE_TRIGGER;
|
||||
protected String referenceVariableToken = "";
|
||||
protected int referenceVariableItemId = 0;
|
||||
protected final THashSet<HabboItem> referenceSelectedItems = new THashSet<>();
|
||||
|
||||
public WiredConditionVariableValueMatch(ResultSet set, Item baseItem) throws SQLException {
|
||||
super(set, baseItem);
|
||||
}
|
||||
|
||||
public WiredConditionVariableValueMatch(int id, int userId, Item item, String extradata, int limitedStack, int limitedSells) {
|
||||
super(id, userId, item, extradata, limitedStack, limitedSells);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WiredConditionType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serializeWiredData(ServerMessage message, Room room) {
|
||||
this.refresh();
|
||||
this.refreshReferenceItems();
|
||||
|
||||
List<HabboItem> serializedItems = new ArrayList<>();
|
||||
if (this.targetType == TARGET_FURNI && this.furniSource == WiredSourceUtil.SOURCE_SELECTED) {
|
||||
serializedItems.addAll(this.selectedItems);
|
||||
}
|
||||
|
||||
message.appendBoolean(false);
|
||||
message.appendInt(WiredManager.MAXIMUM_FURNI_SELECTION);
|
||||
message.appendInt(serializedItems.size());
|
||||
|
||||
for (HabboItem item : serializedItems) {
|
||||
message.appendInt(item.getId());
|
||||
}
|
||||
|
||||
message.appendInt(this.getBaseItem().getSpriteId());
|
||||
message.appendInt(this.getId());
|
||||
message.appendString(this.serializeStringData());
|
||||
message.appendInt(10);
|
||||
message.appendInt(this.targetType);
|
||||
message.appendInt(this.comparison);
|
||||
message.appendInt(this.referenceMode);
|
||||
message.appendInt(this.referenceConstantValue);
|
||||
message.appendInt(this.referenceTargetType);
|
||||
message.appendInt(this.userSource);
|
||||
message.appendInt(this.furniSource);
|
||||
message.appendInt(this.referenceUserSource);
|
||||
message.appendInt(this.referenceFurniSource);
|
||||
message.appendInt(this.quantifier);
|
||||
message.appendInt(0);
|
||||
message.appendInt(this.getType().code);
|
||||
message.appendInt(0);
|
||||
message.appendInt(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean saveData(WiredSettings settings) {
|
||||
Room room = Emulator.getGameEnvironment().getRoomManager().getRoom(this.getRoomId());
|
||||
if (room == null) return false;
|
||||
|
||||
int[] params = settings.getIntParams();
|
||||
String[] stringParts = this.parseStringData(settings.getStringParam());
|
||||
int nextTargetType = normalizeTargetTypeExtended(param(params, 0, TARGET_USER));
|
||||
int nextComparison = normalizeComparison(param(params, 1, COMPARISON_EQUAL));
|
||||
int nextReferenceMode = normalizeReferenceMode(param(params, 2, REFERENCE_CONSTANT));
|
||||
int nextReferenceConstantValue = param(params, 3, 0);
|
||||
int nextReferenceTargetType = normalizeTargetTypeExtended(param(params, 4, TARGET_USER));
|
||||
int nextUserSource = normalizeUserSource(param(params, 5, WiredSourceUtil.SOURCE_TRIGGER));
|
||||
int nextFurniSource = normalizeFurniSource(param(params, 6, WiredSourceUtil.SOURCE_TRIGGER));
|
||||
int nextReferenceUserSource = normalizeUserSource(param(params, 7, WiredSourceUtil.SOURCE_TRIGGER));
|
||||
int nextReferenceFurniSource = normalizeReferenceFurniSource(param(params, 8, WiredSourceUtil.SOURCE_TRIGGER));
|
||||
int nextQuantifier = normalizeQuantifier(param(params, 9, QUANTIFIER_ALL));
|
||||
String nextVariableToken = normalizeVariableToken((stringParts.length > 0) ? stringParts[0] : settings.getStringParam());
|
||||
String nextReferenceVariableToken = normalizeVariableToken((stringParts.length > 1) ? stringParts[1] : "");
|
||||
|
||||
if (!this.isValidSource(room, nextTargetType, nextVariableToken)) return false;
|
||||
if (nextReferenceMode == REFERENCE_VARIABLE && !this.isValidReference(room, nextReferenceTargetType, nextReferenceVariableToken)) return false;
|
||||
|
||||
int selectionLimit = Emulator.getConfig().getInt("hotel.wired.furni.selection.count");
|
||||
List<HabboItem> nextSelectedItems = (nextTargetType == TARGET_FURNI && nextFurniSource == WiredSourceUtil.SOURCE_SELECTED)
|
||||
? this.parseItems(settings.getFurniIds(), room)
|
||||
: new ArrayList<>();
|
||||
List<HabboItem> nextReferenceItems = (nextReferenceMode == REFERENCE_VARIABLE && nextReferenceTargetType == TARGET_FURNI && nextReferenceFurniSource == SOURCE_SECONDARY_SELECTED)
|
||||
? this.parseItems((stringParts.length > 2) ? stringParts[2] : "", room)
|
||||
: new ArrayList<>();
|
||||
|
||||
if (nextSelectedItems.size() > selectionLimit || nextReferenceItems.size() > selectionLimit) return false;
|
||||
|
||||
this.selectedItems.clear();
|
||||
this.selectedItems.addAll(nextSelectedItems);
|
||||
this.referenceSelectedItems.clear();
|
||||
this.referenceSelectedItems.addAll(nextReferenceItems);
|
||||
this.targetType = nextTargetType;
|
||||
this.comparison = nextComparison;
|
||||
this.referenceMode = nextReferenceMode;
|
||||
this.referenceConstantValue = nextReferenceConstantValue;
|
||||
this.referenceTargetType = nextReferenceTargetType;
|
||||
this.userSource = nextUserSource;
|
||||
this.furniSource = nextFurniSource;
|
||||
this.referenceUserSource = nextReferenceUserSource;
|
||||
this.referenceFurniSource = nextReferenceFurniSource;
|
||||
this.quantifier = nextQuantifier;
|
||||
this.setVariableToken(nextVariableToken);
|
||||
this.setReferenceVariableToken(nextReferenceVariableToken);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean evaluate(WiredContext ctx) {
|
||||
Room room = ctx.room();
|
||||
|
||||
if (room == null || this.variableToken == null || this.variableToken.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return switch (this.targetType) {
|
||||
case TARGET_FURNI -> this.evaluateFurniTargets(ctx, room);
|
||||
case TARGET_ROOM -> this.evaluateRoomTarget(ctx, room);
|
||||
case TARGET_CONTEXT -> this.evaluateContextTarget(ctx, room);
|
||||
default -> this.evaluateUserTargets(ctx, room);
|
||||
};
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@Override
|
||||
public boolean execute(RoomUnit roomUnit, Room room, Object[] stuff) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getWiredData() {
|
||||
this.refresh();
|
||||
this.refreshReferenceItems();
|
||||
|
||||
return WiredManager.getGson().toJson(new JsonData(
|
||||
this.targetType,
|
||||
this.variableToken,
|
||||
this.variableItemId,
|
||||
this.comparison,
|
||||
this.referenceMode,
|
||||
this.referenceConstantValue,
|
||||
this.referenceTargetType,
|
||||
this.referenceVariableToken,
|
||||
this.referenceVariableItemId,
|
||||
this.userSource,
|
||||
this.furniSource,
|
||||
this.referenceUserSource,
|
||||
this.referenceFurniSource,
|
||||
this.quantifier,
|
||||
this.toIds(this.selectedItems),
|
||||
this.toIds(this.referenceSelectedItems)
|
||||
));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadWiredData(ResultSet set, Room room) throws SQLException {
|
||||
this.onPickUp();
|
||||
|
||||
String wiredData = set.getString("wired_data");
|
||||
if (wiredData == null || wiredData.isEmpty() || !wiredData.startsWith("{")) return;
|
||||
|
||||
JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class);
|
||||
if (data == null) return;
|
||||
|
||||
this.targetType = normalizeTargetTypeExtended(data.targetType);
|
||||
this.setVariableToken(normalizeVariableToken((data.variableToken != null) ? data.variableToken : ((data.variableItemId > 0) ? String.valueOf(data.variableItemId) : "")));
|
||||
this.comparison = normalizeComparison(data.comparison);
|
||||
this.referenceMode = normalizeReferenceMode(data.referenceMode);
|
||||
this.referenceConstantValue = data.referenceConstantValue;
|
||||
this.referenceTargetType = normalizeTargetTypeExtended(data.referenceTargetType);
|
||||
this.setReferenceVariableToken(normalizeVariableToken((data.referenceVariableToken != null) ? data.referenceVariableToken : ((data.referenceVariableItemId > 0) ? String.valueOf(data.referenceVariableItemId) : "")));
|
||||
this.userSource = normalizeUserSource(data.userSource);
|
||||
this.furniSource = normalizeFurniSource(data.furniSource);
|
||||
this.referenceUserSource = normalizeUserSource(data.referenceUserSource);
|
||||
this.referenceFurniSource = normalizeReferenceFurniSource(data.referenceFurniSource);
|
||||
this.quantifier = normalizeQuantifier(data.quantifier);
|
||||
|
||||
if (room == null) return;
|
||||
|
||||
this.selectedItems.addAll(this.parseItems(data.selectedItemIds, room));
|
||||
this.referenceSelectedItems.addAll(this.parseItems(data.referenceSelectedItemIds, room));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPickUp() {
|
||||
super.onPickUp();
|
||||
this.comparison = COMPARISON_EQUAL;
|
||||
this.referenceMode = REFERENCE_CONSTANT;
|
||||
this.referenceConstantValue = 0;
|
||||
this.referenceTargetType = TARGET_USER;
|
||||
this.referenceUserSource = WiredSourceUtil.SOURCE_TRIGGER;
|
||||
this.referenceFurniSource = WiredSourceUtil.SOURCE_TRIGGER;
|
||||
this.referenceSelectedItems.clear();
|
||||
this.setReferenceVariableToken("");
|
||||
}
|
||||
|
||||
public boolean requiresTriggeringUser() {
|
||||
return (this.targetType == TARGET_USER && this.userSource == WiredSourceUtil.SOURCE_TRIGGER)
|
||||
|| (this.referenceMode == REFERENCE_VARIABLE && this.referenceTargetType == TARGET_USER && this.referenceUserSource == WiredSourceUtil.SOURCE_TRIGGER);
|
||||
}
|
||||
|
||||
private boolean evaluateUserTargets(WiredContext ctx, Room room) {
|
||||
List<RoomUnit> targets = WiredSourceUtil.resolveUsers(ctx, this.userSource);
|
||||
if (targets.isEmpty()) return false;
|
||||
|
||||
ReferenceSnapshot references = this.resolveReferences(ctx, room);
|
||||
|
||||
if (this.quantifier == QUANTIFIER_ANY) {
|
||||
int index = 0;
|
||||
for (RoomUnit roomUnit : targets) {
|
||||
Integer currentValue = this.readUserValue(room, roomUnit);
|
||||
Integer referenceValue = this.referenceFor(references, roomUnit != null ? roomUnit.getId() : 0, TARGET_USER, index++);
|
||||
|
||||
if (this.matchesComparison(currentValue, referenceValue)) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int index = 0;
|
||||
for (RoomUnit roomUnit : targets) {
|
||||
Integer currentValue = this.readUserValue(room, roomUnit);
|
||||
Integer referenceValue = this.referenceFor(references, roomUnit != null ? roomUnit.getId() : 0, TARGET_USER, index++);
|
||||
|
||||
if (!this.matchesComparison(currentValue, referenceValue)) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean evaluateFurniTargets(WiredContext ctx, Room room) {
|
||||
this.refresh();
|
||||
|
||||
List<HabboItem> targets = WiredSourceUtil.resolveItems(ctx, this.furniSource, this.selectedItems);
|
||||
if (targets.isEmpty()) return false;
|
||||
|
||||
ReferenceSnapshot references = this.resolveReferences(ctx, room);
|
||||
|
||||
if (this.quantifier == QUANTIFIER_ANY) {
|
||||
int index = 0;
|
||||
for (HabboItem item : targets) {
|
||||
Integer currentValue = this.readFurniValue(room, item);
|
||||
Integer referenceValue = this.referenceFor(references, item != null ? item.getId() : 0, TARGET_FURNI, index++);
|
||||
|
||||
if (this.matchesComparison(currentValue, referenceValue)) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int index = 0;
|
||||
for (HabboItem item : targets) {
|
||||
Integer currentValue = this.readFurniValue(room, item);
|
||||
Integer referenceValue = this.referenceFor(references, item != null ? item.getId() : 0, TARGET_FURNI, index++);
|
||||
|
||||
if (!this.matchesComparison(currentValue, referenceValue)) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean evaluateRoomTarget(WiredContext ctx, Room room) {
|
||||
Integer currentValue = this.readRoomValue(room);
|
||||
Integer referenceValue = this.referenceFor(this.resolveReferences(ctx, room), room.getId(), TARGET_ROOM, 0);
|
||||
|
||||
return this.matchesComparison(currentValue, referenceValue);
|
||||
}
|
||||
|
||||
private boolean evaluateContextTarget(WiredContext ctx, Room room) {
|
||||
Integer currentValue = this.readContextTargetValue(ctx, room);
|
||||
Integer referenceValue = this.referenceFor(this.resolveReferences(ctx, room), this.variableItemId, TARGET_CONTEXT, 0);
|
||||
|
||||
return this.matchesComparison(currentValue, referenceValue);
|
||||
}
|
||||
|
||||
private ReferenceSnapshot resolveReferences(WiredContext ctx, Room room) {
|
||||
if (this.referenceMode != REFERENCE_VARIABLE) return null;
|
||||
|
||||
return switch (this.referenceTargetType) {
|
||||
case TARGET_USER -> this.userReferences(ctx, room);
|
||||
case TARGET_FURNI -> this.furniReferences(ctx, room);
|
||||
case TARGET_CONTEXT -> this.contextReferences(ctx, room);
|
||||
case TARGET_ROOM -> this.roomReferences(room);
|
||||
default -> null;
|
||||
};
|
||||
}
|
||||
|
||||
private ReferenceSnapshot userReferences(WiredContext ctx, Room room) {
|
||||
ReferenceSnapshot snapshot = new ReferenceSnapshot(TARGET_USER);
|
||||
|
||||
if (isInternalVariableToken(this.referenceVariableToken)) {
|
||||
String key = getInternalVariableKey(this.referenceVariableToken);
|
||||
if (!canUseUserInternalReference(key)) return null;
|
||||
|
||||
for (RoomUnit roomUnit : WiredSourceUtil.resolveUsers(ctx, this.referenceUserSource)) {
|
||||
Integer value = this.readUserInternalValue(room, roomUnit, key);
|
||||
if (value != null && roomUnit != null) snapshot.add(roomUnit.getId(), value);
|
||||
}
|
||||
|
||||
return snapshot.isEmpty() ? null : snapshot;
|
||||
}
|
||||
|
||||
WiredVariableDefinitionInfo definition = room.getUserVariableManager().getDefinitionInfo(this.referenceVariableItemId);
|
||||
if (definition == null || !definition.hasValue()) return null;
|
||||
|
||||
for (RoomUnit roomUnit : WiredSourceUtil.resolveUsers(ctx, this.referenceUserSource)) {
|
||||
if (roomUnit == null) continue;
|
||||
|
||||
Habbo habbo = room.getHabbo(roomUnit);
|
||||
if (habbo != null) snapshot.add(roomUnit.getId(), room.getUserVariableManager().getCurrentValue(habbo.getHabboInfo().getId(), this.referenceVariableItemId));
|
||||
}
|
||||
|
||||
return snapshot.isEmpty() ? null : snapshot;
|
||||
}
|
||||
|
||||
private ReferenceSnapshot furniReferences(WiredContext ctx, Room room) {
|
||||
int source = (this.referenceFurniSource == SOURCE_SECONDARY_SELECTED) ? WiredSourceUtil.SOURCE_SELECTED : this.referenceFurniSource;
|
||||
if (source == WiredSourceUtil.SOURCE_SELECTED) this.refreshReferenceItems();
|
||||
|
||||
ReferenceSnapshot snapshot = new ReferenceSnapshot(TARGET_FURNI);
|
||||
|
||||
if (isInternalVariableToken(this.referenceVariableToken)) {
|
||||
String key = getInternalVariableKey(this.referenceVariableToken);
|
||||
if (!canUseFurniInternalReference(key)) return null;
|
||||
|
||||
for (HabboItem item : WiredSourceUtil.resolveItems(ctx, source, this.referenceSelectedItems)) {
|
||||
Integer value = this.readFurniInternalValue(room, item, key);
|
||||
if (value != null && item != null) snapshot.add(item.getId(), value);
|
||||
}
|
||||
|
||||
return snapshot.isEmpty() ? null : snapshot;
|
||||
}
|
||||
|
||||
WiredVariableDefinitionInfo definition = room.getFurniVariableManager().getDefinitionInfo(this.referenceVariableItemId);
|
||||
if (definition == null || !definition.hasValue()) return null;
|
||||
|
||||
for (HabboItem item : WiredSourceUtil.resolveItems(ctx, source, this.referenceSelectedItems)) {
|
||||
if (item != null) snapshot.add(item.getId(), room.getFurniVariableManager().getCurrentValue(item.getId(), this.referenceVariableItemId));
|
||||
}
|
||||
|
||||
return snapshot.isEmpty() ? null : snapshot;
|
||||
}
|
||||
|
||||
private ReferenceSnapshot roomReferences(Room room) {
|
||||
ReferenceSnapshot snapshot = new ReferenceSnapshot(TARGET_ROOM);
|
||||
|
||||
if (isInternalVariableToken(this.referenceVariableToken)) {
|
||||
String key = getInternalVariableKey(this.referenceVariableToken);
|
||||
if (!canUseRoomInternalReference(key)) return null;
|
||||
|
||||
Integer value = this.readRoomInternalValue(room, key);
|
||||
if (value == null) return null;
|
||||
|
||||
snapshot.add(room.getId(), value);
|
||||
return snapshot;
|
||||
}
|
||||
|
||||
WiredVariableDefinitionInfo definition = room.getRoomVariableManager().getDefinitionInfo(this.referenceVariableItemId);
|
||||
if (definition == null || !definition.hasValue()) return null;
|
||||
|
||||
snapshot.add(room.getId(), room.getRoomVariableManager().getCurrentValue(this.referenceVariableItemId));
|
||||
return snapshot;
|
||||
}
|
||||
|
||||
private ReferenceSnapshot contextReferences(WiredContext ctx, Room room) {
|
||||
ReferenceSnapshot snapshot = new ReferenceSnapshot(TARGET_CONTEXT);
|
||||
|
||||
if (isInternalVariableToken(this.referenceVariableToken)) {
|
||||
String key = getInternalVariableKey(this.referenceVariableToken);
|
||||
if (!canUseContextInternalReference(key)) return null;
|
||||
|
||||
Integer value = WiredInternalVariableSupport.readContextValue(ctx, key);
|
||||
if (value == null) return null;
|
||||
|
||||
snapshot.add(this.referenceVariableItemId > 0 ? this.referenceVariableItemId : (room != null ? room.getId() : 0), value);
|
||||
return snapshot;
|
||||
}
|
||||
|
||||
WiredVariableDefinitionInfo definition = WiredContextVariableSupport.getDefinitionInfo(room, this.referenceVariableItemId);
|
||||
if (definition == null || !definition.hasValue() || !WiredContextVariableSupport.hasVariable(ctx, this.referenceVariableItemId)) return null;
|
||||
|
||||
Integer value = WiredContextVariableSupport.getCurrentValue(ctx, this.referenceVariableItemId);
|
||||
if (value == null) return null;
|
||||
|
||||
snapshot.add(this.referenceVariableItemId, value);
|
||||
return snapshot;
|
||||
}
|
||||
|
||||
private Integer readUserValue(Room room, RoomUnit roomUnit) {
|
||||
if (room == null || roomUnit == null) return null;
|
||||
|
||||
if (isInternalVariableToken(this.variableToken)) {
|
||||
String key = getInternalVariableKey(this.variableToken);
|
||||
return canUseUserInternalReference(key) ? this.readUserInternalValue(room, roomUnit, key) : null;
|
||||
}
|
||||
|
||||
WiredVariableDefinitionInfo definition = room.getUserVariableManager().getDefinitionInfo(this.variableItemId);
|
||||
if (definition == null || !definition.hasValue()) return null;
|
||||
|
||||
Habbo habbo = room.getHabbo(roomUnit);
|
||||
return (habbo != null) ? room.getUserVariableManager().getCurrentValue(habbo.getHabboInfo().getId(), this.variableItemId) : null;
|
||||
}
|
||||
|
||||
private Integer readFurniValue(Room room, HabboItem item) {
|
||||
if (room == null || item == null) return null;
|
||||
|
||||
if (isInternalVariableToken(this.variableToken)) {
|
||||
String key = getInternalVariableKey(this.variableToken);
|
||||
return canUseFurniInternalReference(key) ? this.readFurniInternalValue(room, item, key) : null;
|
||||
}
|
||||
|
||||
WiredVariableDefinitionInfo definition = room.getFurniVariableManager().getDefinitionInfo(this.variableItemId);
|
||||
return (definition != null && definition.hasValue()) ? room.getFurniVariableManager().getCurrentValue(item.getId(), this.variableItemId) : null;
|
||||
}
|
||||
|
||||
private Integer readRoomValue(Room room) {
|
||||
if (room == null) return null;
|
||||
|
||||
if (isInternalVariableToken(this.variableToken)) {
|
||||
String key = getInternalVariableKey(this.variableToken);
|
||||
return canUseRoomInternalReference(key) ? this.readRoomInternalValue(room, key) : null;
|
||||
}
|
||||
|
||||
WiredVariableDefinitionInfo definition = room.getRoomVariableManager().getDefinitionInfo(this.variableItemId);
|
||||
return (definition != null && definition.hasValue()) ? room.getRoomVariableManager().getCurrentValue(this.variableItemId) : null;
|
||||
}
|
||||
|
||||
private Integer readContextTargetValue(WiredContext ctx, Room room) {
|
||||
if (ctx == null || room == null) return null;
|
||||
|
||||
if (isInternalVariableToken(this.variableToken)) {
|
||||
String key = getInternalVariableKey(this.variableToken);
|
||||
return canUseContextInternalReference(key) ? WiredInternalVariableSupport.readContextValue(ctx, key) : null;
|
||||
}
|
||||
|
||||
WiredVariableDefinitionInfo definition = WiredContextVariableSupport.getDefinitionInfo(room, this.variableItemId);
|
||||
if (definition == null || !definition.hasValue() || !WiredContextVariableSupport.hasVariable(ctx, this.variableItemId)) return null;
|
||||
|
||||
return WiredContextVariableSupport.getCurrentValue(ctx, this.variableItemId);
|
||||
}
|
||||
|
||||
private Integer referenceFor(ReferenceSnapshot snapshot, int destinationEntityId, int destinationTarget, int destinationIndex) {
|
||||
if (this.referenceMode != REFERENCE_VARIABLE) return this.referenceConstantValue;
|
||||
if (snapshot == null || snapshot.isEmpty()) return null;
|
||||
if (snapshot.targetType == destinationTarget && snapshot.values.containsKey(destinationEntityId)) return snapshot.values.get(destinationEntityId);
|
||||
if (destinationIndex >= 0 && destinationIndex < snapshot.values.size()) return new ArrayList<>(snapshot.values.values()).get(destinationIndex);
|
||||
return new ArrayList<>(snapshot.values.values()).get(0);
|
||||
}
|
||||
|
||||
private boolean matchesComparison(Integer currentValue, Integer referenceValue) {
|
||||
if (currentValue == null || referenceValue == null) return false;
|
||||
|
||||
return switch (this.comparison) {
|
||||
case COMPARISON_GREATER_THAN -> currentValue > referenceValue;
|
||||
case COMPARISON_GREATER_THAN_OR_EQUAL -> currentValue >= referenceValue;
|
||||
case COMPARISON_LESS_THAN_OR_EQUAL -> currentValue <= referenceValue;
|
||||
case COMPARISON_LESS_THAN -> currentValue < referenceValue;
|
||||
case COMPARISON_NOT_EQUAL -> !currentValue.equals(referenceValue);
|
||||
default -> currentValue.equals(referenceValue);
|
||||
};
|
||||
}
|
||||
|
||||
private boolean isValidSource(Room room, int targetType, String variableToken) {
|
||||
if (variableToken == null || variableToken.isEmpty()) return false;
|
||||
|
||||
return switch (targetType) {
|
||||
case TARGET_USER -> isInternalVariableToken(variableToken)
|
||||
? canUseUserInternalReference(getInternalVariableKey(variableToken))
|
||||
: this.isValidUserCustomValue(room, getCustomItemId(variableToken));
|
||||
case TARGET_FURNI -> isInternalVariableToken(variableToken)
|
||||
? canUseFurniInternalReference(getInternalVariableKey(variableToken))
|
||||
: this.isValidFurniCustomValue(room, getCustomItemId(variableToken));
|
||||
case TARGET_CONTEXT -> isInternalVariableToken(variableToken)
|
||||
? canUseContextInternalReference(getInternalVariableKey(variableToken))
|
||||
: this.isValidContextCustomValue(room, getCustomItemId(variableToken));
|
||||
case TARGET_ROOM -> isInternalVariableToken(variableToken)
|
||||
? canUseRoomInternalReference(getInternalVariableKey(variableToken))
|
||||
: this.isValidRoomCustomValue(room, getCustomItemId(variableToken));
|
||||
default -> false;
|
||||
};
|
||||
}
|
||||
|
||||
private boolean isValidReference(Room room, int targetType, String variableToken) {
|
||||
return this.isValidSource(room, targetType, variableToken);
|
||||
}
|
||||
|
||||
private boolean isValidUserCustomValue(Room room, int variableItemId) {
|
||||
WiredVariableDefinitionInfo definition = (room != null) ? room.getUserVariableManager().getDefinitionInfo(variableItemId) : null;
|
||||
return definition != null && definition.hasValue();
|
||||
}
|
||||
|
||||
private boolean isValidFurniCustomValue(Room room, int variableItemId) {
|
||||
WiredVariableDefinitionInfo definition = (room != null) ? room.getFurniVariableManager().getDefinitionInfo(variableItemId) : null;
|
||||
return definition != null && definition.hasValue();
|
||||
}
|
||||
|
||||
private boolean isValidRoomCustomValue(Room room, int variableItemId) {
|
||||
WiredVariableDefinitionInfo definition = (room != null) ? room.getRoomVariableManager().getDefinitionInfo(variableItemId) : null;
|
||||
return definition != null && definition.hasValue();
|
||||
}
|
||||
|
||||
private boolean isValidContextCustomValue(Room room, int variableItemId) {
|
||||
WiredVariableDefinitionInfo definition = WiredContextVariableSupport.getDefinitionInfo(room, variableItemId);
|
||||
return definition != null && definition.hasValue();
|
||||
}
|
||||
|
||||
private Integer readUserInternalValue(Room room, RoomUnit roomUnit, String key) {
|
||||
return WiredInternalVariableSupport.readUserValue(room, roomUnit, key);
|
||||
}
|
||||
|
||||
private Integer readFurniInternalValue(Room room, HabboItem item, String key) {
|
||||
return WiredInternalVariableSupport.readFurniValue(room, item, key);
|
||||
}
|
||||
|
||||
private Integer readRoomInternalValue(Room room, String key) {
|
||||
return WiredInternalVariableSupport.readRoomValue(room, key);
|
||||
}
|
||||
|
||||
private Integer getUserTeamScore(Room room, Habbo habbo) {
|
||||
if (room == null || habbo == null || habbo.getHabboInfo().getGamePlayer() == null) return null;
|
||||
|
||||
Game game = this.resolveTeamGame(room, habbo);
|
||||
GamePlayer gamePlayer = habbo.getHabboInfo().getGamePlayer();
|
||||
|
||||
if (game == null || gamePlayer.getTeamColor() == null) return gamePlayer.getScore();
|
||||
|
||||
GameTeam team = game.getTeam(gamePlayer.getTeamColor());
|
||||
return (team != null) ? team.getTotalScore() : gamePlayer.getScore();
|
||||
}
|
||||
|
||||
private Integer getTeamColorId(int effectId) {
|
||||
TeamEffectData data = this.getTeamEffectData(effectId);
|
||||
return data == null ? null : data.colorId;
|
||||
}
|
||||
|
||||
private Integer getTeamTypeId(int effectId) {
|
||||
TeamEffectData data = this.getTeamEffectData(effectId);
|
||||
return data == null ? null : data.typeId;
|
||||
}
|
||||
|
||||
private int getTeamMetric(Room room, GameTeamColors color, boolean score) {
|
||||
Game game = this.resolveTeamGame(room, null);
|
||||
if (game == null || color == null) return 0;
|
||||
|
||||
GameTeam team = game.getTeam(color);
|
||||
if (team == null) return 0;
|
||||
|
||||
return score ? team.getTotalScore() : team.getMembers().size();
|
||||
}
|
||||
|
||||
private Game resolveTeamGame(Room room, Habbo habbo) {
|
||||
if (room == null) return null;
|
||||
|
||||
if (habbo != null && habbo.getHabboInfo() != null && habbo.getHabboInfo().getCurrentGame() != null) {
|
||||
Game game = room.getGame(habbo.getHabboInfo().getCurrentGame());
|
||||
if (game != null) return game;
|
||||
}
|
||||
|
||||
Game wiredGame = room.getGame(WiredGame.class);
|
||||
if (wiredGame != null) return wiredGame;
|
||||
|
||||
Game freezeGame = room.getGame(FreezeGame.class);
|
||||
if (freezeGame != null) return freezeGame;
|
||||
|
||||
return room.getGame(BattleBanzaiGame.class);
|
||||
}
|
||||
|
||||
private List<HabboItem> parseItems(int[] ids, Room room) {
|
||||
List<HabboItem> items = new ArrayList<>();
|
||||
if (ids == null || room == null) return items;
|
||||
|
||||
for (int id : ids) {
|
||||
HabboItem item = room.getHabboItem(id);
|
||||
if (item != null) items.add(item);
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
private List<HabboItem> parseItems(List<Integer> ids, Room room) {
|
||||
List<HabboItem> items = new ArrayList<>();
|
||||
if (ids == null || room == null) return items;
|
||||
|
||||
for (Integer id : ids) {
|
||||
if (id == null || id <= 0) continue;
|
||||
|
||||
HabboItem item = room.getHabboItem(id);
|
||||
if (item != null) items.add(item);
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
private List<HabboItem> parseItems(String ids, Room room) {
|
||||
List<HabboItem> items = new ArrayList<>();
|
||||
if (ids == null || ids.trim().isEmpty() || room == null) return items;
|
||||
|
||||
for (String part : ids.split("[;,\\t]")) {
|
||||
int id = parseInteger(part);
|
||||
if (id <= 0) continue;
|
||||
|
||||
HabboItem item = room.getHabboItem(id);
|
||||
if (item != null) items.add(item);
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
private void refreshReferenceItems() {
|
||||
THashSet<HabboItem> staleItems = new THashSet<>();
|
||||
Room room = Emulator.getGameEnvironment().getRoomManager().getRoom(this.getRoomId());
|
||||
|
||||
if (room == null) {
|
||||
staleItems.addAll(this.referenceSelectedItems);
|
||||
} else {
|
||||
for (HabboItem item : this.referenceSelectedItems) {
|
||||
if (item == null || item.getRoomId() != room.getId() || room.getHabboItem(item.getId()) == null) {
|
||||
staleItems.add(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.referenceSelectedItems.removeAll(staleItems);
|
||||
}
|
||||
|
||||
private String serializeStringData() {
|
||||
return (this.variableToken == null ? "" : this.variableToken) + DELIM + (this.referenceVariableToken == null ? "" : this.referenceVariableToken) + DELIM + this.serializeIds(this.referenceSelectedItems);
|
||||
}
|
||||
|
||||
private String[] parseStringData(String value) {
|
||||
return (value == null || value.isEmpty()) ? new String[0] : value.split("\\t", -1);
|
||||
}
|
||||
|
||||
private List<Integer> toIds(THashSet<HabboItem> items) {
|
||||
List<Integer> ids = new ArrayList<>();
|
||||
for (HabboItem item : items) {
|
||||
if (item != null) ids.add(item.getId());
|
||||
}
|
||||
return ids;
|
||||
}
|
||||
|
||||
private String serializeIds(THashSet<HabboItem> items) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
for (HabboItem item : items) {
|
||||
if (item == null) continue;
|
||||
if (builder.length() > 0) builder.append(FURNI_DELIM);
|
||||
builder.append(item.getId());
|
||||
}
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
private void setReferenceVariableToken(String token) {
|
||||
this.referenceVariableToken = normalizeVariableToken(token);
|
||||
this.referenceVariableItemId = getCustomItemId(this.referenceVariableToken);
|
||||
}
|
||||
|
||||
private static boolean canUseUserInternalReference(String key) {
|
||||
return WiredInternalVariableSupport.canUseUserReference(key);
|
||||
}
|
||||
|
||||
private static boolean canUseFurniInternalReference(String key) {
|
||||
return WiredInternalVariableSupport.canUseFurniReference(key);
|
||||
}
|
||||
|
||||
private static boolean canUseRoomInternalReference(String key) {
|
||||
return WiredInternalVariableSupport.canUseRoomReference(key);
|
||||
}
|
||||
|
||||
private static boolean canUseContextInternalReference(String key) {
|
||||
return WiredInternalVariableSupport.canUseContextReference(key);
|
||||
}
|
||||
|
||||
private static int param(int[] params, int index, int fallback) {
|
||||
return (params.length > index) ? params[index] : fallback;
|
||||
}
|
||||
|
||||
private static int normalizeTargetTypeExtended(int value) {
|
||||
return switch (value) {
|
||||
case TARGET_FURNI, TARGET_CONTEXT, TARGET_ROOM -> value;
|
||||
default -> TARGET_USER;
|
||||
};
|
||||
}
|
||||
|
||||
private static int normalizeReferenceMode(int value) {
|
||||
return (value == REFERENCE_VARIABLE) ? REFERENCE_VARIABLE : REFERENCE_CONSTANT;
|
||||
}
|
||||
|
||||
private static int normalizeReferenceFurniSource(int value) {
|
||||
return switch (value) {
|
||||
case SOURCE_SECONDARY_SELECTED, WiredSourceUtil.SOURCE_SELECTOR, WiredSourceUtil.SOURCE_SIGNAL -> value;
|
||||
default -> WiredSourceUtil.SOURCE_TRIGGER;
|
||||
};
|
||||
}
|
||||
|
||||
private static int normalizeComparison(int value) {
|
||||
return switch (value) {
|
||||
case COMPARISON_GREATER_THAN, COMPARISON_GREATER_THAN_OR_EQUAL, COMPARISON_LESS_THAN_OR_EQUAL, COMPARISON_LESS_THAN, COMPARISON_NOT_EQUAL -> value;
|
||||
default -> COMPARISON_EQUAL;
|
||||
};
|
||||
}
|
||||
|
||||
private static int parseInteger(String value) {
|
||||
try {
|
||||
return (value == null || value.trim().isEmpty()) ? 0 : Integer.parseInt(value.trim());
|
||||
} catch (NumberFormatException e) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static class JsonData {
|
||||
int targetType, variableItemId, comparison, referenceMode, referenceConstantValue, referenceTargetType, referenceVariableItemId, userSource, furniSource, referenceUserSource, referenceFurniSource, quantifier;
|
||||
String variableToken, referenceVariableToken;
|
||||
List<Integer> selectedItemIds, referenceSelectedItemIds;
|
||||
|
||||
JsonData(int targetType, String variableToken, int variableItemId, int comparison, int referenceMode, int referenceConstantValue, int referenceTargetType, String referenceVariableToken, int referenceVariableItemId, int userSource, int furniSource, int referenceUserSource, int referenceFurniSource, int quantifier, List<Integer> selectedItemIds, List<Integer> referenceSelectedItemIds) {
|
||||
this.targetType = targetType;
|
||||
this.variableToken = variableToken;
|
||||
this.variableItemId = variableItemId;
|
||||
this.comparison = comparison;
|
||||
this.referenceMode = referenceMode;
|
||||
this.referenceConstantValue = referenceConstantValue;
|
||||
this.referenceTargetType = referenceTargetType;
|
||||
this.referenceVariableToken = referenceVariableToken;
|
||||
this.referenceVariableItemId = referenceVariableItemId;
|
||||
this.userSource = userSource;
|
||||
this.furniSource = furniSource;
|
||||
this.referenceUserSource = referenceUserSource;
|
||||
this.referenceFurniSource = referenceFurniSource;
|
||||
this.quantifier = quantifier;
|
||||
this.selectedItemIds = selectedItemIds;
|
||||
this.referenceSelectedItemIds = referenceSelectedItemIds;
|
||||
}
|
||||
}
|
||||
|
||||
private static class ReferenceSnapshot {
|
||||
final int targetType;
|
||||
final LinkedHashMap<Integer, Integer> values = new LinkedHashMap<>();
|
||||
|
||||
ReferenceSnapshot(int targetType) {
|
||||
this.targetType = targetType;
|
||||
}
|
||||
|
||||
void add(int entityId, int value) {
|
||||
this.values.put(entityId, value);
|
||||
}
|
||||
|
||||
boolean isEmpty() {
|
||||
return this.values.isEmpty();
|
||||
}
|
||||
}
|
||||
}
|
||||
+17
-4
@@ -3,12 +3,14 @@ package com.eu.habbo.habbohotel.items.interactions.wired.effects;
|
||||
import com.eu.habbo.Emulator;
|
||||
import com.eu.habbo.habbohotel.items.Item;
|
||||
import com.eu.habbo.habbohotel.rooms.Room;
|
||||
import com.eu.habbo.habbohotel.rooms.RoomUnit;
|
||||
import com.eu.habbo.habbohotel.users.Habbo;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredContext;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredTextPlaceholderUtil;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
|
||||
public class WiredEffectAlert extends WiredEffectWhisper {
|
||||
public WiredEffectAlert(ResultSet set, Item baseItem) throws SQLException {
|
||||
@@ -22,14 +24,25 @@ public class WiredEffectAlert extends WiredEffectWhisper {
|
||||
@Override
|
||||
public void execute(WiredContext ctx) {
|
||||
Room room = ctx.room();
|
||||
List<RoomUnit> sourceUsers = resolveUsers(ctx);
|
||||
List<Habbo> recipients = resolveRecipients(ctx, sourceUsers);
|
||||
Habbo sharedSourceHabbo = (this.visibilitySelection == VISIBILITY_ALL_ROOM_USERS)
|
||||
? resolveMessageSourceHabbo(ctx, sourceUsers)
|
||||
: null;
|
||||
|
||||
for (com.eu.habbo.habbohotel.rooms.RoomUnit unit : resolveUsers(ctx)) {
|
||||
Habbo habbo = room.getHabbo(unit);
|
||||
if (habbo == null) continue;
|
||||
for (Habbo habbo : recipients) {
|
||||
if (!shouldDeliverToRecipient(ctx, habbo)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Habbo referenceHabbo = (sharedSourceHabbo != null) ? sharedSourceHabbo : habbo;
|
||||
String username = (referenceHabbo != null && referenceHabbo.getHabboInfo() != null)
|
||||
? referenceHabbo.getHabboInfo().getUsername()
|
||||
: "";
|
||||
|
||||
String message = this.message
|
||||
.replace("%online%", Emulator.getGameEnvironment().getHabboManager().getOnlineCount() + "")
|
||||
.replace("%username%", habbo.getHabboInfo().getUsername())
|
||||
.replace("%username%", username)
|
||||
.replace("%roomsloaded%", Emulator.getGameEnvironment().getRoomManager().loadedRoomsCount() + "");
|
||||
habbo.alert(WiredTextPlaceholderUtil.applyUsernamePlaceholders(ctx, message));
|
||||
}
|
||||
|
||||
+4
@@ -133,6 +133,10 @@ public class WiredEffectBotTeleport extends InteractionWiredEffect {
|
||||
throw new WiredSaveException("Too many furni selected");
|
||||
}
|
||||
|
||||
if (itemsCount > 0 && this.furniSource == WiredSourceUtil.SOURCE_TRIGGER) {
|
||||
this.furniSource = WiredSourceUtil.SOURCE_SELECTED;
|
||||
}
|
||||
|
||||
List<HabboItem> newItems = new ArrayList<>();
|
||||
|
||||
if (this.furniSource == WiredSourceUtil.SOURCE_SELECTED) {
|
||||
|
||||
+4
@@ -85,6 +85,10 @@ public class WiredEffectBotWalkToFurni extends InteractionWiredEffect {
|
||||
throw new WiredSaveException("Too many furni selected");
|
||||
}
|
||||
|
||||
if (itemsCount > 0 && this.furniSource == WiredSourceUtil.SOURCE_TRIGGER) {
|
||||
this.furniSource = WiredSourceUtil.SOURCE_SELECTED;
|
||||
}
|
||||
|
||||
List<HabboItem> newItems = new ArrayList<>();
|
||||
|
||||
if (this.furniSource == WiredSourceUtil.SOURCE_SELECTED) {
|
||||
|
||||
+4
@@ -290,6 +290,10 @@ public class WiredEffectChangeFurniDirection extends InteractionWiredEffect {
|
||||
throw new WiredSaveException("Too many furni selected");
|
||||
}
|
||||
|
||||
if (itemsCount > 0 && this.furniSource == WiredSourceUtil.SOURCE_TRIGGER) {
|
||||
this.furniSource = WiredSourceUtil.SOURCE_SELECTED;
|
||||
}
|
||||
|
||||
THashMap<HabboItem, WiredChangeDirectionSetting> newItems = new THashMap<>();
|
||||
|
||||
for (int i = 0; i < itemsCount; i++) {
|
||||
|
||||
+946
@@ -0,0 +1,946 @@
|
||||
package com.eu.habbo.habbohotel.items.interactions.wired.effects;
|
||||
|
||||
import com.eu.habbo.Emulator;
|
||||
import com.eu.habbo.habbohotel.bots.Bot;
|
||||
import com.eu.habbo.habbohotel.gameclients.GameClient;
|
||||
import com.eu.habbo.habbohotel.games.Game;
|
||||
import com.eu.habbo.habbohotel.games.GamePlayer;
|
||||
import com.eu.habbo.habbohotel.games.GameTeam;
|
||||
import com.eu.habbo.habbohotel.games.GameTeamColors;
|
||||
import com.eu.habbo.habbohotel.games.battlebanzai.BattleBanzaiGame;
|
||||
import com.eu.habbo.habbohotel.games.freeze.FreezeGame;
|
||||
import com.eu.habbo.habbohotel.games.wired.WiredGame;
|
||||
import com.eu.habbo.habbohotel.items.FurnitureType;
|
||||
import com.eu.habbo.habbohotel.items.Item;
|
||||
import com.eu.habbo.habbohotel.items.interactions.InteractionWiredEffect;
|
||||
import com.eu.habbo.habbohotel.items.interactions.wired.WiredSettings;
|
||||
import com.eu.habbo.habbohotel.pets.Pet;
|
||||
import com.eu.habbo.habbohotel.rooms.FurnitureMovementError;
|
||||
import com.eu.habbo.habbohotel.rooms.Room;
|
||||
import com.eu.habbo.habbohotel.rooms.RoomTile;
|
||||
import com.eu.habbo.habbohotel.rooms.RoomTileState;
|
||||
import com.eu.habbo.habbohotel.rooms.RoomUnit;
|
||||
import com.eu.habbo.habbohotel.rooms.RoomUserRotation;
|
||||
import com.eu.habbo.habbohotel.rooms.WiredVariableDefinitionInfo;
|
||||
import com.eu.habbo.habbohotel.users.Habbo;
|
||||
import com.eu.habbo.habbohotel.users.HabboItem;
|
||||
import com.eu.habbo.habbohotel.wired.WiredEffectType;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredContext;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredContextVariableSupport;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredInternalVariableSupport;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredManager;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredSourceUtil;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredUserMovementHelper;
|
||||
import com.eu.habbo.messages.ServerMessage;
|
||||
import com.eu.habbo.messages.incoming.wired.WiredSaveException;
|
||||
import com.eu.habbo.messages.outgoing.rooms.users.RoomUserStatusComposer;
|
||||
import com.eu.habbo.util.HotelDateTimeUtil;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.temporal.WeekFields;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
public class WiredEffectChangeVariableValue extends InteractionWiredEffect {
|
||||
public static final WiredEffectType type = WiredEffectType.CHANGE_VAR_VAL;
|
||||
public static final int TARGET_USER = 0, TARGET_FURNI = 1, TARGET_CONTEXT = 2, TARGET_ROOM = 3;
|
||||
public static final int REF_CONSTANT = 0, REF_VARIABLE = 1;
|
||||
public static final int OP_ASSIGN = 0, OP_ADD = 1, OP_SUB = 2, OP_MUL = 3, OP_DIV = 4, OP_POW = 5, OP_MOD = 6, OP_MIN = 40, OP_MAX = 41, OP_RANDOM = 50, OP_ABS = 60, OP_AND = 100, OP_OR = 101, OP_XOR = 102, OP_NOT = 103, OP_LSHIFT = 104, OP_RSHIFT = 105;
|
||||
|
||||
private static final int SOURCE_SECONDARY_SELECTED = 101;
|
||||
private static final String DELIM = "\t", FURNI_DELIM = ";";
|
||||
private static final String CUSTOM_TOKEN_PREFIX = "custom:";
|
||||
private static final String INTERNAL_TOKEN_PREFIX = "internal:";
|
||||
|
||||
private int destinationTargetType = TARGET_USER, destinationVariableItemId = 0, operation = OP_ASSIGN, referenceMode = REF_CONSTANT, referenceConstantValue = 0, referenceTargetType = TARGET_USER, referenceVariableItemId = 0, destinationUserSource = WiredSourceUtil.SOURCE_TRIGGER, destinationFurniSource = WiredSourceUtil.SOURCE_TRIGGER, referenceUserSource = WiredSourceUtil.SOURCE_TRIGGER, referenceFurniSource = WiredSourceUtil.SOURCE_TRIGGER;
|
||||
private String destinationVariableToken = "", referenceVariableToken = "";
|
||||
private final List<HabboItem> destinationSelectedFurni = new ArrayList<>();
|
||||
private final List<HabboItem> referenceSelectedFurni = new ArrayList<>();
|
||||
|
||||
public WiredEffectChangeVariableValue(ResultSet set, Item baseItem) throws SQLException {
|
||||
super(set, baseItem);
|
||||
}
|
||||
|
||||
public WiredEffectChangeVariableValue(int id, int userId, Item item, String extradata, int limitedStack, int limitedSells) {
|
||||
super(id, userId, item, extradata, limitedStack, limitedSells);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(WiredContext ctx) {
|
||||
Room room = ctx.room();
|
||||
if (room == null) return;
|
||||
|
||||
switch (this.destinationTargetType) {
|
||||
case TARGET_USER -> this.executeUsers(ctx, room);
|
||||
case TARGET_FURNI -> this.executeFurni(ctx, room);
|
||||
case TARGET_CONTEXT -> this.executeContext(ctx, room);
|
||||
case TARGET_ROOM -> this.executeRoom(ctx, room);
|
||||
}
|
||||
}
|
||||
|
||||
private void executeUsers(WiredContext ctx, Room room) {
|
||||
if (isInternalVariableToken(this.destinationVariableToken)) {
|
||||
this.executeUsersInternal(ctx, room, getInternalVariableKey(this.destinationVariableToken));
|
||||
return;
|
||||
}
|
||||
|
||||
WiredVariableDefinitionInfo definition = room.getUserVariableManager().getDefinitionInfo(this.destinationVariableItemId);
|
||||
if (definition == null || !definition.hasValue() || definition.isReadOnly()) return;
|
||||
|
||||
ReferenceSnapshot references = this.resolveReferences(ctx, room);
|
||||
int index = 0;
|
||||
|
||||
for (RoomUnit roomUnit : WiredSourceUtil.resolveUsers(ctx, this.destinationUserSource)) {
|
||||
if (roomUnit == null) continue;
|
||||
|
||||
Habbo habbo = room.getHabbo(roomUnit);
|
||||
if (habbo == null) continue;
|
||||
|
||||
Integer referenceValue = this.referenceFor(references, roomUnit.getId(), TARGET_USER, index++);
|
||||
if (!this.isUnaryOperation() && referenceValue == null) continue;
|
||||
|
||||
int currentValue = room.getUserVariableManager().getCurrentValue(habbo.getHabboInfo().getId(), this.destinationVariableItemId);
|
||||
room.getUserVariableManager().updateVariableValue(habbo.getHabboInfo().getId(), this.destinationVariableItemId, this.applyOperation(currentValue, referenceValue));
|
||||
}
|
||||
}
|
||||
|
||||
private void executeUsersInternal(WiredContext ctx, Room room, String key) {
|
||||
if (!canUseUserInternalDestination(key)) return;
|
||||
|
||||
ReferenceSnapshot references = this.resolveReferences(ctx, room);
|
||||
int index = 0;
|
||||
|
||||
for (RoomUnit roomUnit : WiredSourceUtil.resolveUsers(ctx, this.destinationUserSource)) {
|
||||
if (roomUnit == null) continue;
|
||||
|
||||
Integer currentValue = this.readUserInternalValue(room, roomUnit, key);
|
||||
if (currentValue == null) continue;
|
||||
|
||||
Integer referenceValue = this.referenceFor(references, roomUnit.getId(), TARGET_USER, index++);
|
||||
if (!this.isUnaryOperation() && referenceValue == null) continue;
|
||||
|
||||
this.writeUserInternalValue(room, roomUnit, key, this.applyOperation(currentValue, referenceValue));
|
||||
}
|
||||
}
|
||||
|
||||
private void executeFurni(WiredContext ctx, Room room) {
|
||||
if (isInternalVariableToken(this.destinationVariableToken)) {
|
||||
this.executeFurniInternal(ctx, room, getInternalVariableKey(this.destinationVariableToken));
|
||||
return;
|
||||
}
|
||||
|
||||
WiredVariableDefinitionInfo definition = room.getFurniVariableManager().getDefinitionInfo(this.destinationVariableItemId);
|
||||
if (definition == null || !definition.hasValue() || definition.isReadOnly()) return;
|
||||
if (this.destinationFurniSource == WiredSourceUtil.SOURCE_SELECTED) this.validateItems(this.destinationSelectedFurni);
|
||||
|
||||
ReferenceSnapshot references = this.resolveReferences(ctx, room);
|
||||
int index = 0;
|
||||
|
||||
for (HabboItem item : WiredSourceUtil.resolveItems(ctx, this.destinationFurniSource, this.destinationSelectedFurni)) {
|
||||
if (item == null) continue;
|
||||
|
||||
Integer referenceValue = this.referenceFor(references, item.getId(), TARGET_FURNI, index++);
|
||||
if (!this.isUnaryOperation() && referenceValue == null) continue;
|
||||
|
||||
int currentValue = room.getFurniVariableManager().getCurrentValue(item.getId(), this.destinationVariableItemId);
|
||||
room.getFurniVariableManager().updateVariableValue(item.getId(), this.destinationVariableItemId, this.applyOperation(currentValue, referenceValue));
|
||||
}
|
||||
}
|
||||
|
||||
private void executeFurniInternal(WiredContext ctx, Room room, String key) {
|
||||
if (!canUseFurniInternalDestination(key)) return;
|
||||
if (this.destinationFurniSource == WiredSourceUtil.SOURCE_SELECTED) this.validateItems(this.destinationSelectedFurni);
|
||||
|
||||
ReferenceSnapshot references = this.resolveReferences(ctx, room);
|
||||
int index = 0;
|
||||
|
||||
for (HabboItem item : WiredSourceUtil.resolveItems(ctx, this.destinationFurniSource, this.destinationSelectedFurni)) {
|
||||
if (item == null) continue;
|
||||
|
||||
Integer currentValue = this.readFurniInternalValue(room, item, key);
|
||||
if (currentValue == null) continue;
|
||||
|
||||
Integer referenceValue = this.referenceFor(references, item.getId(), TARGET_FURNI, index++);
|
||||
if (!this.isUnaryOperation() && referenceValue == null) continue;
|
||||
|
||||
this.writeFurniInternalValue(room, item, key, this.applyOperation(currentValue, referenceValue));
|
||||
}
|
||||
}
|
||||
|
||||
private void executeRoom(WiredContext ctx, Room room) {
|
||||
if (isInternalVariableToken(this.destinationVariableToken)) return;
|
||||
|
||||
WiredVariableDefinitionInfo definition = room.getRoomVariableManager().getDefinitionInfo(this.destinationVariableItemId);
|
||||
if (definition == null || !definition.hasValue() || definition.isReadOnly()) return;
|
||||
|
||||
ReferenceSnapshot references = this.resolveReferences(ctx, room);
|
||||
Integer referenceValue = this.referenceFor(references, room.getId(), TARGET_ROOM, 0);
|
||||
if (!this.isUnaryOperation() && referenceValue == null) return;
|
||||
|
||||
int currentValue = room.getRoomVariableManager().getCurrentValue(this.destinationVariableItemId);
|
||||
room.getRoomVariableManager().updateVariableValue(this.destinationVariableItemId, this.applyOperation(currentValue, referenceValue));
|
||||
}
|
||||
|
||||
private void executeContext(WiredContext ctx, Room room) {
|
||||
if (isInternalVariableToken(this.destinationVariableToken)) return;
|
||||
|
||||
WiredVariableDefinitionInfo definition = WiredContextVariableSupport.getDefinitionInfo(room, this.destinationVariableItemId);
|
||||
if (definition == null || !definition.hasValue() || definition.isReadOnly()) return;
|
||||
|
||||
ReferenceSnapshot references = this.resolveReferences(ctx, room);
|
||||
Integer referenceValue = this.referenceFor(references, this.destinationVariableItemId, TARGET_CONTEXT, 0);
|
||||
if (!this.isUnaryOperation() && referenceValue == null) return;
|
||||
if (!WiredContextVariableSupport.hasVariable(ctx, this.destinationVariableItemId)) return;
|
||||
|
||||
Integer currentValue = WiredContextVariableSupport.getCurrentValue(ctx, this.destinationVariableItemId);
|
||||
int nextValue = this.applyOperation(currentValue != null ? currentValue : 0, referenceValue);
|
||||
WiredContextVariableSupport.updateVariableValue(ctx, room, this.destinationVariableItemId, nextValue);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@Override
|
||||
public boolean execute(RoomUnit roomUnit, Room room, Object[] stuff) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serializeWiredData(ServerMessage message, Room room) {
|
||||
this.validateItems(this.destinationSelectedFurni);
|
||||
this.validateItems(this.referenceSelectedFurni);
|
||||
|
||||
List<HabboItem> selectedItems = new ArrayList<>();
|
||||
if (this.destinationTargetType == TARGET_FURNI && this.destinationFurniSource == WiredSourceUtil.SOURCE_SELECTED) selectedItems.addAll(this.destinationSelectedFurni);
|
||||
|
||||
message.appendBoolean(false);
|
||||
message.appendInt(WiredManager.MAXIMUM_FURNI_SELECTION);
|
||||
message.appendInt(selectedItems.size());
|
||||
for (HabboItem item : selectedItems) message.appendInt(item.getId());
|
||||
message.appendInt(this.getBaseItem().getSpriteId());
|
||||
message.appendInt(this.getId());
|
||||
message.appendString(this.serializeStringData());
|
||||
message.appendInt(9);
|
||||
message.appendInt(this.destinationTargetType);
|
||||
message.appendInt(this.operation);
|
||||
message.appendInt(this.referenceMode);
|
||||
message.appendInt(this.referenceConstantValue);
|
||||
message.appendInt(this.referenceTargetType);
|
||||
message.appendInt(this.destinationUserSource);
|
||||
message.appendInt(this.destinationFurniSource);
|
||||
message.appendInt(this.referenceUserSource);
|
||||
message.appendInt(this.referenceFurniSource);
|
||||
message.appendInt(0);
|
||||
message.appendInt(this.getType().code);
|
||||
message.appendInt(this.getDelay());
|
||||
message.appendInt(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean saveData(WiredSettings settings, GameClient gameClient) throws WiredSaveException {
|
||||
Room room = this.getRoom();
|
||||
if (room == null) throw new WiredSaveException("Room not found");
|
||||
|
||||
int[] params = settings.getIntParams();
|
||||
String[] stringParts = this.parseStringData(settings.getStringParam());
|
||||
int nextDestinationTargetType = normalizeTargetType(param(params, 0, TARGET_USER));
|
||||
int nextOperation = normalizeOperation(param(params, 1, OP_ASSIGN));
|
||||
int nextReferenceMode = normalizeReferenceMode(param(params, 2, REF_CONSTANT));
|
||||
int nextReferenceConstantValue = param(params, 3, 0);
|
||||
int nextReferenceTargetType = normalizeTargetType(param(params, 4, TARGET_USER));
|
||||
int nextDestinationUserSource = normalizeUserSource(param(params, 5, WiredSourceUtil.SOURCE_TRIGGER));
|
||||
int nextDestinationFurniSource = normalizeDestinationFurniSource(param(params, 6, WiredSourceUtil.SOURCE_TRIGGER));
|
||||
int nextReferenceUserSource = normalizeUserSource(param(params, 7, WiredSourceUtil.SOURCE_TRIGGER));
|
||||
int nextReferenceFurniSource = normalizeReferenceFurniSource(param(params, 8, WiredSourceUtil.SOURCE_TRIGGER));
|
||||
String nextDestinationVariableToken = normalizeVariableToken((stringParts.length > 0) ? stringParts[0] : "");
|
||||
String nextReferenceVariableToken = normalizeVariableToken((stringParts.length > 1) ? stringParts[1] : "");
|
||||
|
||||
this.validateDestination(room, nextDestinationTargetType, nextDestinationVariableToken);
|
||||
if (nextReferenceMode == REF_VARIABLE) this.validateReference(room, nextReferenceTargetType, nextReferenceVariableToken);
|
||||
|
||||
int maxDelay = Emulator.getConfig().getInt("hotel.wired.max_delay", 20);
|
||||
if (settings.getDelay() > maxDelay) throw new WiredSaveException("Delay too long");
|
||||
|
||||
List<HabboItem> nextDestinationItems = (nextDestinationTargetType == TARGET_FURNI && nextDestinationFurniSource == WiredSourceUtil.SOURCE_SELECTED) ? this.parseItems(settings.getFurniIds(), room) : new ArrayList<>();
|
||||
List<HabboItem> nextReferenceItems = (nextReferenceMode == REF_VARIABLE && nextReferenceTargetType == TARGET_FURNI && nextReferenceFurniSource == SOURCE_SECONDARY_SELECTED) ? this.parseItems((stringParts.length > 2) ? stringParts[2] : "", room) : new ArrayList<>();
|
||||
int selectionLimit = Emulator.getConfig().getInt("hotel.wired.furni.selection.count");
|
||||
if (nextDestinationItems.size() > selectionLimit || nextReferenceItems.size() > selectionLimit) throw new WiredSaveException("Too many furni selected");
|
||||
|
||||
this.destinationSelectedFurni.clear();
|
||||
this.destinationSelectedFurni.addAll(nextDestinationItems);
|
||||
this.referenceSelectedFurni.clear();
|
||||
this.referenceSelectedFurni.addAll(nextReferenceItems);
|
||||
this.destinationTargetType = nextDestinationTargetType;
|
||||
this.setDestinationVariableToken(nextDestinationVariableToken);
|
||||
this.operation = nextOperation;
|
||||
this.referenceMode = nextReferenceMode;
|
||||
this.referenceConstantValue = nextReferenceConstantValue;
|
||||
this.referenceTargetType = nextReferenceTargetType;
|
||||
this.setReferenceVariableToken(nextReferenceVariableToken);
|
||||
this.destinationUserSource = nextDestinationUserSource;
|
||||
this.destinationFurniSource = nextDestinationFurniSource;
|
||||
this.referenceUserSource = nextReferenceUserSource;
|
||||
this.referenceFurniSource = nextReferenceFurniSource;
|
||||
this.setDelay(settings.getDelay());
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getWiredData() {
|
||||
return WiredManager.getGson().toJson(new JsonData(this.destinationTargetType, this.destinationVariableToken, this.destinationVariableItemId, this.operation, this.referenceMode, this.referenceConstantValue, this.referenceTargetType, this.referenceVariableToken, this.referenceVariableItemId, this.destinationUserSource, this.destinationFurniSource, this.referenceUserSource, this.referenceFurniSource, this.getDelay(), this.toIds(this.destinationSelectedFurni), this.toIds(this.referenceSelectedFurni)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadWiredData(ResultSet set, Room room) throws SQLException {
|
||||
this.onPickUp();
|
||||
String wiredData = set.getString("wired_data");
|
||||
if (wiredData == null || wiredData.isEmpty() || !wiredData.startsWith("{")) return;
|
||||
|
||||
JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class);
|
||||
if (data == null) return;
|
||||
|
||||
this.destinationTargetType = normalizeTargetType(data.destinationTargetType);
|
||||
this.setDestinationVariableToken(normalizeVariableToken((data.destinationVariableToken != null) ? data.destinationVariableToken : ((data.destinationVariableItemId > 0) ? String.valueOf(data.destinationVariableItemId) : "")));
|
||||
this.operation = normalizeOperation(data.operation);
|
||||
this.referenceMode = normalizeReferenceMode(data.referenceMode);
|
||||
this.referenceConstantValue = data.referenceConstantValue;
|
||||
this.referenceTargetType = normalizeTargetType(data.referenceTargetType);
|
||||
this.setReferenceVariableToken(normalizeVariableToken((data.referenceVariableToken != null) ? data.referenceVariableToken : ((data.referenceVariableItemId > 0) ? String.valueOf(data.referenceVariableItemId) : "")));
|
||||
this.destinationUserSource = normalizeUserSource(data.destinationUserSource);
|
||||
this.destinationFurniSource = normalizeDestinationFurniSource(data.destinationFurniSource);
|
||||
this.referenceUserSource = normalizeUserSource(data.referenceUserSource);
|
||||
this.referenceFurniSource = normalizeReferenceFurniSource(data.referenceFurniSource);
|
||||
this.setDelay(Math.max(0, data.delay));
|
||||
|
||||
if (room != null) {
|
||||
try {
|
||||
this.destinationSelectedFurni.addAll(this.parseItems(data.destinationSelectedFurniIds, room));
|
||||
this.referenceSelectedFurni.addAll(this.parseItems(data.referenceSelectedFurniIds, room));
|
||||
} catch (WiredSaveException ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPickUp() {
|
||||
this.destinationTargetType = TARGET_USER;
|
||||
this.setDestinationVariableToken("");
|
||||
this.operation = OP_ASSIGN;
|
||||
this.referenceMode = REF_CONSTANT;
|
||||
this.referenceConstantValue = 0;
|
||||
this.referenceTargetType = TARGET_USER;
|
||||
this.setReferenceVariableToken("");
|
||||
this.destinationUserSource = WiredSourceUtil.SOURCE_TRIGGER;
|
||||
this.destinationFurniSource = WiredSourceUtil.SOURCE_TRIGGER;
|
||||
this.referenceUserSource = WiredSourceUtil.SOURCE_TRIGGER;
|
||||
this.referenceFurniSource = WiredSourceUtil.SOURCE_TRIGGER;
|
||||
this.destinationSelectedFurni.clear();
|
||||
this.referenceSelectedFurni.clear();
|
||||
this.setDelay(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWalk(RoomUnit roomUnit, Room room, Object[] objects) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public WiredEffectType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean requiresTriggeringUser() {
|
||||
return (this.destinationTargetType == TARGET_USER && this.destinationUserSource == WiredSourceUtil.SOURCE_TRIGGER)
|
||||
|| (this.referenceMode == REF_VARIABLE && this.referenceTargetType == TARGET_USER && this.referenceUserSource == WiredSourceUtil.SOURCE_TRIGGER);
|
||||
}
|
||||
|
||||
private ReferenceSnapshot resolveReferences(WiredContext ctx, Room room) {
|
||||
if (this.referenceMode != REF_VARIABLE) return null;
|
||||
|
||||
return switch (this.referenceTargetType) {
|
||||
case TARGET_USER -> this.userReferences(ctx, room);
|
||||
case TARGET_FURNI -> this.furniReferences(ctx, room);
|
||||
case TARGET_CONTEXT -> this.contextReferences(ctx, room);
|
||||
case TARGET_ROOM -> this.roomReferences(room);
|
||||
default -> null;
|
||||
};
|
||||
}
|
||||
|
||||
private ReferenceSnapshot userReferences(WiredContext ctx, Room room) {
|
||||
ReferenceSnapshot snapshot = new ReferenceSnapshot(TARGET_USER);
|
||||
|
||||
if (isInternalVariableToken(this.referenceVariableToken)) {
|
||||
String key = getInternalVariableKey(this.referenceVariableToken);
|
||||
if (!canUseUserInternalReference(key)) return null;
|
||||
|
||||
for (RoomUnit roomUnit : WiredSourceUtil.resolveUsers(ctx, this.referenceUserSource)) {
|
||||
if (roomUnit == null) continue;
|
||||
|
||||
Integer value = this.readUserInternalValue(room, roomUnit, key);
|
||||
if (value != null) snapshot.add(roomUnit.getId(), value);
|
||||
}
|
||||
|
||||
return snapshot.isEmpty() ? null : snapshot;
|
||||
}
|
||||
|
||||
WiredVariableDefinitionInfo definition = room.getUserVariableManager().getDefinitionInfo(this.referenceVariableItemId);
|
||||
if (definition == null || !definition.hasValue()) return null;
|
||||
|
||||
for (RoomUnit roomUnit : WiredSourceUtil.resolveUsers(ctx, this.referenceUserSource)) {
|
||||
if (roomUnit == null) continue;
|
||||
|
||||
Habbo habbo = room.getHabbo(roomUnit);
|
||||
if (habbo != null) snapshot.add(roomUnit.getId(), room.getUserVariableManager().getCurrentValue(habbo.getHabboInfo().getId(), this.referenceVariableItemId));
|
||||
}
|
||||
|
||||
return snapshot.isEmpty() ? null : snapshot;
|
||||
}
|
||||
|
||||
private ReferenceSnapshot furniReferences(WiredContext ctx, Room room) {
|
||||
int source = (this.referenceFurniSource == SOURCE_SECONDARY_SELECTED) ? WiredSourceUtil.SOURCE_SELECTED : this.referenceFurniSource;
|
||||
if (source == WiredSourceUtil.SOURCE_SELECTED) this.validateItems(this.referenceSelectedFurni);
|
||||
|
||||
ReferenceSnapshot snapshot = new ReferenceSnapshot(TARGET_FURNI);
|
||||
|
||||
if (isInternalVariableToken(this.referenceVariableToken)) {
|
||||
String key = getInternalVariableKey(this.referenceVariableToken);
|
||||
if (!canUseFurniInternalReference(key)) return null;
|
||||
|
||||
for (HabboItem item : WiredSourceUtil.resolveItems(ctx, source, this.referenceSelectedFurni)) {
|
||||
if (item == null) continue;
|
||||
|
||||
Integer value = this.readFurniInternalValue(room, item, key);
|
||||
if (value != null) snapshot.add(item.getId(), value);
|
||||
}
|
||||
|
||||
return snapshot.isEmpty() ? null : snapshot;
|
||||
}
|
||||
|
||||
WiredVariableDefinitionInfo definition = room.getFurniVariableManager().getDefinitionInfo(this.referenceVariableItemId);
|
||||
if (definition == null || !definition.hasValue()) return null;
|
||||
|
||||
for (HabboItem item : WiredSourceUtil.resolveItems(ctx, source, this.referenceSelectedFurni)) {
|
||||
if (item != null) snapshot.add(item.getId(), room.getFurniVariableManager().getCurrentValue(item.getId(), this.referenceVariableItemId));
|
||||
}
|
||||
|
||||
return snapshot.isEmpty() ? null : snapshot;
|
||||
}
|
||||
|
||||
private ReferenceSnapshot roomReferences(Room room) {
|
||||
ReferenceSnapshot snapshot = new ReferenceSnapshot(TARGET_ROOM);
|
||||
|
||||
if (isInternalVariableToken(this.referenceVariableToken)) {
|
||||
String key = getInternalVariableKey(this.referenceVariableToken);
|
||||
if (!canUseRoomInternalReference(key)) return null;
|
||||
|
||||
Integer value = this.readRoomInternalValue(room, key);
|
||||
if (value == null) return null;
|
||||
|
||||
snapshot.add(room.getId(), value);
|
||||
return snapshot;
|
||||
}
|
||||
|
||||
WiredVariableDefinitionInfo definition = room.getRoomVariableManager().getDefinitionInfo(this.referenceVariableItemId);
|
||||
if (definition == null || !definition.hasValue()) return null;
|
||||
|
||||
snapshot.add(room.getId(), room.getRoomVariableManager().getCurrentValue(this.referenceVariableItemId));
|
||||
return snapshot;
|
||||
}
|
||||
|
||||
private ReferenceSnapshot contextReferences(WiredContext ctx, Room room) {
|
||||
ReferenceSnapshot snapshot = new ReferenceSnapshot(TARGET_CONTEXT);
|
||||
|
||||
if (isInternalVariableToken(this.referenceVariableToken)) {
|
||||
String key = getInternalVariableKey(this.referenceVariableToken);
|
||||
if (!canUseContextInternalReference(key)) return null;
|
||||
|
||||
Integer value = WiredInternalVariableSupport.readContextValue(ctx, key);
|
||||
if (value == null) return null;
|
||||
|
||||
snapshot.add(this.referenceVariableItemId > 0 ? this.referenceVariableItemId : room.getId(), value);
|
||||
return snapshot;
|
||||
}
|
||||
|
||||
WiredVariableDefinitionInfo definition = WiredContextVariableSupport.getDefinitionInfo(room, this.referenceVariableItemId);
|
||||
if (definition == null || !definition.hasValue() || !WiredContextVariableSupport.hasVariable(ctx, this.referenceVariableItemId)) return null;
|
||||
|
||||
Integer value = WiredContextVariableSupport.getCurrentValue(ctx, this.referenceVariableItemId);
|
||||
if (value == null) return null;
|
||||
|
||||
snapshot.add(this.referenceVariableItemId, value);
|
||||
return snapshot;
|
||||
}
|
||||
|
||||
private Integer referenceFor(ReferenceSnapshot snapshot, int destinationEntityId, int destinationTarget, int destinationIndex) {
|
||||
if (this.referenceMode != REF_VARIABLE) return this.referenceConstantValue;
|
||||
if (this.isUnaryOperation()) return 0;
|
||||
if (snapshot == null || snapshot.isEmpty()) return null;
|
||||
if (snapshot.targetType == destinationTarget && snapshot.values.containsKey(destinationEntityId)) return snapshot.values.get(destinationEntityId);
|
||||
if (destinationIndex >= 0 && destinationIndex < snapshot.values.size()) return new ArrayList<>(snapshot.values.values()).get(destinationIndex);
|
||||
return new ArrayList<>(snapshot.values.values()).get(0);
|
||||
}
|
||||
|
||||
private int applyOperation(int currentValue, Integer referenceValue) {
|
||||
return switch (this.operation) {
|
||||
case OP_ASSIGN -> (referenceValue != null) ? referenceValue : currentValue;
|
||||
case OP_ADD -> clamp((long) currentValue + referenceValue);
|
||||
case OP_SUB -> clamp((long) currentValue - referenceValue);
|
||||
case OP_MUL -> clamp((long) currentValue * referenceValue);
|
||||
case OP_DIV -> (referenceValue == null || referenceValue == 0) ? currentValue : (currentValue / referenceValue);
|
||||
case OP_POW -> (referenceValue == null || referenceValue < 0) ? 0 : clamp(Math.round(Math.pow(currentValue, referenceValue)));
|
||||
case OP_MOD -> (referenceValue == null || referenceValue == 0) ? currentValue : (currentValue % referenceValue);
|
||||
case OP_MIN -> (referenceValue != null) ? Math.min(currentValue, referenceValue) : currentValue;
|
||||
case OP_MAX -> (referenceValue != null) ? Math.max(currentValue, referenceValue) : currentValue;
|
||||
case OP_RANDOM -> (referenceValue == null || referenceValue <= 0) ? 0 : Emulator.getRandom().nextInt(referenceValue + 1);
|
||||
case OP_ABS -> (currentValue == Integer.MIN_VALUE) ? Integer.MAX_VALUE : Math.abs(currentValue);
|
||||
case OP_AND -> (referenceValue != null) ? (currentValue & referenceValue) : currentValue;
|
||||
case OP_OR -> (referenceValue != null) ? (currentValue | referenceValue) : currentValue;
|
||||
case OP_XOR -> (referenceValue != null) ? (currentValue ^ referenceValue) : currentValue;
|
||||
case OP_NOT -> ~currentValue;
|
||||
case OP_LSHIFT -> currentValue << shift(referenceValue);
|
||||
case OP_RSHIFT -> currentValue >> shift(referenceValue);
|
||||
default -> currentValue;
|
||||
};
|
||||
}
|
||||
|
||||
private boolean isUnaryOperation() {
|
||||
return this.operation == OP_ABS || this.operation == OP_NOT;
|
||||
}
|
||||
|
||||
private void validateDestination(Room room, int targetType, String variableToken) throws WiredSaveException {
|
||||
if (variableToken == null || variableToken.isEmpty()) throw new WiredSaveException("wiredfurni.params.variables.validation.missing_variable");
|
||||
|
||||
boolean valid = switch (targetType) {
|
||||
case TARGET_USER -> isInternalVariableToken(variableToken)
|
||||
? canUseUserInternalDestination(getInternalVariableKey(variableToken))
|
||||
: this.isValidUserCustomDestination(room, getCustomItemId(variableToken));
|
||||
case TARGET_FURNI -> isInternalVariableToken(variableToken)
|
||||
? canUseFurniInternalDestination(getInternalVariableKey(variableToken))
|
||||
: this.isValidFurniCustomDestination(room, getCustomItemId(variableToken));
|
||||
case TARGET_CONTEXT -> !isInternalVariableToken(variableToken)
|
||||
&& this.isValidContextCustomDestination(room, getCustomItemId(variableToken));
|
||||
case TARGET_ROOM -> !isInternalVariableToken(variableToken) && this.isValidRoomCustomDestination(room, getCustomItemId(variableToken));
|
||||
default -> false;
|
||||
};
|
||||
|
||||
if (!valid) throw new WiredSaveException("wiredfurni.params.variables.validation.invalid_variable");
|
||||
}
|
||||
|
||||
private void validateReference(Room room, int targetType, String variableToken) throws WiredSaveException {
|
||||
if (variableToken == null || variableToken.isEmpty()) throw new WiredSaveException("wiredfurni.params.variables.validation.missing_variable");
|
||||
|
||||
boolean valid = switch (targetType) {
|
||||
case TARGET_USER -> isInternalVariableToken(variableToken)
|
||||
? canUseUserInternalReference(getInternalVariableKey(variableToken))
|
||||
: this.isValidUserCustomReference(room, getCustomItemId(variableToken));
|
||||
case TARGET_FURNI -> isInternalVariableToken(variableToken)
|
||||
? canUseFurniInternalReference(getInternalVariableKey(variableToken))
|
||||
: this.isValidFurniCustomDestination(room, getCustomItemId(variableToken));
|
||||
case TARGET_CONTEXT -> isInternalVariableToken(variableToken)
|
||||
? canUseContextInternalReference(getInternalVariableKey(variableToken))
|
||||
: this.isValidContextCustomReference(room, getCustomItemId(variableToken));
|
||||
case TARGET_ROOM -> isInternalVariableToken(variableToken)
|
||||
? canUseRoomInternalReference(getInternalVariableKey(variableToken))
|
||||
: this.isValidRoomCustomReference(room, getCustomItemId(variableToken));
|
||||
default -> false;
|
||||
};
|
||||
|
||||
if (!valid) throw new WiredSaveException("wiredfurni.params.variables.validation.invalid_variable");
|
||||
}
|
||||
|
||||
private boolean isValidUserCustomDestination(Room room, int variableItemId) {
|
||||
WiredVariableDefinitionInfo definition = (room != null) ? room.getUserVariableManager().getDefinitionInfo(variableItemId) : null;
|
||||
return definition != null && definition.hasValue() && !definition.isReadOnly();
|
||||
}
|
||||
|
||||
private boolean isValidFurniCustomDestination(Room room, int variableItemId) {
|
||||
WiredVariableDefinitionInfo definition = (room != null) ? room.getFurniVariableManager().getDefinitionInfo(variableItemId) : null;
|
||||
return definition != null && definition.hasValue() && !definition.isReadOnly();
|
||||
}
|
||||
|
||||
private boolean isValidRoomCustomDestination(Room room, int variableItemId) {
|
||||
WiredVariableDefinitionInfo definition = (room != null) ? room.getRoomVariableManager().getDefinitionInfo(variableItemId) : null;
|
||||
return definition != null && definition.hasValue() && !definition.isReadOnly();
|
||||
}
|
||||
|
||||
private boolean isValidContextCustomDestination(Room room, int variableItemId) {
|
||||
WiredVariableDefinitionInfo definition = WiredContextVariableSupport.getDefinitionInfo(room, variableItemId);
|
||||
return definition != null && definition.hasValue() && !definition.isReadOnly();
|
||||
}
|
||||
|
||||
private boolean isValidUserCustomReference(Room room, int variableItemId) {
|
||||
WiredVariableDefinitionInfo definition = (room != null) ? room.getUserVariableManager().getDefinitionInfo(variableItemId) : null;
|
||||
return definition != null && definition.hasValue();
|
||||
}
|
||||
|
||||
private boolean isValidRoomCustomReference(Room room, int variableItemId) {
|
||||
WiredVariableDefinitionInfo definition = (room != null) ? room.getRoomVariableManager().getDefinitionInfo(variableItemId) : null;
|
||||
return definition != null && definition.hasValue();
|
||||
}
|
||||
|
||||
private boolean isValidContextCustomReference(Room room, int variableItemId) {
|
||||
WiredVariableDefinitionInfo definition = WiredContextVariableSupport.getDefinitionInfo(room, variableItemId);
|
||||
return definition != null && definition.hasValue();
|
||||
}
|
||||
|
||||
private boolean isValidFurniCustomReference(Room room, int variableItemId) {
|
||||
WiredVariableDefinitionInfo definition = (room != null) ? room.getFurniVariableManager().getDefinitionInfo(variableItemId) : null;
|
||||
return definition != null && definition.hasValue();
|
||||
}
|
||||
|
||||
private Integer readUserInternalValue(Room room, RoomUnit roomUnit, String key) {
|
||||
return WiredInternalVariableSupport.readUserValue(room, roomUnit, key);
|
||||
}
|
||||
|
||||
private boolean writeUserInternalValue(Room room, RoomUnit roomUnit, String key, int value) {
|
||||
return WiredInternalVariableSupport.writeUserValue(
|
||||
room,
|
||||
roomUnit,
|
||||
key,
|
||||
value,
|
||||
WiredUserMovementHelper.DEFAULT_ANIMATION_DURATION,
|
||||
false);
|
||||
}
|
||||
|
||||
private Integer readFurniInternalValue(Room room, HabboItem item, String key) {
|
||||
return WiredInternalVariableSupport.readFurniValue(room, item, key);
|
||||
}
|
||||
|
||||
private boolean writeFurniInternalValue(Room room, HabboItem item, String key, int value) {
|
||||
return WiredInternalVariableSupport.writeFurniValue(room, item, key, value);
|
||||
}
|
||||
|
||||
private Integer readRoomInternalValue(Room room, String key) {
|
||||
return WiredInternalVariableSupport.readRoomValue(room, key);
|
||||
}
|
||||
|
||||
private Integer getUserTeamScore(Room room, Habbo habbo) {
|
||||
if (room == null || habbo == null || habbo.getHabboInfo().getGamePlayer() == null) return null;
|
||||
|
||||
Game game = this.resolveTeamGame(room, habbo);
|
||||
GamePlayer gamePlayer = habbo.getHabboInfo().getGamePlayer();
|
||||
|
||||
if (game == null || gamePlayer.getTeamColor() == null) return gamePlayer.getScore();
|
||||
|
||||
GameTeam team = game.getTeam(gamePlayer.getTeamColor());
|
||||
return (team != null) ? team.getTotalScore() : gamePlayer.getScore();
|
||||
}
|
||||
|
||||
private Integer getTeamColorId(int effectId) {
|
||||
TeamEffectData data = this.getTeamEffectData(effectId);
|
||||
return data == null ? null : data.colorId;
|
||||
}
|
||||
|
||||
private Integer getTeamTypeId(int effectId) {
|
||||
TeamEffectData data = this.getTeamEffectData(effectId);
|
||||
return data == null ? null : data.typeId;
|
||||
}
|
||||
|
||||
private int getTeamMetric(Room room, GameTeamColors color, boolean score) {
|
||||
Game game = this.resolveTeamGame(room, null);
|
||||
if (game == null || color == null) return 0;
|
||||
|
||||
GameTeam team = game.getTeam(color);
|
||||
if (team == null) return 0;
|
||||
|
||||
return score ? team.getTotalScore() : team.getMembers().size();
|
||||
}
|
||||
|
||||
private Game resolveTeamGame(Room room, Habbo habbo) {
|
||||
if (room == null) return null;
|
||||
|
||||
if (habbo != null && habbo.getHabboInfo() != null && habbo.getHabboInfo().getCurrentGame() != null) {
|
||||
Game game = room.getGame(habbo.getHabboInfo().getCurrentGame());
|
||||
if (game != null) return game;
|
||||
}
|
||||
|
||||
Game wiredGame = room.getGame(WiredGame.class);
|
||||
if (wiredGame != null) return wiredGame;
|
||||
|
||||
Game freezeGame = room.getGame(FreezeGame.class);
|
||||
if (freezeGame != null) return freezeGame;
|
||||
|
||||
return room.getGame(BattleBanzaiGame.class);
|
||||
}
|
||||
|
||||
private TeamEffectData getTeamEffectData(int effectValue) {
|
||||
if (effectValue <= 0) return null;
|
||||
|
||||
if (effectValue >= 223 && effectValue <= 226) return new TeamEffectData(effectValue - 222, 0);
|
||||
if (effectValue >= 33 && effectValue <= 36) return new TeamEffectData(effectValue - 32, 1);
|
||||
if (effectValue >= 40 && effectValue <= 43) return new TeamEffectData(effectValue - 39, 2);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean moveUserTo(Room room, RoomUnit roomUnit, int x, int y) {
|
||||
if (room == null || roomUnit == null || room.getLayout() == null) return false;
|
||||
|
||||
RoomTile targetTile = room.getLayout().getTile((short) x, (short) y);
|
||||
if (targetTile == null || targetTile.state == RoomTileState.INVALID) return false;
|
||||
|
||||
double targetZ = targetTile.getStackHeight() + ((targetTile.state == RoomTileState.SIT) ? -0.5 : 0);
|
||||
return WiredUserMovementHelper.moveUser(
|
||||
room,
|
||||
roomUnit,
|
||||
targetTile,
|
||||
targetZ,
|
||||
roomUnit.getBodyRotation(),
|
||||
roomUnit.getHeadRotation(),
|
||||
WiredUserMovementHelper.DEFAULT_ANIMATION_DURATION,
|
||||
false);
|
||||
}
|
||||
|
||||
private boolean moveFurniTo(Room room, HabboItem item, int x, int y, int rotation, double z) {
|
||||
if (room == null || item == null || room.getLayout() == null) return false;
|
||||
|
||||
RoomTile targetTile = room.getLayout().getTile((short) x, (short) y);
|
||||
if (targetTile == null || targetTile.state == RoomTileState.INVALID) return false;
|
||||
|
||||
FurnitureMovementError error = room.moveFurniTo(item, targetTile, rotation, z, null, true, true);
|
||||
return error == FurnitureMovementError.NONE;
|
||||
}
|
||||
|
||||
private List<HabboItem> parseItems(int[] ids, Room room) throws WiredSaveException {
|
||||
List<HabboItem> items = new ArrayList<>();
|
||||
if (ids == null || room == null) return items;
|
||||
|
||||
for (int id : ids) {
|
||||
HabboItem item = room.getHabboItem(id);
|
||||
if (item == null) throw new WiredSaveException(String.format("Item %s not found", id));
|
||||
items.add(item);
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
private List<HabboItem> parseItems(List<Integer> ids, Room room) throws WiredSaveException {
|
||||
List<HabboItem> items = new ArrayList<>();
|
||||
if (ids == null || room == null) return items;
|
||||
|
||||
for (Integer id : ids) {
|
||||
if (id == null || id <= 0) continue;
|
||||
|
||||
HabboItem item = room.getHabboItem(id);
|
||||
if (item == null) throw new WiredSaveException(String.format("Item %s not found", id));
|
||||
items.add(item);
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
private List<HabboItem> parseItems(String ids, Room room) throws WiredSaveException {
|
||||
List<HabboItem> items = new ArrayList<>();
|
||||
if (ids == null || ids.trim().isEmpty() || room == null) return items;
|
||||
|
||||
for (String part : ids.split("[;,\\t]")) {
|
||||
int id = parseInteger(part);
|
||||
if (id <= 0) continue;
|
||||
|
||||
HabboItem item = room.getHabboItem(id);
|
||||
if (item == null) throw new WiredSaveException(String.format("Item %s not found", id));
|
||||
items.add(item);
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
private String serializeStringData() {
|
||||
return (this.destinationVariableToken == null ? "" : this.destinationVariableToken) + DELIM + (this.referenceVariableToken == null ? "" : this.referenceVariableToken) + DELIM + this.serializeIds(this.referenceSelectedFurni);
|
||||
}
|
||||
|
||||
private String[] parseStringData(String value) {
|
||||
return (value == null || value.isEmpty()) ? new String[0] : value.split("\\t", -1);
|
||||
}
|
||||
|
||||
private List<Integer> toIds(List<HabboItem> items) {
|
||||
List<Integer> ids = new ArrayList<>();
|
||||
for (HabboItem item : items) if (item != null) ids.add(item.getId());
|
||||
return ids;
|
||||
}
|
||||
|
||||
private String serializeIds(List<HabboItem> items) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
|
||||
for (HabboItem item : items) {
|
||||
if (item == null) continue;
|
||||
if (builder.length() > 0) builder.append(FURNI_DELIM);
|
||||
builder.append(item.getId());
|
||||
}
|
||||
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
private void setDestinationVariableToken(String token) {
|
||||
this.destinationVariableToken = normalizeVariableToken(token);
|
||||
this.destinationVariableItemId = getCustomItemId(this.destinationVariableToken);
|
||||
}
|
||||
|
||||
private void setReferenceVariableToken(String token) {
|
||||
this.referenceVariableToken = normalizeVariableToken(token);
|
||||
this.referenceVariableItemId = getCustomItemId(this.referenceVariableToken);
|
||||
}
|
||||
|
||||
private static boolean isCustomVariableToken(String token) {
|
||||
return token != null && token.startsWith(CUSTOM_TOKEN_PREFIX);
|
||||
}
|
||||
|
||||
private static boolean isInternalVariableToken(String token) {
|
||||
return token != null && token.startsWith(INTERNAL_TOKEN_PREFIX);
|
||||
}
|
||||
|
||||
private static int getCustomItemId(String token) {
|
||||
if (!isCustomVariableToken(token)) return 0;
|
||||
return parseInteger(token.substring(CUSTOM_TOKEN_PREFIX.length()));
|
||||
}
|
||||
|
||||
private static String getInternalVariableKey(String token) {
|
||||
return isInternalVariableToken(token) ? WiredInternalVariableSupport.normalizeKey(token.substring(INTERNAL_TOKEN_PREFIX.length())) : "";
|
||||
}
|
||||
|
||||
private static String normalizeVariableToken(String token) {
|
||||
if (token == null) return "";
|
||||
|
||||
String normalized = token.trim();
|
||||
if (normalized.isEmpty()) return "";
|
||||
if (isCustomVariableToken(normalized)) return normalized;
|
||||
if (isInternalVariableToken(normalized)) return INTERNAL_TOKEN_PREFIX + WiredInternalVariableSupport.normalizeKey(normalized.substring(INTERNAL_TOKEN_PREFIX.length()));
|
||||
|
||||
int parsedValue = parseInteger(normalized);
|
||||
return parsedValue > 0 ? CUSTOM_TOKEN_PREFIX + parsedValue : "";
|
||||
}
|
||||
|
||||
private static boolean canUseUserInternalDestination(String key) {
|
||||
return WiredInternalVariableSupport.canUseUserDestination(key);
|
||||
}
|
||||
|
||||
private static boolean canUseFurniInternalDestination(String key) {
|
||||
return WiredInternalVariableSupport.canUseFurniDestination(key);
|
||||
}
|
||||
|
||||
private static boolean canUseUserInternalReference(String key) {
|
||||
return WiredInternalVariableSupport.canUseUserReference(key);
|
||||
}
|
||||
|
||||
private static boolean canUseFurniInternalReference(String key) {
|
||||
return WiredInternalVariableSupport.canUseFurniReference(key);
|
||||
}
|
||||
|
||||
private static boolean canUseRoomInternalReference(String key) {
|
||||
return WiredInternalVariableSupport.canUseRoomReference(key);
|
||||
}
|
||||
|
||||
private static boolean canUseContextInternalReference(String key) {
|
||||
return WiredInternalVariableSupport.canUseContextReference(key);
|
||||
}
|
||||
|
||||
private static int param(int[] params, int index, int fallback) {
|
||||
return (params.length > index) ? params[index] : fallback;
|
||||
}
|
||||
|
||||
private static int normalizeTargetType(int value) {
|
||||
return switch (value) {
|
||||
case TARGET_FURNI, TARGET_CONTEXT, TARGET_ROOM -> value;
|
||||
default -> TARGET_USER;
|
||||
};
|
||||
}
|
||||
|
||||
private static int normalizeReferenceMode(int value) {
|
||||
return (value == REF_VARIABLE) ? REF_VARIABLE : REF_CONSTANT;
|
||||
}
|
||||
|
||||
private static int normalizeUserSource(int value) {
|
||||
return WiredSourceUtil.isDefaultUserSource(value) ? value : WiredSourceUtil.SOURCE_TRIGGER;
|
||||
}
|
||||
|
||||
private static int normalizeDestinationFurniSource(int value) {
|
||||
return switch (value) {
|
||||
case WiredSourceUtil.SOURCE_SELECTED, WiredSourceUtil.SOURCE_SELECTOR, WiredSourceUtil.SOURCE_SIGNAL -> value;
|
||||
default -> WiredSourceUtil.SOURCE_TRIGGER;
|
||||
};
|
||||
}
|
||||
|
||||
private static int normalizeReferenceFurniSource(int value) {
|
||||
return switch (value) {
|
||||
case SOURCE_SECONDARY_SELECTED, WiredSourceUtil.SOURCE_SELECTOR, WiredSourceUtil.SOURCE_SIGNAL -> value;
|
||||
default -> WiredSourceUtil.SOURCE_TRIGGER;
|
||||
};
|
||||
}
|
||||
|
||||
private static int normalizeOperation(int value) {
|
||||
return switch (value) {
|
||||
case OP_ADD, OP_SUB, OP_MUL, OP_DIV, OP_POW, OP_MOD, OP_MIN, OP_MAX, OP_RANDOM, OP_ABS, OP_AND, OP_OR, OP_XOR, OP_NOT, OP_LSHIFT, OP_RSHIFT -> value;
|
||||
default -> OP_ASSIGN;
|
||||
};
|
||||
}
|
||||
|
||||
private static int parseInteger(String value) {
|
||||
try {
|
||||
return (value == null || value.trim().isEmpty()) ? 0 : Integer.parseInt(value.trim());
|
||||
} catch (NumberFormatException e) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
private static int shift(Integer value) {
|
||||
return (value == null) ? 0 : Math.max(0, Math.min(31, value));
|
||||
}
|
||||
|
||||
private static int clamp(long value) {
|
||||
return (value > Integer.MAX_VALUE) ? Integer.MAX_VALUE : ((value < Integer.MIN_VALUE) ? Integer.MIN_VALUE : (int) value);
|
||||
}
|
||||
|
||||
static class JsonData {
|
||||
int destinationTargetType, destinationVariableItemId, operation, referenceMode, referenceConstantValue, referenceTargetType, referenceVariableItemId, destinationUserSource, destinationFurniSource, referenceUserSource, referenceFurniSource, delay;
|
||||
String destinationVariableToken, referenceVariableToken;
|
||||
List<Integer> destinationSelectedFurniIds, referenceSelectedFurniIds;
|
||||
|
||||
JsonData(int destinationTargetType, String destinationVariableToken, int destinationVariableItemId, int operation, int referenceMode, int referenceConstantValue, int referenceTargetType, String referenceVariableToken, int referenceVariableItemId, int destinationUserSource, int destinationFurniSource, int referenceUserSource, int referenceFurniSource, int delay, List<Integer> destinationSelectedFurniIds, List<Integer> referenceSelectedFurniIds) {
|
||||
this.destinationTargetType = destinationTargetType;
|
||||
this.destinationVariableToken = destinationVariableToken;
|
||||
this.destinationVariableItemId = destinationVariableItemId;
|
||||
this.operation = operation;
|
||||
this.referenceMode = referenceMode;
|
||||
this.referenceConstantValue = referenceConstantValue;
|
||||
this.referenceTargetType = referenceTargetType;
|
||||
this.referenceVariableToken = referenceVariableToken;
|
||||
this.referenceVariableItemId = referenceVariableItemId;
|
||||
this.destinationUserSource = destinationUserSource;
|
||||
this.destinationFurniSource = destinationFurniSource;
|
||||
this.referenceUserSource = referenceUserSource;
|
||||
this.referenceFurniSource = referenceFurniSource;
|
||||
this.delay = delay;
|
||||
this.destinationSelectedFurniIds = destinationSelectedFurniIds;
|
||||
this.referenceSelectedFurniIds = referenceSelectedFurniIds;
|
||||
}
|
||||
}
|
||||
|
||||
private static class ReferenceSnapshot {
|
||||
final int targetType;
|
||||
final LinkedHashMap<Integer, Integer> values = new LinkedHashMap<>();
|
||||
|
||||
ReferenceSnapshot(int targetType) {
|
||||
this.targetType = targetType;
|
||||
}
|
||||
|
||||
void add(int entityId, int value) {
|
||||
this.values.put(entityId, value);
|
||||
}
|
||||
|
||||
boolean isEmpty() {
|
||||
return this.values.isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
private static class TeamEffectData {
|
||||
final int colorId;
|
||||
final int typeId;
|
||||
|
||||
TeamEffectData(int colorId, int typeId) {
|
||||
this.colorId = colorId;
|
||||
this.typeId = typeId;
|
||||
}
|
||||
}
|
||||
}
|
||||
+434
@@ -0,0 +1,434 @@
|
||||
package com.eu.habbo.habbohotel.items.interactions.wired.effects;
|
||||
|
||||
import com.eu.habbo.Emulator;
|
||||
import com.eu.habbo.habbohotel.gameclients.GameClient;
|
||||
import com.eu.habbo.habbohotel.items.Item;
|
||||
import com.eu.habbo.habbohotel.items.interactions.InteractionWiredEffect;
|
||||
import com.eu.habbo.habbohotel.items.interactions.wired.WiredSettings;
|
||||
import com.eu.habbo.habbohotel.rooms.Room;
|
||||
import com.eu.habbo.habbohotel.rooms.RoomUnit;
|
||||
import com.eu.habbo.habbohotel.rooms.WiredVariableDefinitionInfo;
|
||||
import com.eu.habbo.habbohotel.users.Habbo;
|
||||
import com.eu.habbo.habbohotel.users.HabboItem;
|
||||
import com.eu.habbo.habbohotel.wired.WiredEffectType;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredContext;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredContextVariableSupport;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredManager;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredSourceUtil;
|
||||
import com.eu.habbo.messages.ServerMessage;
|
||||
import com.eu.habbo.messages.incoming.wired.WiredSaveException;
|
||||
import gnu.trove.set.hash.THashSet;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class WiredEffectGiveVariable extends InteractionWiredEffect {
|
||||
public static final WiredEffectType type = WiredEffectType.GIVE_VAR;
|
||||
|
||||
public static final int TARGET_USER = 0;
|
||||
public static final int TARGET_FURNI = 1;
|
||||
public static final int TARGET_CONTEXT = 2;
|
||||
|
||||
private int variableItemId = 0;
|
||||
private int targetType = TARGET_USER;
|
||||
private boolean overrideExisting = false;
|
||||
private int initialValue = 0;
|
||||
private int userSource = WiredSourceUtil.SOURCE_TRIGGER;
|
||||
private int furniSource = WiredSourceUtil.SOURCE_TRIGGER;
|
||||
private final THashSet<HabboItem> selectedFurni;
|
||||
|
||||
public WiredEffectGiveVariable(ResultSet set, Item baseItem) throws SQLException {
|
||||
super(set, baseItem);
|
||||
this.selectedFurni = new THashSet<>();
|
||||
}
|
||||
|
||||
public WiredEffectGiveVariable(int id, int userId, Item item, String extradata, int limitedStack, int limitedSells) {
|
||||
super(id, userId, item, extradata, limitedStack, limitedSells);
|
||||
this.selectedFurni = new THashSet<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(WiredContext ctx) {
|
||||
Room room = ctx.room();
|
||||
|
||||
if (room == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (this.targetType) {
|
||||
case TARGET_USER:
|
||||
this.executeUserVariables(ctx, room);
|
||||
return;
|
||||
case TARGET_FURNI:
|
||||
this.executeFurniVariables(ctx, room);
|
||||
return;
|
||||
case TARGET_CONTEXT:
|
||||
this.executeContextVariables(ctx, room);
|
||||
return;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private void executeContextVariables(WiredContext ctx, Room room) {
|
||||
WiredVariableDefinitionInfo definitionInfo = WiredContextVariableSupport.getDefinitionInfo(room, this.variableItemId);
|
||||
if (definitionInfo == null || definitionInfo.isReadOnly()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Integer value = definitionInfo.hasValue() ? this.initialValue : null;
|
||||
WiredContextVariableSupport.assignVariable(ctx, room, this.variableItemId, value, this.overrideExisting);
|
||||
}
|
||||
|
||||
private void executeUserVariables(WiredContext ctx, Room room) {
|
||||
WiredVariableDefinitionInfo definitionInfo = room.getUserVariableManager().getDefinitionInfo(this.variableItemId);
|
||||
|
||||
if (definitionInfo == null || definitionInfo.isReadOnly()) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<RoomUnit> users = WiredSourceUtil.resolveUsers(ctx, this.userSource);
|
||||
|
||||
if (users.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Integer value = definitionInfo.hasValue() ? this.initialValue : null;
|
||||
|
||||
for (RoomUnit roomUnit : users) {
|
||||
if (roomUnit == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Habbo habbo = room.getHabbo(roomUnit);
|
||||
|
||||
if (habbo == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
room.getUserVariableManager().assignVariable(habbo, this.variableItemId, value, this.overrideExisting);
|
||||
}
|
||||
}
|
||||
|
||||
private void executeFurniVariables(WiredContext ctx, Room room) {
|
||||
WiredVariableDefinitionInfo definition = room.getFurniVariableManager().getDefinitionInfo(this.variableItemId);
|
||||
|
||||
if (definition == null || definition.isReadOnly()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.furniSource == WiredSourceUtil.SOURCE_SELECTED) {
|
||||
this.validateItems(this.selectedFurni);
|
||||
}
|
||||
|
||||
List<HabboItem> furni = WiredSourceUtil.resolveItems(ctx, this.furniSource, this.selectedFurni);
|
||||
|
||||
if (furni.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Integer value = definition.hasValue() ? this.initialValue : null;
|
||||
|
||||
for (HabboItem item : furni) {
|
||||
if (item == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
room.getFurniVariableManager().assignVariable(item, this.variableItemId, value, this.overrideExisting);
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@Override
|
||||
public boolean execute(RoomUnit roomUnit, Room room, Object[] stuff) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serializeWiredData(ServerMessage message, Room room) {
|
||||
List<HabboItem> selectedItems = new ArrayList<>();
|
||||
|
||||
if (this.targetType == TARGET_FURNI && this.furniSource == WiredSourceUtil.SOURCE_SELECTED) {
|
||||
for (HabboItem item : this.selectedFurni) {
|
||||
if (item != null && room != null && room.getHabboItem(item.getId()) != null) {
|
||||
selectedItems.add(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
message.appendBoolean(false);
|
||||
message.appendInt(WiredManager.MAXIMUM_FURNI_SELECTION);
|
||||
message.appendInt(selectedItems.size());
|
||||
|
||||
for (HabboItem item : selectedItems) {
|
||||
message.appendInt(item.getId());
|
||||
}
|
||||
|
||||
message.appendInt(this.getBaseItem().getSpriteId());
|
||||
message.appendInt(this.getId());
|
||||
message.appendString(String.valueOf(this.variableItemId));
|
||||
message.appendInt(5);
|
||||
message.appendInt(this.targetType);
|
||||
message.appendInt(this.overrideExisting ? 1 : 0);
|
||||
message.appendInt(this.initialValue);
|
||||
message.appendInt(this.userSource);
|
||||
message.appendInt(this.furniSource);
|
||||
message.appendInt(0);
|
||||
message.appendInt(this.getType().code);
|
||||
message.appendInt(this.getDelay());
|
||||
message.appendInt(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean saveData(WiredSettings settings, GameClient gameClient) throws WiredSaveException {
|
||||
Room room = Emulator.getGameEnvironment().getRoomManager().getRoom(this.getRoomId());
|
||||
|
||||
if (room == null) {
|
||||
throw new WiredSaveException("Room not found");
|
||||
}
|
||||
|
||||
int[] intParams = settings.getIntParams();
|
||||
int nextTargetType = normalizeTargetType((intParams.length > 0) ? intParams[0] : TARGET_USER);
|
||||
boolean nextOverrideExisting = (intParams.length > 1) && (intParams[1] == 1);
|
||||
int nextInitialValue = (intParams.length > 2) ? intParams[2] : 0;
|
||||
int nextUserSource = normalizeUserSource((intParams.length > 3) ? intParams[3] : WiredSourceUtil.SOURCE_TRIGGER);
|
||||
int nextFurniSource = normalizeFurniSource((intParams.length > 4) ? intParams[4] : WiredSourceUtil.SOURCE_TRIGGER);
|
||||
int nextVariableItemId = parseVariableItemId(settings.getStringParam());
|
||||
|
||||
if (nextVariableItemId <= 0 && settings.getFurniIds() != null && settings.getFurniIds().length > 0) {
|
||||
int legacyItemId = settings.getFurniIds()[0];
|
||||
|
||||
if (room.getUserVariableManager().hasDefinition(legacyItemId)) {
|
||||
nextVariableItemId = legacyItemId;
|
||||
nextTargetType = TARGET_USER;
|
||||
}
|
||||
}
|
||||
|
||||
if (nextVariableItemId <= 0) {
|
||||
throw new WiredSaveException("wiredfurni.params.variables.validation.missing_variable");
|
||||
}
|
||||
|
||||
WiredVariableDefinitionInfo userDefinitionInfo = (nextTargetType == TARGET_USER) ? room.getUserVariableManager().getDefinitionInfo(nextVariableItemId) : null;
|
||||
|
||||
if (nextTargetType == TARGET_USER && (userDefinitionInfo == null || userDefinitionInfo.isReadOnly())) {
|
||||
throw new WiredSaveException("wiredfurni.params.variables.validation.invalid_variable");
|
||||
}
|
||||
|
||||
if (nextTargetType == TARGET_FURNI) {
|
||||
WiredVariableDefinitionInfo furniDefinitionInfo = room.getFurniVariableManager().getDefinitionInfo(nextVariableItemId);
|
||||
|
||||
if (furniDefinitionInfo == null || furniDefinitionInfo.isReadOnly()) {
|
||||
throw new WiredSaveException("wiredfurni.params.variables.validation.invalid_variable");
|
||||
}
|
||||
}
|
||||
|
||||
if (nextTargetType == TARGET_CONTEXT) {
|
||||
WiredVariableDefinitionInfo contextDefinitionInfo = WiredContextVariableSupport.getDefinitionInfo(room, nextVariableItemId);
|
||||
|
||||
if (contextDefinitionInfo == null || contextDefinitionInfo.isReadOnly()) {
|
||||
throw new WiredSaveException("wiredfurni.params.variables.validation.invalid_variable");
|
||||
}
|
||||
}
|
||||
|
||||
this.selectedFurni.clear();
|
||||
|
||||
if (nextTargetType == TARGET_FURNI && nextFurniSource == WiredSourceUtil.SOURCE_SELECTED) {
|
||||
int[] furniIds = settings.getFurniIds();
|
||||
int itemsCount = (furniIds != null) ? furniIds.length : 0;
|
||||
|
||||
if (itemsCount > Emulator.getConfig().getInt("hotel.wired.furni.selection.count")) {
|
||||
throw new WiredSaveException("Too many furni selected");
|
||||
}
|
||||
|
||||
for (int i = 0; i < itemsCount; i++) {
|
||||
int itemId = furniIds[i];
|
||||
HabboItem item = room.getHabboItem(itemId);
|
||||
|
||||
if (item == null) {
|
||||
throw new WiredSaveException(String.format("Item %s not found", itemId));
|
||||
}
|
||||
|
||||
this.selectedFurni.add(item);
|
||||
}
|
||||
}
|
||||
|
||||
this.variableItemId = nextVariableItemId;
|
||||
this.targetType = nextTargetType;
|
||||
this.overrideExisting = nextOverrideExisting;
|
||||
this.initialValue = nextInitialValue;
|
||||
this.userSource = nextUserSource;
|
||||
this.furniSource = nextFurniSource;
|
||||
this.setDelay(settings.getDelay());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getWiredData() {
|
||||
List<Integer> selectedItemIds = new ArrayList<>();
|
||||
|
||||
for (HabboItem item : this.selectedFurni) {
|
||||
if (item != null) {
|
||||
selectedItemIds.add(item.getId());
|
||||
}
|
||||
}
|
||||
|
||||
return WiredManager.getGson().toJson(new JsonData(this.variableItemId, this.targetType, this.overrideExisting, this.initialValue, this.userSource, this.furniSource, this.getDelay(), selectedItemIds));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadWiredData(ResultSet set, Room room) throws SQLException {
|
||||
this.onPickUp();
|
||||
|
||||
String wiredData = set.getString("wired_data");
|
||||
if (wiredData == null || wiredData.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (wiredData.startsWith("{")) {
|
||||
JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class);
|
||||
|
||||
if (data != null) {
|
||||
this.variableItemId = Math.max(0, data.variableItemId);
|
||||
this.targetType = normalizeTargetType(data.targetType);
|
||||
this.overrideExisting = data.overrideExisting;
|
||||
this.initialValue = data.initialValue;
|
||||
this.userSource = normalizeUserSource(data.userSource);
|
||||
this.furniSource = normalizeFurniSource(data.furniSource);
|
||||
this.setDelay(Math.max(0, data.delay));
|
||||
|
||||
if (room != null && data.selectedFurniIds != null) {
|
||||
for (Integer itemId : data.selectedFurniIds) {
|
||||
if (itemId == null || itemId <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
HabboItem item = room.getHabboItem(itemId);
|
||||
|
||||
if (item != null) {
|
||||
this.selectedFurni.add(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
this.variableItemId = Math.max(0, Integer.parseInt(wiredData.trim()));
|
||||
this.targetType = TARGET_USER;
|
||||
} catch (NumberFormatException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPickUp() {
|
||||
this.variableItemId = 0;
|
||||
this.targetType = TARGET_USER;
|
||||
this.overrideExisting = false;
|
||||
this.initialValue = 0;
|
||||
this.userSource = WiredSourceUtil.SOURCE_TRIGGER;
|
||||
this.furniSource = WiredSourceUtil.SOURCE_TRIGGER;
|
||||
this.selectedFurni.clear();
|
||||
this.setDelay(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWalk(RoomUnit roomUnit, Room room, Object[] objects) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public WiredEffectType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public int getVariableItemId() {
|
||||
return this.variableItemId;
|
||||
}
|
||||
|
||||
public int getTargetType() {
|
||||
return this.targetType;
|
||||
}
|
||||
|
||||
public boolean isOverrideExisting() {
|
||||
return this.overrideExisting;
|
||||
}
|
||||
|
||||
public int getInitialValue() {
|
||||
return this.initialValue;
|
||||
}
|
||||
|
||||
public int getUserSource() {
|
||||
return this.userSource;
|
||||
}
|
||||
|
||||
public int getFurniSource() {
|
||||
return this.furniSource;
|
||||
}
|
||||
|
||||
public THashSet<HabboItem> getSelectedFurni() {
|
||||
return this.selectedFurni;
|
||||
}
|
||||
|
||||
private static int normalizeTargetType(int value) {
|
||||
switch (value) {
|
||||
case TARGET_FURNI:
|
||||
case TARGET_CONTEXT:
|
||||
return value;
|
||||
default:
|
||||
return TARGET_USER;
|
||||
}
|
||||
}
|
||||
|
||||
private static int normalizeUserSource(int value) {
|
||||
return WiredSourceUtil.isDefaultUserSource(value) ? value : WiredSourceUtil.SOURCE_TRIGGER;
|
||||
}
|
||||
|
||||
private static int normalizeFurniSource(int value) {
|
||||
switch (value) {
|
||||
case WiredSourceUtil.SOURCE_SELECTED:
|
||||
case WiredSourceUtil.SOURCE_SELECTOR:
|
||||
case WiredSourceUtil.SOURCE_SIGNAL:
|
||||
return value;
|
||||
default:
|
||||
return WiredSourceUtil.SOURCE_TRIGGER;
|
||||
}
|
||||
}
|
||||
|
||||
private static int parseVariableItemId(String value) {
|
||||
if (value == null || value.trim().isEmpty()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
try {
|
||||
return Math.max(0, Integer.parseInt(value.trim()));
|
||||
} catch (NumberFormatException ignored) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static class JsonData {
|
||||
int variableItemId;
|
||||
int targetType;
|
||||
boolean overrideExisting;
|
||||
int initialValue;
|
||||
int userSource;
|
||||
int furniSource;
|
||||
int delay;
|
||||
List<Integer> selectedFurniIds;
|
||||
|
||||
JsonData(int variableItemId, int targetType, boolean overrideExisting, int initialValue, int userSource, int furniSource, int delay, List<Integer> selectedFurniIds) {
|
||||
this.variableItemId = variableItemId;
|
||||
this.targetType = targetType;
|
||||
this.overrideExisting = overrideExisting;
|
||||
this.initialValue = initialValue;
|
||||
this.userSource = userSource;
|
||||
this.furniSource = furniSource;
|
||||
this.delay = delay;
|
||||
this.selectedFurniIds = selectedFurniIds;
|
||||
}
|
||||
}
|
||||
}
|
||||
+4
@@ -263,6 +263,10 @@ public class WiredEffectMoveFurniAway extends InteractionWiredEffect {
|
||||
throw new WiredSaveException("Too many furni selected");
|
||||
}
|
||||
|
||||
if (itemsCount > 0 && this.furniSource == WiredSourceUtil.SOURCE_TRIGGER) {
|
||||
this.furniSource = WiredSourceUtil.SOURCE_SELECTED;
|
||||
}
|
||||
|
||||
List<HabboItem> newItems = new ArrayList<>();
|
||||
|
||||
if (this.furniSource == WiredSourceUtil.SOURCE_SELECTED) {
|
||||
|
||||
+5
@@ -59,6 +59,11 @@ public class WiredEffectMoveFurniTo extends InteractionWiredEffect {
|
||||
this.furniSource = settings.getIntParams()[2];
|
||||
|
||||
int count = settings.getFurniIds().length;
|
||||
|
||||
if (count > 0 && this.furniSource == WiredSourceUtil.SOURCE_TRIGGER) {
|
||||
this.furniSource = WiredSourceUtil.SOURCE_SELECTED;
|
||||
}
|
||||
|
||||
if (this.furniSource == WiredSourceUtil.SOURCE_SELECTED) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
this.items.add(room.getHabboItem(settings.getFurniIds()[i]));
|
||||
|
||||
+4
@@ -415,6 +415,10 @@ public class WiredEffectMoveFurniTowards extends InteractionWiredEffect {
|
||||
throw new WiredSaveException("Too many furni selected");
|
||||
}
|
||||
|
||||
if (itemsCount > 0 && this.furniSource == WiredSourceUtil.SOURCE_TRIGGER) {
|
||||
this.furniSource = WiredSourceUtil.SOURCE_SELECTED;
|
||||
}
|
||||
|
||||
List<HabboItem> newItems = new ArrayList<>();
|
||||
|
||||
if (this.furniSource == WiredSourceUtil.SOURCE_SELECTED) {
|
||||
|
||||
+4
@@ -261,6 +261,10 @@ public class WiredEffectMoveRotateFurni extends InteractionWiredEffect implement
|
||||
int count = settings.getFurniIds().length;
|
||||
if (count > Emulator.getConfig().getInt("hotel.wired.furni.selection.count", 5)) return false;
|
||||
|
||||
if (count > 0 && this.furniSource == WiredSourceUtil.SOURCE_TRIGGER) {
|
||||
this.furniSource = WiredSourceUtil.SOURCE_SELECTED;
|
||||
}
|
||||
|
||||
this.items.clear();
|
||||
if (this.furniSource == WiredSourceUtil.SOURCE_SELECTED) {
|
||||
for (int i = 0; i < count; i++) {
|
||||
|
||||
+15
-123
@@ -10,15 +10,14 @@ import com.eu.habbo.habbohotel.rooms.Room;
|
||||
import com.eu.habbo.habbohotel.rooms.RoomTile;
|
||||
import com.eu.habbo.habbohotel.rooms.RoomTileState;
|
||||
import com.eu.habbo.habbohotel.rooms.RoomUnit;
|
||||
import com.eu.habbo.habbohotel.rooms.RoomUnitStatus;
|
||||
import com.eu.habbo.habbohotel.rooms.RoomUserRotation;
|
||||
import com.eu.habbo.habbohotel.wired.WiredEffectType;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredContext;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredManager;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredMovementPhysics;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredMoveCarryHelper;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredSourceUtil;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredUserMovementHelper;
|
||||
import com.eu.habbo.messages.outgoing.rooms.users.RoomUserStatusComposer;
|
||||
import com.eu.habbo.messages.ServerMessage;
|
||||
import com.eu.habbo.messages.incoming.wired.WiredSaveException;
|
||||
import gnu.trove.procedure.TObjectProcedure;
|
||||
@@ -31,10 +30,6 @@ import java.util.List;
|
||||
public class WiredEffectMoveRotateUser extends InteractionWiredEffect {
|
||||
private static final int ROTATION_CLOCKWISE = 8;
|
||||
private static final int ROTATION_COUNTER_CLOCKWISE = 9;
|
||||
private static final String CACHE_ACTIVE_UNTIL = "wired.move_rotate_user.active_until";
|
||||
private static final String CACHE_WALK_IN_PLACE_UNTIL = "wired.move_rotate_user.walk_in_place_until";
|
||||
private static final int WALK_IN_PLACE_DURATION_MS = 550;
|
||||
private static final int ROTATION_ACTIVE_WINDOW_MS = 250;
|
||||
|
||||
public static final WiredEffectType type = WiredEffectType.MOVE_ROTATE_USER;
|
||||
|
||||
@@ -53,6 +48,7 @@ public class WiredEffectMoveRotateUser extends InteractionWiredEffect {
|
||||
@Override
|
||||
public void execute(WiredContext ctx) {
|
||||
Room room = ctx.room();
|
||||
WiredMovementPhysics movementPhysics = WiredMoveCarryHelper.getUserMovementPhysics(room, this, ctx);
|
||||
|
||||
for (RoomUnit roomUnit : WiredSourceUtil.resolveUsers(ctx, this.userSource)) {
|
||||
if (roomUnit == null || roomUnit.getRoom() != room) {
|
||||
@@ -62,17 +58,23 @@ public class WiredEffectMoveRotateUser extends InteractionWiredEffect {
|
||||
boolean hasRotation = this.rotationDirection >= 0;
|
||||
RoomUserRotation targetBodyRotation = hasRotation ? this.getTargetRotation(roomUnit) : roomUnit.getBodyRotation();
|
||||
RoomUserRotation targetHeadRotation = hasRotation ? targetBodyRotation : roomUnit.getHeadRotation();
|
||||
|
||||
if (roomUnit.isWalking()) {
|
||||
if (hasRotation) {
|
||||
WiredUserMovementHelper.updateUserDirection(room, roomUnit, targetBodyRotation, targetHeadRotation);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
RoomTile targetTile = (this.movementDirection >= 0) ? this.getTargetTile(room, roomUnit, this.movementDirection) : null;
|
||||
boolean canMove = this.canMoveTo(room, roomUnit, targetTile);
|
||||
boolean canMove = this.canMoveTo(room, roomUnit, targetTile, movementPhysics);
|
||||
boolean noAnimation = WiredMoveCarryHelper.hasNoAnimationExtra(room, this);
|
||||
int animationDuration = noAnimation ? 0 : WiredMoveCarryHelper.getAnimationDuration(room, this, WiredUserMovementHelper.DEFAULT_ANIMATION_DURATION);
|
||||
int activeWindowMs = this.resolveActiveWindow(canMove, hasRotation, noAnimation, animationDuration);
|
||||
|
||||
if (canMove) {
|
||||
double targetZ = targetTile.getStackHeight() + ((targetTile.state == RoomTileState.SIT) ? -0.5 : 0);
|
||||
this.markActive(roomUnit, activeWindowMs);
|
||||
if (!WiredUserMovementHelper.moveUser(room, roomUnit, targetTile, targetZ, targetBodyRotation, targetHeadRotation,
|
||||
animationDuration, noAnimation)) {
|
||||
animationDuration, noAnimation, movementPhysics)) {
|
||||
if (hasRotation) {
|
||||
WiredUserMovementHelper.updateUserDirection(room, roomUnit, targetBodyRotation, targetHeadRotation);
|
||||
}
|
||||
@@ -81,7 +83,6 @@ public class WiredEffectMoveRotateUser extends InteractionWiredEffect {
|
||||
}
|
||||
|
||||
if (hasRotation) {
|
||||
this.markActive(roomUnit, activeWindowMs);
|
||||
WiredUserMovementHelper.updateUserDirection(room, roomUnit, targetBodyRotation, targetHeadRotation);
|
||||
}
|
||||
}
|
||||
@@ -266,121 +267,12 @@ public class WiredEffectMoveRotateUser extends InteractionWiredEffect {
|
||||
return room.getLayout().getTile((short) (currentTile.x + deltaX), (short) (currentTile.y + deltaY));
|
||||
}
|
||||
|
||||
private boolean canMoveTo(Room room, RoomUnit roomUnit, RoomTile targetTile) {
|
||||
if (targetTile == null || targetTile.state == RoomTileState.INVALID || targetTile.state == RoomTileState.BLOCKED) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!room.tileWalkable(targetTile)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (RoomUnit unit : room.getRoomUnitsAt(targetTile)) {
|
||||
if (unit != null && unit != roomUnit) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void markActive(RoomUnit roomUnit, int durationMs) {
|
||||
if (roomUnit == null || durationMs <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
long activeUntil = System.currentTimeMillis() + durationMs;
|
||||
roomUnit.getCacheable().put(CACHE_ACTIVE_UNTIL, activeUntil);
|
||||
}
|
||||
|
||||
private int resolveActiveWindow(boolean canMove, boolean hasRotation, boolean noAnimation, int animationDuration) {
|
||||
if (noAnimation) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (canMove) {
|
||||
return Math.max(1, animationDuration);
|
||||
}
|
||||
|
||||
if (hasRotation) {
|
||||
return ROTATION_ACTIVE_WINDOW_MS;
|
||||
}
|
||||
|
||||
return 0;
|
||||
private boolean canMoveTo(Room room, RoomUnit roomUnit, RoomTile targetTile, WiredMovementPhysics movementPhysics) {
|
||||
return WiredUserMovementHelper.canMoveTo(room, roomUnit, targetTile, movementPhysics);
|
||||
}
|
||||
|
||||
public static boolean handleWalkWhileActive(Room room, RoomUnit roomUnit, RoomTile targetTile) {
|
||||
if (room == null || roomUnit == null || !isActive(roomUnit)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
long walkInPlaceUntil = System.currentTimeMillis() + WALK_IN_PLACE_DURATION_MS;
|
||||
roomUnit.getCacheable().put(CACHE_WALK_IN_PLACE_UNTIL, walkInPlaceUntil);
|
||||
roomUnit.stopWalking();
|
||||
roomUnit.removeStatus(RoomUnitStatus.MOVE);
|
||||
roomUnit.setStatus(RoomUnitStatus.MOVE, roomUnit.getX() + "," + roomUnit.getY() + "," + roomUnit.getZ());
|
||||
roomUnit.statusUpdate(false);
|
||||
room.sendComposer(new RoomUserStatusComposer(roomUnit).compose());
|
||||
|
||||
Emulator.getThreading().run(() -> clearWalkInPlace(room, roomUnit, walkInPlaceUntil), WALK_IN_PLACE_DURATION_MS);
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean isActive(RoomUnit roomUnit) {
|
||||
Long activeUntil = getCachedTimestamp(roomUnit, CACHE_ACTIVE_UNTIL);
|
||||
return activeUntil != null && activeUntil > System.currentTimeMillis();
|
||||
}
|
||||
|
||||
private static boolean isWalkInPlaceActive(RoomUnit roomUnit) {
|
||||
Long walkInPlaceUntil = getCachedTimestamp(roomUnit, CACHE_WALK_IN_PLACE_UNTIL);
|
||||
|
||||
if (walkInPlaceUntil == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (walkInPlaceUntil <= System.currentTimeMillis()) {
|
||||
roomUnit.getCacheable().remove(CACHE_WALK_IN_PLACE_UNTIL);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static Long getCachedTimestamp(RoomUnit roomUnit, String key) {
|
||||
if (roomUnit == null || key == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Object value = roomUnit.getCacheable().get(key);
|
||||
|
||||
if (value instanceof Long) {
|
||||
return (Long) value;
|
||||
}
|
||||
|
||||
if (value instanceof Number) {
|
||||
return ((Number) value).longValue();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void clearWalkInPlace(Room room, RoomUnit roomUnit, long expectedUntil) {
|
||||
if (room == null || roomUnit == null || !room.isLoaded()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Long currentUntil = getCachedTimestamp(roomUnit, CACHE_WALK_IN_PLACE_UNTIL);
|
||||
if (currentUntil == null || currentUntil.longValue() != expectedUntil) {
|
||||
return;
|
||||
}
|
||||
|
||||
roomUnit.getCacheable().remove(CACHE_WALK_IN_PLACE_UNTIL);
|
||||
|
||||
if (roomUnit.hasStatus(RoomUnitStatus.MOVE) && !roomUnit.isWalking()) {
|
||||
roomUnit.removeStatus(RoomUnitStatus.MOVE);
|
||||
roomUnit.statusUpdate(false);
|
||||
room.sendComposer(new RoomUserStatusComposer(roomUnit).compose());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static class JsonData {
|
||||
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
package com.eu.habbo.habbohotel.items.interactions.wired.effects;
|
||||
|
||||
import com.eu.habbo.habbohotel.items.Item;
|
||||
import com.eu.habbo.habbohotel.wired.WiredEffectType;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredEvent;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredManager;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
public class WiredEffectNegativeSendSignal extends WiredEffectSendSignal {
|
||||
public static final WiredEffectType type = WiredEffectType.NEG_SEND_SIGNAL;
|
||||
|
||||
public WiredEffectNegativeSendSignal(ResultSet set, Item baseItem) throws SQLException {
|
||||
super(set, baseItem);
|
||||
}
|
||||
|
||||
public WiredEffectNegativeSendSignal(int id, int userId, Item item, String extradata, int limitedStack, int limitedSells) {
|
||||
super(id, userId, item, extradata, limitedStack, limitedSells);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean dispatchSignalEvent(WiredEvent event) {
|
||||
return WiredManager.dispatchEffectTriggeredEvent(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WiredEffectType getType() {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
package com.eu.habbo.habbohotel.items.interactions.wired.effects;
|
||||
|
||||
import com.eu.habbo.habbohotel.items.Item;
|
||||
import com.eu.habbo.habbohotel.wired.WiredEffectType;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredContext;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
public class WiredEffectNegativeTriggerStacks extends WiredEffectTriggerStacks {
|
||||
public static final WiredEffectType type = WiredEffectType.NEG_CALL_STACKS;
|
||||
|
||||
public WiredEffectNegativeTriggerStacks(ResultSet set, Item baseItem) throws SQLException {
|
||||
super(set, baseItem);
|
||||
}
|
||||
|
||||
public WiredEffectNegativeTriggerStacks(int id, int userId, Item item, String extradata, int limitedStack, int limitedSells) {
|
||||
super(id, userId, item, extradata, limitedStack, limitedSells);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(WiredContext ctx) {
|
||||
super.execute(ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public WiredEffectType getType() {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
+370
@@ -0,0 +1,370 @@
|
||||
package com.eu.habbo.habbohotel.items.interactions.wired.effects;
|
||||
|
||||
import com.eu.habbo.Emulator;
|
||||
import com.eu.habbo.habbohotel.gameclients.GameClient;
|
||||
import com.eu.habbo.habbohotel.items.Item;
|
||||
import com.eu.habbo.habbohotel.items.interactions.InteractionWiredEffect;
|
||||
import com.eu.habbo.habbohotel.items.interactions.wired.WiredSettings;
|
||||
import com.eu.habbo.habbohotel.rooms.Room;
|
||||
import com.eu.habbo.habbohotel.rooms.RoomUnit;
|
||||
import com.eu.habbo.habbohotel.rooms.WiredVariableDefinitionInfo;
|
||||
import com.eu.habbo.habbohotel.users.Habbo;
|
||||
import com.eu.habbo.habbohotel.users.HabboItem;
|
||||
import com.eu.habbo.habbohotel.wired.WiredEffectType;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredContext;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredContextVariableSupport;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredManager;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredSourceUtil;
|
||||
import com.eu.habbo.messages.ServerMessage;
|
||||
import com.eu.habbo.messages.incoming.wired.WiredSaveException;
|
||||
import gnu.trove.set.hash.THashSet;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class WiredEffectRemoveVariable extends InteractionWiredEffect {
|
||||
public static final WiredEffectType type = WiredEffectType.REMOVE_VAR;
|
||||
|
||||
public static final int TARGET_USER = 0;
|
||||
public static final int TARGET_FURNI = 1;
|
||||
public static final int TARGET_CONTEXT = 2;
|
||||
|
||||
private int variableItemId = 0;
|
||||
private int targetType = TARGET_USER;
|
||||
private int userSource = WiredSourceUtil.SOURCE_TRIGGER;
|
||||
private int furniSource = WiredSourceUtil.SOURCE_TRIGGER;
|
||||
private final THashSet<HabboItem> selectedFurni;
|
||||
|
||||
public WiredEffectRemoveVariable(ResultSet set, Item baseItem) throws SQLException {
|
||||
super(set, baseItem);
|
||||
this.selectedFurni = new THashSet<>();
|
||||
}
|
||||
|
||||
public WiredEffectRemoveVariable(int id, int userId, Item item, String extradata, int limitedStack, int limitedSells) {
|
||||
super(id, userId, item, extradata, limitedStack, limitedSells);
|
||||
this.selectedFurni = new THashSet<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(WiredContext ctx) {
|
||||
Room room = ctx.room();
|
||||
|
||||
if (room == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (this.targetType) {
|
||||
case TARGET_USER:
|
||||
this.executeUserVariables(ctx, room);
|
||||
return;
|
||||
case TARGET_FURNI:
|
||||
this.executeFurniVariables(ctx, room);
|
||||
return;
|
||||
case TARGET_CONTEXT:
|
||||
this.executeContextVariables(ctx, room);
|
||||
return;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private void executeUserVariables(WiredContext ctx, Room room) {
|
||||
WiredVariableDefinitionInfo definition = room.getUserVariableManager().getDefinitionInfo(this.variableItemId);
|
||||
|
||||
if (definition == null || definition.isReadOnly()) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<RoomUnit> users = WiredSourceUtil.resolveUsers(ctx, this.userSource);
|
||||
|
||||
for (RoomUnit roomUnit : users) {
|
||||
if (roomUnit == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Habbo habbo = room.getHabbo(roomUnit);
|
||||
|
||||
if (habbo == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
room.getUserVariableManager().removeVariable(habbo.getHabboInfo().getId(), this.variableItemId);
|
||||
}
|
||||
}
|
||||
|
||||
private void executeFurniVariables(WiredContext ctx, Room room) {
|
||||
WiredVariableDefinitionInfo definition = room.getFurniVariableManager().getDefinitionInfo(this.variableItemId);
|
||||
|
||||
if (definition == null || definition.isReadOnly()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.furniSource == WiredSourceUtil.SOURCE_SELECTED) {
|
||||
this.validateItems(this.selectedFurni);
|
||||
}
|
||||
|
||||
List<HabboItem> furni = WiredSourceUtil.resolveItems(ctx, this.furniSource, this.selectedFurni);
|
||||
|
||||
for (HabboItem item : furni) {
|
||||
if (item == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
room.getFurniVariableManager().removeVariable(item.getId(), this.variableItemId);
|
||||
}
|
||||
}
|
||||
|
||||
private void executeContextVariables(WiredContext ctx, Room room) {
|
||||
WiredVariableDefinitionInfo definition = WiredContextVariableSupport.getDefinitionInfo(room, this.variableItemId);
|
||||
|
||||
if (definition == null || definition.isReadOnly()) {
|
||||
return;
|
||||
}
|
||||
|
||||
WiredContextVariableSupport.removeVariable(ctx, room, this.variableItemId);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@Override
|
||||
public boolean execute(RoomUnit roomUnit, Room room, Object[] stuff) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serializeWiredData(ServerMessage message, Room room) {
|
||||
List<HabboItem> selectedItems = new ArrayList<>();
|
||||
|
||||
if (this.targetType == TARGET_FURNI && this.furniSource == WiredSourceUtil.SOURCE_SELECTED) {
|
||||
for (HabboItem item : this.selectedFurni) {
|
||||
if (item != null && room != null && room.getHabboItem(item.getId()) != null) {
|
||||
selectedItems.add(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
message.appendBoolean(false);
|
||||
message.appendInt(WiredManager.MAXIMUM_FURNI_SELECTION);
|
||||
message.appendInt(selectedItems.size());
|
||||
|
||||
for (HabboItem item : selectedItems) {
|
||||
message.appendInt(item.getId());
|
||||
}
|
||||
|
||||
message.appendInt(this.getBaseItem().getSpriteId());
|
||||
message.appendInt(this.getId());
|
||||
message.appendString(String.valueOf(this.variableItemId));
|
||||
message.appendInt(3);
|
||||
message.appendInt(this.targetType);
|
||||
message.appendInt(this.userSource);
|
||||
message.appendInt(this.furniSource);
|
||||
message.appendInt(0);
|
||||
message.appendInt(this.getType().code);
|
||||
message.appendInt(this.getDelay());
|
||||
message.appendInt(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean saveData(WiredSettings settings, GameClient gameClient) throws WiredSaveException {
|
||||
Room room = Emulator.getGameEnvironment().getRoomManager().getRoom(this.getRoomId());
|
||||
|
||||
if (room == null) {
|
||||
throw new WiredSaveException("Room not found");
|
||||
}
|
||||
|
||||
int[] intParams = settings.getIntParams();
|
||||
int nextTargetType = normalizeTargetType((intParams.length > 0) ? intParams[0] : TARGET_USER);
|
||||
int nextUserSource = normalizeUserSource((intParams.length > 1) ? intParams[1] : WiredSourceUtil.SOURCE_TRIGGER);
|
||||
int nextFurniSource = normalizeFurniSource((intParams.length > 2) ? intParams[2] : WiredSourceUtil.SOURCE_TRIGGER);
|
||||
int nextVariableItemId = parseVariableItemId(settings.getStringParam());
|
||||
|
||||
if (nextVariableItemId <= 0) {
|
||||
throw new WiredSaveException("wiredfurni.params.variables.validation.missing_variable");
|
||||
}
|
||||
|
||||
switch (nextTargetType) {
|
||||
case TARGET_USER:
|
||||
WiredVariableDefinitionInfo userDefinition = room.getUserVariableManager().getDefinitionInfo(nextVariableItemId);
|
||||
if (userDefinition == null || userDefinition.isReadOnly()) {
|
||||
throw new WiredSaveException("wiredfurni.params.variables.validation.invalid_variable");
|
||||
}
|
||||
break;
|
||||
case TARGET_FURNI:
|
||||
WiredVariableDefinitionInfo furniDefinition = room.getFurniVariableManager().getDefinitionInfo(nextVariableItemId);
|
||||
if (furniDefinition == null || furniDefinition.isReadOnly()) {
|
||||
throw new WiredSaveException("wiredfurni.params.variables.validation.invalid_variable");
|
||||
}
|
||||
break;
|
||||
case TARGET_CONTEXT:
|
||||
WiredVariableDefinitionInfo contextDefinition = WiredContextVariableSupport.getDefinitionInfo(room, nextVariableItemId);
|
||||
if (contextDefinition == null || contextDefinition.isReadOnly()) {
|
||||
throw new WiredSaveException("wiredfurni.params.variables.validation.invalid_variable");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new WiredSaveException("wiredfurni.params.variables.validation.invalid_variable");
|
||||
}
|
||||
|
||||
this.selectedFurni.clear();
|
||||
|
||||
if (nextTargetType == TARGET_FURNI && nextFurniSource == WiredSourceUtil.SOURCE_SELECTED) {
|
||||
int[] furniIds = settings.getFurniIds();
|
||||
int itemsCount = (furniIds != null) ? furniIds.length : 0;
|
||||
|
||||
if (itemsCount > Emulator.getConfig().getInt("hotel.wired.furni.selection.count")) {
|
||||
throw new WiredSaveException("Too many furni selected");
|
||||
}
|
||||
|
||||
for (int i = 0; i < itemsCount; i++) {
|
||||
int itemId = furniIds[i];
|
||||
HabboItem item = room.getHabboItem(itemId);
|
||||
|
||||
if (item == null) {
|
||||
throw new WiredSaveException(String.format("Item %s not found", itemId));
|
||||
}
|
||||
|
||||
this.selectedFurni.add(item);
|
||||
}
|
||||
}
|
||||
|
||||
this.variableItemId = nextVariableItemId;
|
||||
this.targetType = nextTargetType;
|
||||
this.userSource = nextUserSource;
|
||||
this.furniSource = nextFurniSource;
|
||||
this.setDelay(settings.getDelay());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getWiredData() {
|
||||
List<Integer> selectedItemIds = new ArrayList<>();
|
||||
|
||||
for (HabboItem item : this.selectedFurni) {
|
||||
if (item != null) {
|
||||
selectedItemIds.add(item.getId());
|
||||
}
|
||||
}
|
||||
|
||||
return WiredManager.getGson().toJson(new JsonData(this.variableItemId, this.targetType, this.userSource, this.furniSource, this.getDelay(), selectedItemIds));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadWiredData(ResultSet set, Room room) throws SQLException {
|
||||
this.onPickUp();
|
||||
|
||||
String wiredData = set.getString("wired_data");
|
||||
if (wiredData == null || wiredData.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (wiredData.startsWith("{")) {
|
||||
JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class);
|
||||
|
||||
if (data != null) {
|
||||
this.variableItemId = Math.max(0, data.variableItemId);
|
||||
this.targetType = normalizeTargetType(data.targetType);
|
||||
this.userSource = normalizeUserSource(data.userSource);
|
||||
this.furniSource = normalizeFurniSource(data.furniSource);
|
||||
this.setDelay(Math.max(0, data.delay));
|
||||
|
||||
if (room != null && data.selectedFurniIds != null) {
|
||||
for (Integer itemId : data.selectedFurniIds) {
|
||||
if (itemId == null || itemId <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
HabboItem item = room.getHabboItem(itemId);
|
||||
|
||||
if (item != null) {
|
||||
this.selectedFurni.add(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
this.variableItemId = Math.max(0, Integer.parseInt(wiredData.trim()));
|
||||
this.targetType = TARGET_USER;
|
||||
} catch (NumberFormatException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPickUp() {
|
||||
this.variableItemId = 0;
|
||||
this.targetType = TARGET_USER;
|
||||
this.userSource = WiredSourceUtil.SOURCE_TRIGGER;
|
||||
this.furniSource = WiredSourceUtil.SOURCE_TRIGGER;
|
||||
this.selectedFurni.clear();
|
||||
this.setDelay(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWalk(RoomUnit roomUnit, Room room, Object[] objects) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public WiredEffectType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
private static int normalizeTargetType(int value) {
|
||||
switch (value) {
|
||||
case TARGET_FURNI:
|
||||
case TARGET_CONTEXT:
|
||||
return value;
|
||||
default:
|
||||
return TARGET_USER;
|
||||
}
|
||||
}
|
||||
|
||||
private static int normalizeUserSource(int value) {
|
||||
return WiredSourceUtil.isDefaultUserSource(value) ? value : WiredSourceUtil.SOURCE_TRIGGER;
|
||||
}
|
||||
|
||||
private static int normalizeFurniSource(int value) {
|
||||
switch (value) {
|
||||
case WiredSourceUtil.SOURCE_SELECTED:
|
||||
case WiredSourceUtil.SOURCE_SELECTOR:
|
||||
case WiredSourceUtil.SOURCE_SIGNAL:
|
||||
return value;
|
||||
default:
|
||||
return WiredSourceUtil.SOURCE_TRIGGER;
|
||||
}
|
||||
}
|
||||
|
||||
private static int parseVariableItemId(String value) {
|
||||
if (value == null || value.trim().isEmpty()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
try {
|
||||
return Math.max(0, Integer.parseInt(value.trim()));
|
||||
} catch (NumberFormatException ignored) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static class JsonData {
|
||||
int variableItemId;
|
||||
int targetType;
|
||||
int userSource;
|
||||
int furniSource;
|
||||
int delay;
|
||||
List<Integer> selectedFurniIds;
|
||||
|
||||
JsonData(int variableItemId, int targetType, int userSource, int furniSource, int delay, List<Integer> selectedFurniIds) {
|
||||
this.variableItemId = variableItemId;
|
||||
this.targetType = targetType;
|
||||
this.userSource = userSource;
|
||||
this.furniSource = furniSource;
|
||||
this.delay = delay;
|
||||
this.selectedFurniIds = selectedFurniIds;
|
||||
}
|
||||
}
|
||||
}
|
||||
+77
-12
@@ -103,32 +103,52 @@ public class WiredEffectSendSignal extends InteractionWiredEffect {
|
||||
}
|
||||
LOGGER.debug("[SendSignal] Resolved {} antenna(s), firing signals", resolvedAntennas.size());
|
||||
|
||||
List<RoomUnit> forwardedUsers = WiredSourceUtil.resolveUsers(ctx, this.userForward);
|
||||
List<HabboItem> forwardedFurni = WiredSourceUtil.resolveItems(ctx, this.furniForward, this.forwardItems);
|
||||
RoomUnit triggeringUser = ctx.event().getOriginActor().orElseGet(() -> ctx.actor().orElse(null));
|
||||
List<RoomUnit> forwardedUsers = WiredSourceUtil.resolveUsersRaw(ctx, this.userForward);
|
||||
List<HabboItem> forwardedFurni = WiredSourceUtil.resolveItemsRaw(ctx, this.furniForward, this.forwardItems);
|
||||
|
||||
RoomUnit defaultUser = forwardedUsers.isEmpty() ? null : forwardedUsers.get(0);
|
||||
HabboItem defaultFurni = forwardedFurni.isEmpty() ? null : forwardedFurni.get(0);
|
||||
List<RoomUnit> usersToSend;
|
||||
if (signalPerUser) {
|
||||
LinkedHashMap<Integer, RoomUnit> mergedUsers = new LinkedHashMap<>();
|
||||
|
||||
Collection<RoomUnit> usersToSend = (signalPerUser && !forwardedUsers.isEmpty())
|
||||
? forwardedUsers
|
||||
: Collections.singletonList(defaultUser);
|
||||
if (triggeringUser != null) {
|
||||
mergedUsers.put(triggeringUser.getId(), triggeringUser);
|
||||
}
|
||||
|
||||
Collection<HabboItem> furniToSend = (signalPerFurni && !forwardedFurni.isEmpty())
|
||||
for (RoomUnit forwardedUser : forwardedUsers) {
|
||||
if (forwardedUser == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
mergedUsers.put(forwardedUser.getId(), forwardedUser);
|
||||
}
|
||||
|
||||
usersToSend = mergedUsers.isEmpty()
|
||||
? Collections.singletonList(null)
|
||||
: new ArrayList<>(mergedUsers.values());
|
||||
} else {
|
||||
usersToSend = Collections.singletonList(triggeringUser);
|
||||
}
|
||||
|
||||
Collection<HabboItem> furniToSend = !forwardedFurni.isEmpty()
|
||||
? forwardedFurni
|
||||
: Collections.singletonList(defaultFurni);
|
||||
: Collections.singletonList(null);
|
||||
|
||||
int nextDepth = currentDepth + 1;
|
||||
int signalUserCount = signalPerUser
|
||||
? (int) usersToSend.stream().filter(Objects::nonNull).count()
|
||||
: (!forwardedUsers.isEmpty() ? forwardedUsers.size() : (triggeringUser != null ? 1 : 0));
|
||||
|
||||
for (RoomUnit user : usersToSend) {
|
||||
for (HabboItem sourceItem : furniToSend) {
|
||||
for (HabboItem antenna : resolvedAntennas) {
|
||||
fireSignalAtAntenna(room, antenna, user, sourceItem, nextDepth);
|
||||
fireSignalAtAntenna(ctx, room, antenna, user, triggeringUser, sourceItem, signalUserCount, nextDepth);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void fireSignalAtAntenna(Room room, HabboItem antenna, RoomUnit actor, HabboItem sourceItem, int depth) {
|
||||
private void fireSignalAtAntenna(WiredContext ctx, Room room, HabboItem antenna, RoomUnit actor, RoomUnit originActor, HabboItem sourceItem, int signalUserCount, int depth) {
|
||||
if (antenna == null) return;
|
||||
RoomTile tile = room.getLayout().getTile(antenna.getX(), antenna.getY());
|
||||
if (tile == null) return;
|
||||
@@ -144,12 +164,16 @@ public class WiredEffectSendSignal extends InteractionWiredEffect {
|
||||
.tile(tile)
|
||||
.callStackDepth(depth)
|
||||
.signalChannel(signalChannel)
|
||||
.signalUserCount(signalUserCount)
|
||||
.signalFurniCount(sourceItem != null ? 1 : 0)
|
||||
.contextVariableScope(ctx.contextVariables())
|
||||
.triggeredByEffect(true);
|
||||
|
||||
if (actor != null) builder.actor(actor);
|
||||
if (originActor != null) builder.originActor(originActor);
|
||||
if (sourceItem != null) builder.sourceItem(sourceItem);
|
||||
|
||||
boolean result = WiredManager.handleEvent(builder.build());
|
||||
boolean result = dispatchSignalEvent(builder.build());
|
||||
LOGGER.debug("[SendSignal] handleEvent returned: {}", result);
|
||||
}
|
||||
|
||||
@@ -447,11 +471,52 @@ public class WiredEffectSendSignal extends InteractionWiredEffect {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean unlinkAntenna(int antennaItemId) {
|
||||
if (antennaItemId <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean changed = false;
|
||||
|
||||
Iterator<HabboItem> iterator = this.items.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
HabboItem item = iterator.next();
|
||||
|
||||
if (item == null || item.getId() != antennaItemId) {
|
||||
continue;
|
||||
}
|
||||
|
||||
iterator.remove();
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (this.antennaSource == antennaItemId) {
|
||||
if (!this.items.isEmpty()) {
|
||||
HabboItem firstItem = this.items.iterator().next();
|
||||
this.antennaSource = (firstItem != null) ? firstItem.getId() : ANTENNA_PICKED;
|
||||
} else {
|
||||
this.antennaSource = ANTENNA_PICKED;
|
||||
}
|
||||
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
this.needsUpdate(true);
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected long requiredCooldown() {
|
||||
return COOLDOWN_TRIGGER_STACKS;
|
||||
}
|
||||
|
||||
protected boolean dispatchSignalEvent(WiredEvent event) {
|
||||
return WiredManager.dispatchEffectTriggeredEvent(event);
|
||||
}
|
||||
|
||||
static class JsonData {
|
||||
int delay;
|
||||
List<Integer> itemIds;
|
||||
|
||||
+6
-7
@@ -7,16 +7,11 @@ import com.eu.habbo.habbohotel.items.interactions.InteractionWiredEffect;
|
||||
import com.eu.habbo.habbohotel.items.interactions.InteractionWiredTrigger;
|
||||
import com.eu.habbo.habbohotel.items.interactions.wired.WiredSettings;
|
||||
import com.eu.habbo.habbohotel.pets.RideablePet;
|
||||
import com.eu.habbo.habbohotel.rooms.Room;
|
||||
import com.eu.habbo.habbohotel.rooms.RoomTile;
|
||||
import com.eu.habbo.habbohotel.rooms.RoomTileState;
|
||||
import com.eu.habbo.habbohotel.rooms.RoomUnit;
|
||||
import com.eu.habbo.habbohotel.rooms.RoomUnitStatus;
|
||||
import com.eu.habbo.habbohotel.rooms.RoomUnitType;
|
||||
import com.eu.habbo.habbohotel.rooms.*;
|
||||
import com.eu.habbo.habbohotel.users.Habbo;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredContext;
|
||||
import com.eu.habbo.habbohotel.users.HabboItem;
|
||||
import com.eu.habbo.habbohotel.wired.WiredEffectType;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredContext;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredManager;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredSourceUtil;
|
||||
import com.eu.habbo.messages.ServerMessage;
|
||||
@@ -189,6 +184,10 @@ public class WiredEffectTeleport extends InteractionWiredEffect {
|
||||
throw new WiredSaveException("Too many furni selected");
|
||||
}
|
||||
|
||||
if (itemsCount > 0 && this.furniSource == WiredSourceUtil.SOURCE_TRIGGER) {
|
||||
this.furniSource = WiredSourceUtil.SOURCE_SELECTED;
|
||||
}
|
||||
|
||||
List<HabboItem> newItems = new ArrayList<>();
|
||||
|
||||
if (this.furniSource == WiredSourceUtil.SOURCE_SELECTED) {
|
||||
|
||||
+4
@@ -169,6 +169,10 @@ public class WiredEffectToggleFurni extends InteractionWiredEffect {
|
||||
throw new WiredSaveException("Too many furni selected");
|
||||
}
|
||||
|
||||
if (itemsCount > 0 && this.furniSource == WiredSourceUtil.SOURCE_TRIGGER) {
|
||||
this.furniSource = WiredSourceUtil.SOURCE_SELECTED;
|
||||
}
|
||||
|
||||
List<HabboItem> newItems = new ArrayList<>();
|
||||
if (this.furniSource == WiredSourceUtil.SOURCE_SELECTED) {
|
||||
for (int i = 0; i < itemsCount; i++) {
|
||||
|
||||
+4
@@ -153,6 +153,10 @@ public class WiredEffectToggleRandom extends InteractionWiredEffect {
|
||||
throw new WiredSaveException("Too many furni selected");
|
||||
}
|
||||
|
||||
if (itemsCount > 0 && this.furniSource == WiredSourceUtil.SOURCE_TRIGGER) {
|
||||
this.furniSource = WiredSourceUtil.SOURCE_SELECTED;
|
||||
}
|
||||
|
||||
List<HabboItem> newItems = new ArrayList<>();
|
||||
|
||||
if (this.furniSource == WiredSourceUtil.SOURCE_SELECTED) {
|
||||
|
||||
+33
-26
@@ -28,8 +28,8 @@ import java.util.stream.Collectors;
|
||||
public class WiredEffectTriggerStacks extends InteractionWiredEffect {
|
||||
public static final WiredEffectType type = WiredEffectType.CALL_STACKS;
|
||||
|
||||
private THashSet<HabboItem> items;
|
||||
private int furniSource = WiredSourceUtil.SOURCE_TRIGGER;
|
||||
protected THashSet<HabboItem> items;
|
||||
protected int furniSource = WiredSourceUtil.SOURCE_TRIGGER;
|
||||
|
||||
public WiredEffectTriggerStacks(ResultSet set, Item baseItem) throws SQLException {
|
||||
super(set, baseItem);
|
||||
@@ -101,6 +101,10 @@ public class WiredEffectTriggerStacks extends InteractionWiredEffect {
|
||||
throw new WiredSaveException("Too many furni selected");
|
||||
}
|
||||
|
||||
if (itemsCount > 0 && this.furniSource == WiredSourceUtil.SOURCE_TRIGGER) {
|
||||
this.furniSource = WiredSourceUtil.SOURCE_SELECTED;
|
||||
}
|
||||
|
||||
List<HabboItem> newItems = new ArrayList<>();
|
||||
|
||||
if (this.furniSource == WiredSourceUtil.SOURCE_SELECTED) {
|
||||
@@ -132,7 +136,7 @@ public class WiredEffectTriggerStacks extends InteractionWiredEffect {
|
||||
/**
|
||||
* Maximum recursion depth to prevent infinite loops when trigger stacks call each other.
|
||||
*/
|
||||
private static final int MAX_STACK_DEPTH = 10;
|
||||
protected static final int MAX_STACK_DEPTH = 10;
|
||||
|
||||
@Override
|
||||
public void execute(WiredContext ctx) {
|
||||
@@ -147,30 +151,8 @@ public class WiredEffectTriggerStacks extends InteractionWiredEffect {
|
||||
return;
|
||||
}
|
||||
|
||||
List<HabboItem> effectiveItems = WiredSourceUtil.resolveItems(ctx, this.furniSource, this.items);
|
||||
THashSet<RoomTile> usedTiles = collectTargetTiles(room, ctx);
|
||||
|
||||
THashSet<RoomTile> usedTiles = new THashSet<>();
|
||||
|
||||
for (HabboItem item : effectiveItems) {
|
||||
if (item == null) continue;
|
||||
|
||||
boolean found = false;
|
||||
for (RoomTile tile : usedTiles) {
|
||||
if (tile.x == item.getX() && tile.y == item.getY()) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
RoomTile tile = room.getLayout().getTile(item.getX(), item.getY());
|
||||
if (tile != null) {
|
||||
usedTiles.add(tile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Execute effects at tiles with incremented call stack depth
|
||||
WiredManager.executeEffectsAtTiles(usedTiles, roomUnit, room, currentDepth + 1);
|
||||
}
|
||||
|
||||
@@ -246,6 +228,31 @@ public class WiredEffectTriggerStacks extends InteractionWiredEffect {
|
||||
return COOLDOWN_TRIGGER_STACKS;
|
||||
}
|
||||
|
||||
protected List<HabboItem> resolveEffectiveItems(WiredContext ctx) {
|
||||
return WiredSourceUtil.resolveItems(ctx, this.furniSource, this.items);
|
||||
}
|
||||
|
||||
protected THashSet<RoomTile> collectTargetTiles(Room room, WiredContext ctx) {
|
||||
THashSet<RoomTile> usedTiles = new THashSet<>();
|
||||
|
||||
if (room == null || room.getLayout() == null) {
|
||||
return usedTiles;
|
||||
}
|
||||
|
||||
for (HabboItem item : resolveEffectiveItems(ctx)) {
|
||||
if (item == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
RoomTile tile = room.getLayout().getTile(item.getX(), item.getY());
|
||||
if (tile != null) {
|
||||
usedTiles.add(tile);
|
||||
}
|
||||
}
|
||||
|
||||
return usedTiles;
|
||||
}
|
||||
|
||||
static class JsonData {
|
||||
int delay;
|
||||
List<Integer> itemIds;
|
||||
|
||||
+4
@@ -275,6 +275,10 @@ public abstract class WiredEffectUserFurniBase extends InteractionWiredEffect {
|
||||
throw new WiredSaveException("Too many furni selected");
|
||||
}
|
||||
|
||||
if (settings.getFurniIds().length > 0 && this.furniSource == WiredSourceUtil.SOURCE_TRIGGER) {
|
||||
this.furniSource = WiredSourceUtil.SOURCE_SELECTED;
|
||||
}
|
||||
|
||||
Room room = Emulator.getGameEnvironment().getRoomManager().getRoom(this.getRoomId());
|
||||
if (room == null) {
|
||||
throw new WiredSaveException("Room not found");
|
||||
|
||||
+9
-3
@@ -14,6 +14,7 @@ import com.eu.habbo.habbohotel.users.HabboItem;
|
||||
import com.eu.habbo.habbohotel.wired.WiredEffectType;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredContext;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredManager;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredMovementPhysics;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredMoveCarryHelper;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredSourceUtil;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredUserMovementHelper;
|
||||
@@ -47,6 +48,7 @@ public class WiredEffectUserToFurni extends WiredEffectUserFurniBase {
|
||||
public void execute(WiredContext ctx) {
|
||||
Room room = ctx.room();
|
||||
HabboItem item = this.resolveLastItem(ctx);
|
||||
WiredMovementPhysics movementPhysics = WiredMoveCarryHelper.getUserMovementPhysics(room, this, ctx);
|
||||
|
||||
if (room == null || item == null) {
|
||||
return;
|
||||
@@ -58,7 +60,7 @@ public class WiredEffectUserToFurni extends WiredEffectUserFurniBase {
|
||||
}
|
||||
|
||||
for (Habbo habbo : this.resolveHabbos(room, ctx)) {
|
||||
this.moveHabboSmooth(room, habbo, item, targetTile);
|
||||
this.moveHabboSmooth(room, habbo, item, targetTile, movementPhysics);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -197,6 +199,10 @@ public class WiredEffectUserToFurni extends WiredEffectUserFurniBase {
|
||||
throw new WiredSaveException("Too many furni selected");
|
||||
}
|
||||
|
||||
if (settings.getFurniIds().length > 0 && this.furniSource == WiredSourceUtil.SOURCE_TRIGGER) {
|
||||
this.furniSource = WiredSourceUtil.SOURCE_SELECTED;
|
||||
}
|
||||
|
||||
Room room = Emulator.getGameEnvironment().getRoomManager().getRoom(this.getRoomId());
|
||||
if (room == null) {
|
||||
throw new WiredSaveException("Room not found");
|
||||
@@ -227,7 +233,7 @@ public class WiredEffectUserToFurni extends WiredEffectUserFurniBase {
|
||||
return true;
|
||||
}
|
||||
|
||||
private void moveHabboSmooth(Room room, Habbo habbo, HabboItem item, RoomTile targetTile) {
|
||||
private void moveHabboSmooth(Room room, Habbo habbo, HabboItem item, RoomTile targetTile, WiredMovementPhysics movementPhysics) {
|
||||
if (room == null || habbo == null || item == null || targetTile == null || habbo.getRoomUnit() == null) {
|
||||
return;
|
||||
}
|
||||
@@ -245,7 +251,7 @@ public class WiredEffectUserToFurni extends WiredEffectUserFurniBase {
|
||||
double newZ = item.getZ() + Item.getCurrentHeight(item);
|
||||
int animationDuration = noAnimation ? 0 : WiredMoveCarryHelper.getAnimationDuration(room, this, WiredUserMovementHelper.DEFAULT_ANIMATION_DURATION);
|
||||
if (!WiredUserMovementHelper.moveUser(room, roomUnit, targetTile, newZ,
|
||||
roomUnit.getBodyRotation(), roomUnit.getHeadRotation(), animationDuration, noAnimation)) {
|
||||
roomUnit.getBodyRotation(), roomUnit.getHeadRotation(), animationDuration, noAnimation, movementPhysics)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
+129
-12
@@ -22,13 +22,23 @@ import gnu.trove.procedure.TObjectProcedure;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class WiredEffectWhisper extends InteractionWiredEffect {
|
||||
public static final WiredEffectType type = WiredEffectType.SHOW_MESSAGE;
|
||||
protected static final int VISIBILITY_SOURCE_USERS = 0;
|
||||
protected static final int VISIBILITY_ALL_ROOM_USERS = 1;
|
||||
private static final long DELIVERY_DEDUP_TTL_MS = 60_000L;
|
||||
private static final int DELIVERY_DEDUP_CLEANUP_THRESHOLD = 512;
|
||||
private static final ConcurrentHashMap<String, Long> DELIVERY_DEDUP = new ConcurrentHashMap<>();
|
||||
|
||||
protected String message = "";
|
||||
protected int userSource = WiredSourceUtil.SOURCE_TRIGGER;
|
||||
protected int visibilitySelection = VISIBILITY_SOURCE_USERS;
|
||||
protected int bubbleStyle = RoomChatMessageBubbles.WIRED.getType();
|
||||
|
||||
public WiredEffectWhisper(ResultSet set, Item baseItem) throws SQLException {
|
||||
super(set, baseItem);
|
||||
@@ -46,8 +56,10 @@ public class WiredEffectWhisper extends InteractionWiredEffect {
|
||||
message.appendInt(this.getBaseItem().getSpriteId());
|
||||
message.appendInt(this.getId());
|
||||
message.appendString(this.message);
|
||||
message.appendInt(1);
|
||||
message.appendInt(3);
|
||||
message.appendInt(this.userSource);
|
||||
message.appendInt(this.visibilitySelection);
|
||||
message.appendInt(this.bubbleStyle);
|
||||
message.appendInt(0);
|
||||
message.appendInt(type.code);
|
||||
message.appendInt(this.getDelay());
|
||||
@@ -77,6 +89,10 @@ public class WiredEffectWhisper extends InteractionWiredEffect {
|
||||
String message = settings.getStringParam();
|
||||
int[] params = settings.getIntParams();
|
||||
this.userSource = (params.length > 0) ? params[0] : WiredSourceUtil.SOURCE_TRIGGER;
|
||||
this.visibilitySelection = (params.length > 1 && params[1] == VISIBILITY_ALL_ROOM_USERS)
|
||||
? VISIBILITY_ALL_ROOM_USERS
|
||||
: VISIBILITY_SOURCE_USERS;
|
||||
this.bubbleStyle = (params.length > 2) ? params[2] : RoomChatMessageBubbles.WIRED.getType();
|
||||
|
||||
if(gameClient.getHabbo() == null || !gameClient.getHabbo().hasPermission(Permission.ACC_SUPERWIRED)) {
|
||||
message = Emulator.getGameEnvironment().getWordFilter().filter(message, null);
|
||||
@@ -97,17 +113,106 @@ public class WiredEffectWhisper extends InteractionWiredEffect {
|
||||
return WiredSourceUtil.resolveUsers(ctx, this.userSource);
|
||||
}
|
||||
|
||||
protected List<Habbo> resolveRecipients(WiredContext ctx, List<RoomUnit> sourceUsers) {
|
||||
Room room = ctx.room();
|
||||
LinkedHashMap<Integer, Habbo> recipients = new LinkedHashMap<>();
|
||||
|
||||
if (room == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
if (this.visibilitySelection == VISIBILITY_ALL_ROOM_USERS) {
|
||||
for (Habbo habbo : room.getCurrentHabbos().values()) {
|
||||
addRecipient(recipients, habbo);
|
||||
}
|
||||
} else {
|
||||
for (RoomUnit roomUnit : sourceUsers) {
|
||||
addRecipient(recipients, room.getHabbo(roomUnit));
|
||||
}
|
||||
}
|
||||
|
||||
return new ArrayList<>(recipients.values());
|
||||
}
|
||||
|
||||
protected Habbo resolveMessageSourceHabbo(WiredContext ctx, List<RoomUnit> sourceUsers) {
|
||||
Room room = ctx.room();
|
||||
|
||||
if (room != null) {
|
||||
for (RoomUnit roomUnit : sourceUsers) {
|
||||
Habbo habbo = room.getHabbo(roomUnit);
|
||||
if (habbo != null) {
|
||||
return habbo;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (room == null) ? null : ctx.actor().map(roomUnit -> room.getHabbo(roomUnit)).orElse(null);
|
||||
}
|
||||
|
||||
protected String buildMessage(WiredContext ctx, Habbo referenceHabbo) {
|
||||
String username = "";
|
||||
|
||||
if (referenceHabbo != null && referenceHabbo.getHabboInfo() != null) {
|
||||
username = referenceHabbo.getHabboInfo().getUsername();
|
||||
}
|
||||
|
||||
String msg = this.message
|
||||
.replace("%user%", username)
|
||||
.replace("%online_count%", Emulator.getGameEnvironment().getHabboManager().getOnlineCount() + "")
|
||||
.replace("%room_count%", Emulator.getGameEnvironment().getRoomManager().getActiveRooms().size() + "");
|
||||
|
||||
return WiredTextPlaceholderUtil.applyUsernamePlaceholders(ctx, msg);
|
||||
}
|
||||
|
||||
private void addRecipient(LinkedHashMap<Integer, Habbo> recipients, Habbo habbo) {
|
||||
if (habbo == null || habbo.getHabboInfo() == null || habbo.getClient() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
recipients.putIfAbsent(habbo.getHabboInfo().getId(), habbo);
|
||||
}
|
||||
|
||||
protected boolean shouldDeliverToRecipient(WiredContext ctx, Habbo habbo) {
|
||||
if (ctx == null || habbo == null || habbo.getHabboInfo() == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
long now = System.currentTimeMillis();
|
||||
cleanupDeliveryDedup(now);
|
||||
|
||||
String deliveryKey = buildDeliveryKey(ctx, habbo);
|
||||
|
||||
return DELIVERY_DEDUP.putIfAbsent(deliveryKey, now) == null;
|
||||
}
|
||||
|
||||
private String buildDeliveryKey(WiredContext ctx, Habbo habbo) {
|
||||
return ctx.room().getId() + ":" + this.getId() + ":" + habbo.getHabboInfo().getId() + ":" + ctx.event().getCreatedAtMs();
|
||||
}
|
||||
|
||||
private static void cleanupDeliveryDedup(long now) {
|
||||
if (DELIVERY_DEDUP.size() < DELIVERY_DEDUP_CLEANUP_THRESHOLD) {
|
||||
return;
|
||||
}
|
||||
|
||||
DELIVERY_DEDUP.entrySet().removeIf(entry -> (now - entry.getValue()) > DELIVERY_DEDUP_TTL_MS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(WiredContext ctx) {
|
||||
Room room = ctx.room();
|
||||
if (this.message.length() > 0) {
|
||||
for (RoomUnit roomUnit : resolveUsers(ctx)) {
|
||||
Habbo habbo = room.getHabbo(roomUnit);
|
||||
if (habbo == null) continue;
|
||||
List<RoomUnit> sourceUsers = resolveUsers(ctx);
|
||||
List<Habbo> recipients = resolveRecipients(ctx, sourceUsers);
|
||||
Habbo sharedSourceHabbo = (this.visibilitySelection == VISIBILITY_ALL_ROOM_USERS)
|
||||
? resolveMessageSourceHabbo(ctx, sourceUsers)
|
||||
: null;
|
||||
|
||||
String msg = this.message.replace("%user%", habbo.getHabboInfo().getUsername()).replace("%online_count%", Emulator.getGameEnvironment().getHabboManager().getOnlineCount() + "").replace("%room_count%", Emulator.getGameEnvironment().getRoomManager().getActiveRooms().size() + "");
|
||||
msg = WiredTextPlaceholderUtil.applyUsernamePlaceholders(ctx, msg);
|
||||
habbo.getClient().sendResponse(new RoomUserWhisperComposer(new RoomChatMessage(msg, habbo, habbo, RoomChatMessageBubbles.WIRED)));
|
||||
for (Habbo habbo : recipients) {
|
||||
if (!shouldDeliverToRecipient(ctx, habbo)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String msg = buildMessage(ctx, (sharedSourceHabbo != null) ? sharedSourceHabbo : habbo);
|
||||
habbo.getClient().sendResponse(new RoomUserWhisperComposer(new RoomChatMessage(msg, habbo, habbo, RoomChatMessageBubbles.getBubble(this.bubbleStyle))));
|
||||
|
||||
if (habbo.getRoomUnit().isIdle()) {
|
||||
habbo.getRoomUnit().getRoom().unIdle(habbo);
|
||||
@@ -124,7 +229,7 @@ public class WiredEffectWhisper extends InteractionWiredEffect {
|
||||
|
||||
@Override
|
||||
public String getWiredData() {
|
||||
return WiredManager.getGson().toJson(new JsonData(this.message, this.getDelay(), this.userSource));
|
||||
return WiredManager.getGson().toJson(new JsonData(this.message, this.getDelay(), this.userSource, this.visibilitySelection, this.bubbleStyle));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -135,7 +240,11 @@ public class WiredEffectWhisper extends InteractionWiredEffect {
|
||||
JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class);
|
||||
this.setDelay(data.delay);
|
||||
this.message = data.message;
|
||||
this.userSource = data.userSource;
|
||||
this.userSource = (data.userSource != null) ? data.userSource : WiredSourceUtil.SOURCE_TRIGGER;
|
||||
this.visibilitySelection = (data.visibilitySelection != null && data.visibilitySelection == VISIBILITY_ALL_ROOM_USERS)
|
||||
? VISIBILITY_ALL_ROOM_USERS
|
||||
: VISIBILITY_SOURCE_USERS;
|
||||
this.bubbleStyle = (data.bubbleStyle != null) ? data.bubbleStyle : RoomChatMessageBubbles.WIRED.getType();
|
||||
}
|
||||
else {
|
||||
this.message = "";
|
||||
@@ -146,6 +255,8 @@ public class WiredEffectWhisper extends InteractionWiredEffect {
|
||||
}
|
||||
|
||||
this.userSource = WiredSourceUtil.SOURCE_TRIGGER;
|
||||
this.visibilitySelection = VISIBILITY_SOURCE_USERS;
|
||||
this.bubbleStyle = RoomChatMessageBubbles.WIRED.getType();
|
||||
this.needsUpdate(true);
|
||||
}
|
||||
}
|
||||
@@ -154,6 +265,8 @@ public class WiredEffectWhisper extends InteractionWiredEffect {
|
||||
public void onPickUp() {
|
||||
this.message = "";
|
||||
this.userSource = WiredSourceUtil.SOURCE_TRIGGER;
|
||||
this.visibilitySelection = VISIBILITY_SOURCE_USERS;
|
||||
this.bubbleStyle = RoomChatMessageBubbles.WIRED.getType();
|
||||
this.setDelay(0);
|
||||
}
|
||||
|
||||
@@ -170,12 +283,16 @@ public class WiredEffectWhisper extends InteractionWiredEffect {
|
||||
static class JsonData {
|
||||
String message;
|
||||
int delay;
|
||||
int userSource;
|
||||
Integer userSource;
|
||||
Integer visibilitySelection;
|
||||
Integer bubbleStyle;
|
||||
|
||||
public JsonData(String message, int delay, int userSource) {
|
||||
public JsonData(String message, int delay, int userSource, int visibilitySelection, int bubbleStyle) {
|
||||
this.message = message;
|
||||
this.delay = delay;
|
||||
this.userSource = userSource;
|
||||
this.visibilitySelection = visibilitySelection;
|
||||
this.bubbleStyle = bubbleStyle;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+132
@@ -0,0 +1,132 @@
|
||||
package com.eu.habbo.habbohotel.items.interactions.wired.extra;
|
||||
|
||||
import com.eu.habbo.Emulator;
|
||||
import com.eu.habbo.habbohotel.gameclients.GameClient;
|
||||
import com.eu.habbo.habbohotel.items.Item;
|
||||
import com.eu.habbo.habbohotel.items.interactions.InteractionWiredExtra;
|
||||
import com.eu.habbo.habbohotel.items.interactions.wired.WiredSettings;
|
||||
import com.eu.habbo.habbohotel.rooms.Room;
|
||||
import com.eu.habbo.habbohotel.rooms.RoomUnit;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredContextVariableSupport;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredManager;
|
||||
import com.eu.habbo.messages.ServerMessage;
|
||||
import com.eu.habbo.messages.incoming.wired.WiredSaveException;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
public class WiredExtraContextVariable extends InteractionWiredExtra {
|
||||
public static final int CODE = 84;
|
||||
|
||||
private String variableName = "";
|
||||
private boolean hasValue = false;
|
||||
|
||||
public WiredExtraContextVariable(ResultSet set, Item baseItem) throws SQLException {
|
||||
super(set, baseItem);
|
||||
}
|
||||
|
||||
public WiredExtraContextVariable(int id, int userId, Item item, String extradata, int limitedStack, int limitedSells) {
|
||||
super(id, userId, item, extradata, limitedStack, limitedSells);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean execute(RoomUnit roomUnit, Room room, Object[] stuff) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean saveData(WiredSettings settings, GameClient gameClient) throws WiredSaveException {
|
||||
Room room = Emulator.getGameEnvironment().getRoomManager().getRoom(this.getRoomId());
|
||||
if (room == null) {
|
||||
throw new WiredSaveException("Room not found");
|
||||
}
|
||||
|
||||
int[] intParams = settings.getIntParams();
|
||||
String normalizedName = WiredVariableNameValidator.normalizeForSave(settings.getStringParam());
|
||||
|
||||
WiredVariableNameValidator.validateDefinitionName(room, this.getId(), normalizedName);
|
||||
|
||||
this.variableName = normalizedName;
|
||||
this.hasValue = (intParams.length > 0) && (intParams[0] == 1);
|
||||
|
||||
WiredContextVariableSupport.broadcastDefinitions(room);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getWiredData() {
|
||||
return WiredManager.getGson().toJson(new JsonData(this.variableName, this.hasValue));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serializeWiredData(ServerMessage message, Room room) {
|
||||
message.appendBoolean(false);
|
||||
message.appendInt(0);
|
||||
message.appendInt(0);
|
||||
message.appendInt(this.getBaseItem().getSpriteId());
|
||||
message.appendInt(this.getId());
|
||||
message.appendString(this.variableName);
|
||||
message.appendInt(1);
|
||||
message.appendInt(this.hasValue ? 1 : 0);
|
||||
message.appendInt(0);
|
||||
message.appendInt(CODE);
|
||||
message.appendInt(0);
|
||||
message.appendInt(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadWiredData(ResultSet set, Room room) throws SQLException {
|
||||
this.onPickUp();
|
||||
|
||||
String wiredData = set.getString("wired_data");
|
||||
if (wiredData == null || wiredData.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (wiredData.startsWith("{")) {
|
||||
JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class);
|
||||
|
||||
if (data != null) {
|
||||
this.variableName = WiredVariableNameValidator.normalizeLegacy(data.variableName);
|
||||
this.hasValue = data.hasValue;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.variableName = WiredVariableNameValidator.normalizeLegacy(wiredData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPickUp() {
|
||||
this.variableName = "";
|
||||
this.hasValue = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWalk(RoomUnit roomUnit, Room room, Object[] objects) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasConfiguration() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public String getVariableName() {
|
||||
return this.variableName;
|
||||
}
|
||||
|
||||
public boolean hasValue() {
|
||||
return this.hasValue;
|
||||
}
|
||||
|
||||
static class JsonData {
|
||||
String variableName;
|
||||
boolean hasValue;
|
||||
|
||||
JsonData(String variableName, boolean hasValue) {
|
||||
this.variableName = variableName;
|
||||
this.hasValue = hasValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
package com.eu.habbo.habbohotel.items.interactions.wired.extra;
|
||||
|
||||
import com.eu.habbo.habbohotel.items.Item;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
public class WiredExtraFilterFurniByVariable extends WiredExtraVariableFilterBase {
|
||||
public static final int CODE = 78;
|
||||
|
||||
public WiredExtraFilterFurniByVariable(ResultSet set, Item baseItem) throws SQLException {
|
||||
super(set, baseItem);
|
||||
}
|
||||
|
||||
public WiredExtraFilterFurniByVariable(int id, int userId, Item item, String extradata, int limitedStack, int limitedSells) {
|
||||
super(id, userId, item, extradata, limitedStack, limitedSells);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getVariableTargetType() {
|
||||
return TARGET_FURNI;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getCode() {
|
||||
return CODE;
|
||||
}
|
||||
}
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
package com.eu.habbo.habbohotel.items.interactions.wired.extra;
|
||||
|
||||
import com.eu.habbo.habbohotel.items.Item;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
public class WiredExtraFilterUsersByVariable extends WiredExtraVariableFilterBase {
|
||||
public static final int CODE = 77;
|
||||
|
||||
public WiredExtraFilterUsersByVariable(ResultSet set, Item baseItem) throws SQLException {
|
||||
super(set, baseItem);
|
||||
}
|
||||
|
||||
public WiredExtraFilterUsersByVariable(int id, int userId, Item item, String extradata, int limitedStack, int limitedSells) {
|
||||
super(id, userId, item, extradata, limitedStack, limitedSells);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getVariableTargetType() {
|
||||
return TARGET_USER;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getCode() {
|
||||
return CODE;
|
||||
}
|
||||
}
|
||||
+157
@@ -0,0 +1,157 @@
|
||||
package com.eu.habbo.habbohotel.items.interactions.wired.extra;
|
||||
|
||||
import com.eu.habbo.Emulator;
|
||||
import com.eu.habbo.habbohotel.gameclients.GameClient;
|
||||
import com.eu.habbo.habbohotel.items.Item;
|
||||
import com.eu.habbo.habbohotel.items.interactions.InteractionWiredExtra;
|
||||
import com.eu.habbo.habbohotel.items.interactions.wired.WiredSettings;
|
||||
import com.eu.habbo.habbohotel.rooms.Room;
|
||||
import com.eu.habbo.habbohotel.rooms.RoomUnit;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredManager;
|
||||
import com.eu.habbo.messages.ServerMessage;
|
||||
import com.eu.habbo.messages.incoming.wired.WiredSaveException;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
public class WiredExtraFurniVariable extends InteractionWiredExtra {
|
||||
public static final int CODE = 71;
|
||||
public static final int AVAILABILITY_ROOM_ACTIVE = 1;
|
||||
public static final int AVAILABILITY_PERMANENT = 10;
|
||||
|
||||
private String variableName = "";
|
||||
private boolean hasValue = false;
|
||||
private int availability = AVAILABILITY_ROOM_ACTIVE;
|
||||
|
||||
public WiredExtraFurniVariable(ResultSet set, Item baseItem) throws SQLException {
|
||||
super(set, baseItem);
|
||||
}
|
||||
|
||||
public WiredExtraFurniVariable(int id, int userId, Item item, String extradata, int limitedStack, int limitedSells) {
|
||||
super(id, userId, item, extradata, limitedStack, limitedSells);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean execute(RoomUnit roomUnit, Room room, Object[] stuff) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean saveData(WiredSettings settings, GameClient gameClient) throws WiredSaveException {
|
||||
int[] intParams = settings.getIntParams();
|
||||
String normalizedName = WiredVariableNameValidator.normalizeForSave(settings.getStringParam());
|
||||
|
||||
Room room = Emulator.getGameEnvironment().getRoomManager().getRoom(this.getRoomId());
|
||||
|
||||
if (room == null) {
|
||||
throw new WiredSaveException("Room not found");
|
||||
}
|
||||
|
||||
WiredVariableNameValidator.validateDefinitionName(room, this.getId(), normalizedName);
|
||||
|
||||
this.variableName = normalizedName;
|
||||
this.hasValue = (intParams.length > 0) && (intParams[0] == 1);
|
||||
this.availability = normalizeAvailability((intParams.length > 1) ? intParams[1] : AVAILABILITY_ROOM_ACTIVE);
|
||||
|
||||
room.getFurniVariableManager().handleDefinitionUpdated(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getWiredData() {
|
||||
return WiredManager.getGson().toJson(new JsonData(this.variableName, this.hasValue, this.availability));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serializeWiredData(ServerMessage message, Room room) {
|
||||
message.appendBoolean(false);
|
||||
message.appendInt(0);
|
||||
message.appendInt(0);
|
||||
message.appendInt(this.getBaseItem().getSpriteId());
|
||||
message.appendInt(this.getId());
|
||||
message.appendString(this.variableName);
|
||||
message.appendInt(2);
|
||||
message.appendInt(this.hasValue ? 1 : 0);
|
||||
message.appendInt(this.availability);
|
||||
message.appendInt(0);
|
||||
message.appendInt(CODE);
|
||||
message.appendInt(0);
|
||||
message.appendInt(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadWiredData(ResultSet set, Room room) throws SQLException {
|
||||
this.onPickUp();
|
||||
|
||||
String wiredData = set.getString("wired_data");
|
||||
if (wiredData == null || wiredData.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (wiredData.startsWith("{")) {
|
||||
JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class);
|
||||
|
||||
if (data != null) {
|
||||
this.variableName = WiredVariableNameValidator.normalizeLegacy(data.variableName);
|
||||
this.hasValue = data.hasValue;
|
||||
this.availability = normalizeAvailability(data.availability);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.variableName = WiredVariableNameValidator.normalizeLegacy(wiredData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPickUp() {
|
||||
this.variableName = "";
|
||||
this.hasValue = false;
|
||||
this.availability = AVAILABILITY_ROOM_ACTIVE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWalk(RoomUnit roomUnit, Room room, Object[] objects) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasConfiguration() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public String getVariableName() {
|
||||
return this.variableName;
|
||||
}
|
||||
|
||||
public boolean hasValue() {
|
||||
return this.hasValue;
|
||||
}
|
||||
|
||||
public int getAvailability() {
|
||||
return this.availability;
|
||||
}
|
||||
|
||||
public boolean isPermanentAvailability() {
|
||||
return this.availability == AVAILABILITY_PERMANENT;
|
||||
}
|
||||
|
||||
private static int normalizeAvailability(int value) {
|
||||
if (value == AVAILABILITY_PERMANENT) {
|
||||
return AVAILABILITY_PERMANENT;
|
||||
}
|
||||
|
||||
return AVAILABILITY_ROOM_ACTIVE;
|
||||
}
|
||||
|
||||
static class JsonData {
|
||||
String variableName;
|
||||
boolean hasValue;
|
||||
int availability;
|
||||
|
||||
JsonData(String variableName, boolean hasValue, int availability) {
|
||||
this.variableName = variableName;
|
||||
this.hasValue = hasValue;
|
||||
this.availability = availability;
|
||||
}
|
||||
}
|
||||
}
|
||||
+159
@@ -0,0 +1,159 @@
|
||||
package com.eu.habbo.habbohotel.items.interactions.wired.extra;
|
||||
|
||||
import com.eu.habbo.Emulator;
|
||||
import com.eu.habbo.habbohotel.gameclients.GameClient;
|
||||
import com.eu.habbo.habbohotel.items.Item;
|
||||
import com.eu.habbo.habbohotel.items.interactions.InteractionWiredExtra;
|
||||
import com.eu.habbo.habbohotel.items.interactions.wired.WiredSettings;
|
||||
import com.eu.habbo.habbohotel.rooms.Room;
|
||||
import com.eu.habbo.habbohotel.rooms.RoomUnit;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredManager;
|
||||
import com.eu.habbo.messages.ServerMessage;
|
||||
import com.eu.habbo.messages.incoming.wired.WiredSaveException;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
public class WiredExtraRoomVariable extends InteractionWiredExtra {
|
||||
public static final int CODE = 72;
|
||||
public static final int AVAILABILITY_ROOM_ACTIVE = 1;
|
||||
public static final int AVAILABILITY_PERMANENT = 10;
|
||||
public static final int AVAILABILITY_SHARED = 11;
|
||||
|
||||
private String variableName = "";
|
||||
private int availability = AVAILABILITY_ROOM_ACTIVE;
|
||||
|
||||
public WiredExtraRoomVariable(ResultSet set, Item baseItem) throws SQLException {
|
||||
super(set, baseItem);
|
||||
}
|
||||
|
||||
public WiredExtraRoomVariable(int id, int userId, Item item, String extradata, int limitedStack, int limitedSells) {
|
||||
super(id, userId, item, extradata, limitedStack, limitedSells);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean execute(RoomUnit roomUnit, Room room, Object[] stuff) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean saveData(WiredSettings settings, GameClient gameClient) throws WiredSaveException {
|
||||
String normalizedName = WiredVariableNameValidator.normalizeForSave(settings.getStringParam());
|
||||
|
||||
Room room = Emulator.getGameEnvironment().getRoomManager().getRoom(this.getRoomId());
|
||||
|
||||
if (room == null) {
|
||||
throw new WiredSaveException("Room not found");
|
||||
}
|
||||
|
||||
WiredVariableNameValidator.validateDefinitionName(room, this.getId(), normalizedName);
|
||||
|
||||
int[] intParams = settings.getIntParams();
|
||||
|
||||
this.variableName = normalizedName;
|
||||
this.availability = normalizeAvailability((intParams.length > 0) ? intParams[0] : AVAILABILITY_ROOM_ACTIVE);
|
||||
|
||||
room.getRoomVariableManager().handleDefinitionUpdated(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getWiredData() {
|
||||
return WiredManager.getGson().toJson(new JsonData(this.variableName, this.availability));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serializeWiredData(ServerMessage message, Room room) {
|
||||
int currentValue = (room != null) ? room.getRoomVariableManager().getCurrentValue(this.getId()) : 0;
|
||||
|
||||
message.appendBoolean(false);
|
||||
message.appendInt(0);
|
||||
message.appendInt(0);
|
||||
message.appendInt(this.getBaseItem().getSpriteId());
|
||||
message.appendInt(this.getId());
|
||||
message.appendString(this.variableName);
|
||||
message.appendInt(2);
|
||||
message.appendInt(this.availability);
|
||||
message.appendInt(currentValue);
|
||||
message.appendInt(0);
|
||||
message.appendInt(CODE);
|
||||
message.appendInt(0);
|
||||
message.appendInt(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadWiredData(ResultSet set, Room room) throws SQLException {
|
||||
this.onPickUp();
|
||||
|
||||
String wiredData = set.getString("wired_data");
|
||||
if (wiredData == null || wiredData.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (wiredData.startsWith("{")) {
|
||||
JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class);
|
||||
|
||||
if (data != null) {
|
||||
this.variableName = WiredVariableNameValidator.normalizeLegacy(data.variableName);
|
||||
this.availability = normalizeAvailability(data.availability);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.variableName = WiredVariableNameValidator.normalizeLegacy(wiredData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPickUp() {
|
||||
this.variableName = "";
|
||||
this.availability = AVAILABILITY_ROOM_ACTIVE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWalk(RoomUnit roomUnit, Room room, Object[] objects) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasConfiguration() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public String getVariableName() {
|
||||
return this.variableName;
|
||||
}
|
||||
|
||||
public boolean hasValue() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public int getAvailability() {
|
||||
return this.availability;
|
||||
}
|
||||
|
||||
public boolean isPermanentAvailability() {
|
||||
return this.availability == AVAILABILITY_PERMANENT || this.availability == AVAILABILITY_SHARED;
|
||||
}
|
||||
|
||||
public boolean isSharedAvailability() {
|
||||
return this.availability == AVAILABILITY_SHARED;
|
||||
}
|
||||
|
||||
private static int normalizeAvailability(int value) {
|
||||
if (value == AVAILABILITY_PERMANENT || value == AVAILABILITY_SHARED) {
|
||||
return value;
|
||||
}
|
||||
|
||||
return AVAILABILITY_ROOM_ACTIVE;
|
||||
}
|
||||
|
||||
static class JsonData {
|
||||
String variableName;
|
||||
int availability;
|
||||
|
||||
JsonData(String variableName, int availability) {
|
||||
this.variableName = variableName;
|
||||
this.availability = availability;
|
||||
}
|
||||
}
|
||||
}
|
||||
+271
@@ -0,0 +1,271 @@
|
||||
package com.eu.habbo.habbohotel.items.interactions.wired.extra;
|
||||
|
||||
import com.eu.habbo.Emulator;
|
||||
import com.eu.habbo.habbohotel.gameclients.GameClient;
|
||||
import com.eu.habbo.habbohotel.items.Item;
|
||||
import com.eu.habbo.habbohotel.items.interactions.InteractionWiredExtra;
|
||||
import com.eu.habbo.habbohotel.items.interactions.wired.WiredSettings;
|
||||
import com.eu.habbo.habbohotel.rooms.Room;
|
||||
import com.eu.habbo.habbohotel.rooms.RoomUnit;
|
||||
import com.eu.habbo.habbohotel.rooms.WiredVariableDefinitionInfo;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredContextVariableSupport;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredManager;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredVariableTextConnectorSupport;
|
||||
import com.eu.habbo.messages.ServerMessage;
|
||||
import com.eu.habbo.messages.incoming.wired.WiredSaveException;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class WiredExtraTextInputVariable extends InteractionWiredExtra {
|
||||
public static final int CODE = 85;
|
||||
public static final int DISPLAY_NUMERIC = 1;
|
||||
public static final int DISPLAY_TEXTUAL = 2;
|
||||
public static final String DEFAULT_CAPTURER_NAME = "";
|
||||
public static final int MAX_CAPTURER_NAME_LENGTH = 32;
|
||||
|
||||
private static final String CUSTOM_TOKEN_PREFIX = "custom:";
|
||||
private static final Pattern WRAPPED_PLACEHOLDER_PATTERN = Pattern.compile("^#(.*)#$");
|
||||
|
||||
private int variableItemId = 0;
|
||||
private String variableToken = "";
|
||||
private String capturerName = DEFAULT_CAPTURER_NAME;
|
||||
private int displayType = DISPLAY_NUMERIC;
|
||||
|
||||
public WiredExtraTextInputVariable(ResultSet set, Item baseItem) throws SQLException {
|
||||
super(set, baseItem);
|
||||
}
|
||||
|
||||
public WiredExtraTextInputVariable(int id, int userId, Item item, String extradata, int limitedStack, int limitedSells) {
|
||||
super(id, userId, item, extradata, limitedStack, limitedSells);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean execute(RoomUnit roomUnit, Room room, Object[] stuff) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean saveData(WiredSettings settings, GameClient gameClient) throws WiredSaveException {
|
||||
Room room = Emulator.getGameEnvironment().getRoomManager().getRoom(this.getRoomId());
|
||||
if (room == null) {
|
||||
throw new WiredSaveException("Room not found");
|
||||
}
|
||||
|
||||
int[] intParams = settings.getIntParams();
|
||||
String[] stringData = splitStringData(settings.getStringParam());
|
||||
String nextVariableToken = normalizeVariableToken(stringData[0]);
|
||||
int nextVariableItemId = getCustomItemId(nextVariableToken);
|
||||
|
||||
if (nextVariableItemId <= 0) {
|
||||
throw new WiredSaveException("wiredfurni.params.variables.validation.missing_variable");
|
||||
}
|
||||
|
||||
WiredVariableDefinitionInfo definitionInfo = WiredContextVariableSupport.getDefinitionInfo(room, nextVariableItemId);
|
||||
if (definitionInfo == null || !definitionInfo.hasValue()) {
|
||||
throw new WiredSaveException("wiredfurni.params.variables.validation.invalid_variable");
|
||||
}
|
||||
|
||||
this.variableItemId = nextVariableItemId;
|
||||
this.variableToken = nextVariableToken;
|
||||
this.capturerName = normalizeCapturerName(stringData[1]);
|
||||
this.displayType = normalizeDisplayType((intParams.length > 0) ? intParams[0] : DISPLAY_NUMERIC);
|
||||
|
||||
if (!canUseTextualDisplay(room, this.variableItemId)) {
|
||||
this.displayType = DISPLAY_NUMERIC;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getWiredData() {
|
||||
return WiredManager.getGson().toJson(new JsonData(this.variableToken, this.variableItemId, this.capturerName, this.displayType));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serializeWiredData(ServerMessage message, Room room) {
|
||||
message.appendBoolean(false);
|
||||
message.appendInt(0);
|
||||
message.appendInt(0);
|
||||
message.appendInt(this.getBaseItem().getSpriteId());
|
||||
message.appendInt(this.getId());
|
||||
message.appendString(this.variableToken + "\t" + this.capturerName);
|
||||
message.appendInt(1);
|
||||
message.appendInt(this.getDisplayType(room));
|
||||
message.appendInt(0);
|
||||
message.appendInt(CODE);
|
||||
message.appendInt(0);
|
||||
message.appendInt(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadWiredData(ResultSet set, Room room) throws SQLException {
|
||||
this.onPickUp();
|
||||
|
||||
String wiredData = set.getString("wired_data");
|
||||
if (wiredData == null || wiredData.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (wiredData.startsWith("{")) {
|
||||
JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class);
|
||||
|
||||
if (data != null) {
|
||||
this.variableToken = normalizeVariableToken((data.variableToken != null)
|
||||
? data.variableToken
|
||||
: ((data.variableItemId > 0) ? String.valueOf(data.variableItemId) : ""));
|
||||
this.variableItemId = getCustomItemId(this.variableToken);
|
||||
this.capturerName = normalizeCapturerName(data.capturerName);
|
||||
this.displayType = normalizeDisplayType(data.displayType);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
String[] legacyData = splitStringData(wiredData);
|
||||
this.variableToken = normalizeVariableToken(legacyData[0]);
|
||||
this.variableItemId = getCustomItemId(this.variableToken);
|
||||
this.capturerName = normalizeCapturerName(legacyData[1]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPickUp() {
|
||||
this.variableItemId = 0;
|
||||
this.variableToken = "";
|
||||
this.capturerName = DEFAULT_CAPTURER_NAME;
|
||||
this.displayType = DISPLAY_NUMERIC;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWalk(RoomUnit roomUnit, Room room, Object[] objects) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasConfiguration() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public int getVariableItemId() {
|
||||
return this.variableItemId;
|
||||
}
|
||||
|
||||
public String getVariableToken() {
|
||||
return this.variableToken;
|
||||
}
|
||||
|
||||
public String getCapturerName() {
|
||||
return this.capturerName;
|
||||
}
|
||||
|
||||
public String getPlaceholderToken() {
|
||||
return this.capturerName.isEmpty() ? "" : "#" + this.capturerName + "#";
|
||||
}
|
||||
|
||||
public int getDisplayType(Room room) {
|
||||
return (this.displayType == DISPLAY_TEXTUAL && canUseTextualDisplay(room, this.variableItemId))
|
||||
? DISPLAY_TEXTUAL
|
||||
: DISPLAY_NUMERIC;
|
||||
}
|
||||
|
||||
public Integer resolveCapturedValue(Room room, String rawValue) {
|
||||
String normalizedValue = rawValue != null ? rawValue.trim() : "";
|
||||
if (normalizedValue.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (this.getDisplayType(room) == DISPLAY_TEXTUAL) {
|
||||
return WiredVariableTextConnectorSupport.toValue(room, this.variableItemId, normalizedValue);
|
||||
}
|
||||
|
||||
try {
|
||||
return Integer.parseInt(normalizedValue);
|
||||
} catch (NumberFormatException ignored) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean canUseTextualDisplay(Room room, int definitionItemId) {
|
||||
WiredVariableDefinitionInfo definitionInfo = WiredContextVariableSupport.getDefinitionInfo(room, definitionItemId);
|
||||
return definitionInfo != null && definitionInfo.hasValue() && definitionInfo.isTextConnected();
|
||||
}
|
||||
|
||||
private static String[] splitStringData(String value) {
|
||||
if (value == null) {
|
||||
return new String[]{ "", DEFAULT_CAPTURER_NAME };
|
||||
}
|
||||
|
||||
String[] parts = value.split("\t", -1);
|
||||
if (parts.length == 1) {
|
||||
return new String[]{ parts[0], DEFAULT_CAPTURER_NAME };
|
||||
}
|
||||
|
||||
return new String[]{ parts[0], parts[1] };
|
||||
}
|
||||
|
||||
private static int normalizeDisplayType(int value) {
|
||||
return (value == DISPLAY_TEXTUAL) ? DISPLAY_TEXTUAL : DISPLAY_NUMERIC;
|
||||
}
|
||||
|
||||
private static String normalizeCapturerName(String value) {
|
||||
if (value == null) {
|
||||
return DEFAULT_CAPTURER_NAME;
|
||||
}
|
||||
|
||||
String normalized = value.trim().replace("\t", "").replace("\r", "").replace("\n", "");
|
||||
if (WRAPPED_PLACEHOLDER_PATTERN.matcher(normalized).matches()) {
|
||||
normalized = normalized.substring(1, normalized.length() - 1).trim();
|
||||
}
|
||||
|
||||
if (normalized.length() > MAX_CAPTURER_NAME_LENGTH) {
|
||||
normalized = normalized.substring(0, MAX_CAPTURER_NAME_LENGTH);
|
||||
}
|
||||
|
||||
return normalized;
|
||||
}
|
||||
|
||||
private static String normalizeVariableToken(String value) {
|
||||
String normalized = value == null ? "" : value.trim();
|
||||
if (normalized.isEmpty()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
if (normalized.startsWith(CUSTOM_TOKEN_PREFIX)) {
|
||||
return normalized;
|
||||
}
|
||||
|
||||
try {
|
||||
int parsedValue = Integer.parseInt(normalized);
|
||||
return parsedValue > 0 ? (CUSTOM_TOKEN_PREFIX + parsedValue) : "";
|
||||
} catch (NumberFormatException ignored) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
private static int getCustomItemId(String token) {
|
||||
if (token == null || !token.startsWith(CUSTOM_TOKEN_PREFIX)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
try {
|
||||
return Integer.parseInt(token.substring(CUSTOM_TOKEN_PREFIX.length()));
|
||||
} catch (NumberFormatException ignored) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static class JsonData {
|
||||
String variableToken;
|
||||
int variableItemId;
|
||||
String capturerName;
|
||||
int displayType;
|
||||
|
||||
JsonData(String variableToken, int variableItemId, String capturerName, int displayType) {
|
||||
this.variableToken = variableToken;
|
||||
this.variableItemId = variableItemId;
|
||||
this.capturerName = capturerName;
|
||||
this.displayType = displayType;
|
||||
}
|
||||
}
|
||||
}
|
||||
+544
@@ -0,0 +1,544 @@
|
||||
package com.eu.habbo.habbohotel.items.interactions.wired.extra;
|
||||
|
||||
import com.eu.habbo.Emulator;
|
||||
import com.eu.habbo.habbohotel.gameclients.GameClient;
|
||||
import com.eu.habbo.habbohotel.items.Item;
|
||||
import com.eu.habbo.habbohotel.items.interactions.InteractionWiredExtra;
|
||||
import com.eu.habbo.habbohotel.items.interactions.wired.WiredSettings;
|
||||
import com.eu.habbo.habbohotel.rooms.Room;
|
||||
import com.eu.habbo.habbohotel.rooms.RoomUnit;
|
||||
import com.eu.habbo.habbohotel.rooms.WiredVariableDefinitionInfo;
|
||||
import com.eu.habbo.habbohotel.users.HabboItem;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredContextVariableSupport;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredInternalVariableSupport;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredManager;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredSourceUtil;
|
||||
import com.eu.habbo.messages.ServerMessage;
|
||||
import com.eu.habbo.messages.incoming.wired.WiredSaveException;
|
||||
import gnu.trove.set.hash.THashSet;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class WiredExtraTextOutputVariable extends InteractionWiredExtra {
|
||||
public static final int CODE = 80;
|
||||
public static final int TARGET_USER = 0;
|
||||
public static final int TARGET_FURNI = 1;
|
||||
public static final int TARGET_CONTEXT = 2;
|
||||
public static final int TARGET_ROOM = 3;
|
||||
public static final int DISPLAY_NUMERIC = 1;
|
||||
public static final int DISPLAY_TEXTUAL = 2;
|
||||
public static final int TYPE_SINGLE = 1;
|
||||
public static final int TYPE_MULTIPLE = 2;
|
||||
public static final String DEFAULT_VARIABLE_TOKEN = "";
|
||||
public static final String DEFAULT_PLACEHOLDER_NAME = "";
|
||||
public static final String DEFAULT_DELIMITER = ", ";
|
||||
public static final int MAX_PLACEHOLDER_NAME_LENGTH = 32;
|
||||
public static final int MAX_DELIMITER_LENGTH = 16;
|
||||
|
||||
private static final String CUSTOM_TOKEN_PREFIX = "custom:";
|
||||
private static final String INTERNAL_TOKEN_PREFIX = "internal:";
|
||||
private static final Pattern WRAPPED_PLACEHOLDER_PATTERN = Pattern.compile("^\\$\\((.*)\\)$");
|
||||
|
||||
private final THashSet<HabboItem> items;
|
||||
private int targetType = TARGET_USER;
|
||||
private int displayType = DISPLAY_NUMERIC;
|
||||
private int placeholderType = TYPE_SINGLE;
|
||||
private int userSource = WiredSourceUtil.SOURCE_TRIGGER;
|
||||
private int furniSource = WiredSourceUtil.SOURCE_TRIGGER;
|
||||
private int variableItemId = 0;
|
||||
private String variableToken = DEFAULT_VARIABLE_TOKEN;
|
||||
private String placeholderName = DEFAULT_PLACEHOLDER_NAME;
|
||||
private String delimiter = DEFAULT_DELIMITER;
|
||||
|
||||
public WiredExtraTextOutputVariable(ResultSet set, Item baseItem) throws SQLException {
|
||||
super(set, baseItem);
|
||||
this.items = new THashSet<>();
|
||||
}
|
||||
|
||||
public WiredExtraTextOutputVariable(int id, int userId, Item item, String extradata, int limitedStack, int limitedSells) {
|
||||
super(id, userId, item, extradata, limitedStack, limitedSells);
|
||||
this.items = new THashSet<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean execute(RoomUnit roomUnit, Room room, Object[] stuff) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean saveData(WiredSettings settings, GameClient gameClient) throws WiredSaveException {
|
||||
Room room = Emulator.getGameEnvironment().getRoomManager().getRoom(this.getRoomId());
|
||||
if (room == null) {
|
||||
throw new WiredSaveException("Room not found");
|
||||
}
|
||||
|
||||
int[] intParams = settings.getIntParams();
|
||||
String[] stringData = splitStringData(settings.getStringParam());
|
||||
int nextTargetType = normalizeTargetType((intParams.length > 0) ? intParams[0] : TARGET_USER);
|
||||
String nextVariableToken = normalizeVariableToken(stringData[0]);
|
||||
|
||||
if (nextVariableToken.isEmpty()) {
|
||||
throw new WiredSaveException("wiredfurni.params.variables.validation.missing_variable");
|
||||
}
|
||||
|
||||
if (!isValidVariable(room, nextTargetType, nextVariableToken)) {
|
||||
throw new WiredSaveException("wiredfurni.params.variables.validation.invalid_variable");
|
||||
}
|
||||
|
||||
int nextFurniSource = normalizeFurniSource((intParams.length > 4) ? intParams[4] : WiredSourceUtil.SOURCE_TRIGGER);
|
||||
this.items.clear();
|
||||
|
||||
if (nextTargetType == TARGET_FURNI && nextFurniSource == WiredSourceUtil.SOURCE_SELECTED) {
|
||||
if (settings.getFurniIds().length > Emulator.getConfig().getInt("hotel.wired.furni.selection.count")) {
|
||||
throw new WiredSaveException("wiredfurni.params.variables.validation.invalid_variable");
|
||||
}
|
||||
|
||||
for (int itemId : settings.getFurniIds()) {
|
||||
HabboItem item = room.getHabboItem(itemId);
|
||||
|
||||
if (item != null) {
|
||||
this.items.add(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.targetType = nextTargetType;
|
||||
this.setVariableToken(nextVariableToken);
|
||||
this.displayType = normalizeDisplayType((intParams.length > 1) ? intParams[1] : DISPLAY_NUMERIC);
|
||||
this.placeholderType = normalizePlaceholderType((intParams.length > 2) ? intParams[2] : TYPE_SINGLE);
|
||||
this.userSource = normalizeUserSource((intParams.length > 3) ? intParams[3] : WiredSourceUtil.SOURCE_TRIGGER);
|
||||
this.furniSource = nextFurniSource;
|
||||
this.placeholderName = normalizePlaceholderName(stringData[1]);
|
||||
this.delimiter = normalizeDelimiter(stringData[2]);
|
||||
|
||||
if (!canUseTextualDisplay(room, this.targetType, this.variableToken)) {
|
||||
this.displayType = DISPLAY_NUMERIC;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getWiredData() {
|
||||
return WiredManager.getGson().toJson(new JsonData(
|
||||
this.targetType,
|
||||
this.variableToken,
|
||||
this.variableItemId,
|
||||
this.displayType,
|
||||
this.placeholderType,
|
||||
this.userSource,
|
||||
this.furniSource,
|
||||
this.placeholderName,
|
||||
this.delimiter,
|
||||
this.items.stream().map(HabboItem::getId).collect(Collectors.toList())
|
||||
));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serializeWiredData(ServerMessage message, Room room) {
|
||||
this.refresh(room);
|
||||
|
||||
List<HabboItem> selectedItems = new ArrayList<>();
|
||||
if (this.targetType == TARGET_FURNI && this.furniSource == WiredSourceUtil.SOURCE_SELECTED) {
|
||||
selectedItems.addAll(this.items);
|
||||
}
|
||||
|
||||
message.appendBoolean(false);
|
||||
message.appendInt(WiredManager.MAXIMUM_FURNI_SELECTION);
|
||||
message.appendInt(selectedItems.size());
|
||||
|
||||
for (HabboItem item : selectedItems) {
|
||||
message.appendInt(item.getId());
|
||||
}
|
||||
|
||||
message.appendInt(this.getBaseItem().getSpriteId());
|
||||
message.appendInt(this.getId());
|
||||
message.appendString(this.variableToken + "\t" + this.placeholderName + "\t" + this.delimiter);
|
||||
message.appendInt(5);
|
||||
message.appendInt(this.targetType);
|
||||
message.appendInt(this.displayType);
|
||||
message.appendInt(this.placeholderType);
|
||||
message.appendInt(this.userSource);
|
||||
message.appendInt(this.furniSource);
|
||||
message.appendInt(0);
|
||||
message.appendInt(CODE);
|
||||
message.appendInt(0);
|
||||
message.appendInt(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadWiredData(ResultSet set, Room room) throws SQLException {
|
||||
this.onPickUp();
|
||||
|
||||
String wiredData = set.getString("wired_data");
|
||||
if (wiredData == null || wiredData.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (wiredData.startsWith("{")) {
|
||||
JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class);
|
||||
|
||||
if (data != null) {
|
||||
this.targetType = normalizeTargetType(data.targetType);
|
||||
this.setVariableToken(normalizeVariableToken((data.variableToken != null) ? data.variableToken : ((data.variableItemId > 0) ? String.valueOf(data.variableItemId) : "")));
|
||||
this.displayType = normalizeDisplayType(data.displayType);
|
||||
this.placeholderType = normalizePlaceholderType(data.placeholderType);
|
||||
this.userSource = normalizeUserSource(data.userSource);
|
||||
this.furniSource = normalizeFurniSource(data.furniSource);
|
||||
this.placeholderName = normalizePlaceholderName(data.placeholderName);
|
||||
this.delimiter = normalizeDelimiter(data.delimiter);
|
||||
|
||||
if (room != null && data.itemIds != null) {
|
||||
for (Integer itemId : data.itemIds) {
|
||||
if (itemId == null || itemId <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
HabboItem item = room.getHabboItem(itemId);
|
||||
if (item != null) {
|
||||
this.items.add(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (room == null || !canUseTextualDisplay(room, this.targetType, this.variableToken)) {
|
||||
this.displayType = DISPLAY_NUMERIC;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
String[] legacyData = splitStringData(wiredData);
|
||||
this.setVariableToken(normalizeVariableToken(legacyData[0]));
|
||||
this.placeholderName = normalizePlaceholderName(legacyData[1]);
|
||||
this.delimiter = normalizeDelimiter(legacyData[2]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPickUp() {
|
||||
this.items.clear();
|
||||
this.targetType = TARGET_USER;
|
||||
this.setVariableToken(DEFAULT_VARIABLE_TOKEN);
|
||||
this.displayType = DISPLAY_NUMERIC;
|
||||
this.placeholderType = TYPE_SINGLE;
|
||||
this.userSource = WiredSourceUtil.SOURCE_TRIGGER;
|
||||
this.furniSource = WiredSourceUtil.SOURCE_TRIGGER;
|
||||
this.placeholderName = DEFAULT_PLACEHOLDER_NAME;
|
||||
this.delimiter = DEFAULT_DELIMITER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWalk(RoomUnit roomUnit, Room room, Object[] objects) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasConfiguration() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public int getTargetType() {
|
||||
return this.targetType;
|
||||
}
|
||||
|
||||
public String getVariableToken() {
|
||||
return this.variableToken;
|
||||
}
|
||||
|
||||
public int getVariableItemId() {
|
||||
return this.variableItemId;
|
||||
}
|
||||
|
||||
public int getDisplayType(Room room) {
|
||||
return (this.displayType == DISPLAY_TEXTUAL && canUseTextualDisplay(room, this.targetType, this.variableToken))
|
||||
? DISPLAY_TEXTUAL
|
||||
: DISPLAY_NUMERIC;
|
||||
}
|
||||
|
||||
public int getPlaceholderType() {
|
||||
return this.placeholderType;
|
||||
}
|
||||
|
||||
public String getPlaceholderName() {
|
||||
return this.placeholderName;
|
||||
}
|
||||
|
||||
public String getPlaceholderToken() {
|
||||
return this.placeholderName.isEmpty() ? "" : "$(" + this.placeholderName + ")";
|
||||
}
|
||||
|
||||
public String getDelimiter() {
|
||||
return this.delimiter;
|
||||
}
|
||||
|
||||
public int getUserSource() {
|
||||
return this.userSource;
|
||||
}
|
||||
|
||||
public int getFurniSource() {
|
||||
return this.furniSource;
|
||||
}
|
||||
|
||||
public THashSet<HabboItem> getItems() {
|
||||
return this.items;
|
||||
}
|
||||
|
||||
public boolean requiresActor() {
|
||||
return this.targetType == TARGET_USER
|
||||
&& (this.userSource == WiredSourceUtil.SOURCE_TRIGGER || this.userSource == WiredSourceUtil.SOURCE_CLICKED_USER);
|
||||
}
|
||||
|
||||
public void refresh(Room room) {
|
||||
THashSet<HabboItem> remove = new THashSet<>();
|
||||
|
||||
for (HabboItem item : this.items) {
|
||||
if (room == null || room.getHabboItem(item.getId()) == null) {
|
||||
remove.add(item);
|
||||
}
|
||||
}
|
||||
|
||||
for (HabboItem item : remove) {
|
||||
this.items.remove(item);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isCustomVariableToken(String token) {
|
||||
return token != null && token.startsWith(CUSTOM_TOKEN_PREFIX);
|
||||
}
|
||||
|
||||
public static boolean isInternalVariableToken(String token) {
|
||||
return token != null && token.startsWith(INTERNAL_TOKEN_PREFIX);
|
||||
}
|
||||
|
||||
public static String getInternalVariableKey(String token) {
|
||||
return isInternalVariableToken(token) ? WiredInternalVariableSupport.normalizeKey(token.substring(INTERNAL_TOKEN_PREFIX.length())) : "";
|
||||
}
|
||||
|
||||
public static int getCustomItemId(String token) {
|
||||
if (!isCustomVariableToken(token)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
try {
|
||||
return Integer.parseInt(token.substring(CUSTOM_TOKEN_PREFIX.length()));
|
||||
} catch (NumberFormatException ignored) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
private static String[] splitStringData(String value) {
|
||||
if (value == null) {
|
||||
return new String[]{ DEFAULT_VARIABLE_TOKEN, DEFAULT_PLACEHOLDER_NAME, DEFAULT_DELIMITER };
|
||||
}
|
||||
|
||||
String[] parts = value.split("\t", -1);
|
||||
if (parts.length == 1) {
|
||||
return new String[]{ value, DEFAULT_PLACEHOLDER_NAME, DEFAULT_DELIMITER };
|
||||
}
|
||||
|
||||
if (parts.length == 2) {
|
||||
return new String[]{ parts[0], parts[1], DEFAULT_DELIMITER };
|
||||
}
|
||||
|
||||
return new String[]{ parts[0], parts[1], parts[2] };
|
||||
}
|
||||
|
||||
private static int normalizeTargetType(int value) {
|
||||
return switch (value) {
|
||||
case TARGET_FURNI, TARGET_CONTEXT, TARGET_ROOM -> value;
|
||||
default -> TARGET_USER;
|
||||
};
|
||||
}
|
||||
|
||||
private static int normalizeDisplayType(int value) {
|
||||
return (value == DISPLAY_TEXTUAL) ? DISPLAY_TEXTUAL : DISPLAY_NUMERIC;
|
||||
}
|
||||
|
||||
private static int normalizePlaceholderType(int value) {
|
||||
return (value == TYPE_MULTIPLE) ? TYPE_MULTIPLE : TYPE_SINGLE;
|
||||
}
|
||||
|
||||
private static int normalizeUserSource(int value) {
|
||||
return WiredSourceUtil.isDefaultUserSource(value) ? value : WiredSourceUtil.SOURCE_TRIGGER;
|
||||
}
|
||||
|
||||
private static int normalizeFurniSource(int value) {
|
||||
return switch (value) {
|
||||
case WiredSourceUtil.SOURCE_SELECTED, WiredSourceUtil.SOURCE_SELECTOR, WiredSourceUtil.SOURCE_SIGNAL -> value;
|
||||
default -> WiredSourceUtil.SOURCE_TRIGGER;
|
||||
};
|
||||
}
|
||||
|
||||
private static String normalizePlaceholderName(String value) {
|
||||
if (value == null) {
|
||||
return DEFAULT_PLACEHOLDER_NAME;
|
||||
}
|
||||
|
||||
String normalized = value.trim().replace("\t", "").replace("\r", "").replace("\n", "");
|
||||
if (WRAPPED_PLACEHOLDER_PATTERN.matcher(normalized).matches()) {
|
||||
normalized = normalized.substring(2, normalized.length() - 1).trim();
|
||||
}
|
||||
|
||||
if (normalized.length() > MAX_PLACEHOLDER_NAME_LENGTH) {
|
||||
normalized = normalized.substring(0, MAX_PLACEHOLDER_NAME_LENGTH);
|
||||
}
|
||||
|
||||
return normalized;
|
||||
}
|
||||
|
||||
private static String normalizeDelimiter(String value) {
|
||||
if (value == null) {
|
||||
return DEFAULT_DELIMITER;
|
||||
}
|
||||
|
||||
String normalized = value.replace("\t", "").replace("\r", "").replace("\n", "");
|
||||
if (normalized.length() > MAX_DELIMITER_LENGTH) {
|
||||
normalized = normalized.substring(0, MAX_DELIMITER_LENGTH);
|
||||
}
|
||||
|
||||
return normalized;
|
||||
}
|
||||
|
||||
private static String normalizeVariableToken(String value) {
|
||||
String normalized = (value == null) ? "" : value.trim();
|
||||
if (normalized.isEmpty()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
if (isCustomVariableToken(normalized)) {
|
||||
return normalized;
|
||||
}
|
||||
|
||||
if (isInternalVariableToken(normalized)) {
|
||||
return INTERNAL_TOKEN_PREFIX + WiredInternalVariableSupport.normalizeKey(normalized.substring(INTERNAL_TOKEN_PREFIX.length()));
|
||||
}
|
||||
|
||||
try {
|
||||
int parsedValue = Integer.parseInt(normalized);
|
||||
return parsedValue > 0 ? (CUSTOM_TOKEN_PREFIX + parsedValue) : "";
|
||||
} catch (NumberFormatException ignored) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
private void setVariableToken(String token) {
|
||||
this.variableToken = normalizeVariableToken(token);
|
||||
this.variableItemId = getCustomItemId(this.variableToken);
|
||||
}
|
||||
|
||||
private static boolean canUseTextualDisplay(Room room, int targetType, String variableToken) {
|
||||
if (room == null || !isCustomVariableToken(variableToken)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int itemId = getCustomItemId(variableToken);
|
||||
if (itemId <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return switch (targetType) {
|
||||
case TARGET_USER -> {
|
||||
WiredVariableDefinitionInfo definition = room.getUserVariableManager().getDefinitionInfo(itemId);
|
||||
yield definition != null && definition.hasValue() && definition.isTextConnected();
|
||||
}
|
||||
case TARGET_FURNI -> {
|
||||
WiredVariableDefinitionInfo definition = room.getFurniVariableManager().getDefinitionInfo(itemId);
|
||||
yield definition != null && definition.hasValue() && definition.isTextConnected();
|
||||
}
|
||||
case TARGET_CONTEXT -> {
|
||||
WiredVariableDefinitionInfo definition = WiredContextVariableSupport.getDefinitionInfo(room, itemId);
|
||||
yield definition != null && definition.hasValue() && definition.isTextConnected();
|
||||
}
|
||||
case TARGET_ROOM -> {
|
||||
WiredVariableDefinitionInfo definition = room.getRoomVariableManager().getDefinitionInfo(itemId);
|
||||
yield definition != null && definition.hasValue() && definition.isTextConnected();
|
||||
}
|
||||
default -> false;
|
||||
};
|
||||
}
|
||||
|
||||
private static boolean isValidVariable(Room room, int targetType, String variableToken) {
|
||||
if (room == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return switch (targetType) {
|
||||
case TARGET_USER -> isInternalVariableToken(variableToken)
|
||||
? canUseUserInternalReference(getInternalVariableKey(variableToken))
|
||||
: isUserCustomValue(room, getCustomItemId(variableToken));
|
||||
case TARGET_FURNI -> isInternalVariableToken(variableToken)
|
||||
? canUseFurniInternalReference(getInternalVariableKey(variableToken))
|
||||
: isFurniCustomValue(room, getCustomItemId(variableToken));
|
||||
case TARGET_CONTEXT -> isInternalVariableToken(variableToken)
|
||||
? WiredInternalVariableSupport.canUseContextReference(getInternalVariableKey(variableToken))
|
||||
: isContextCustomValue(room, getCustomItemId(variableToken));
|
||||
case TARGET_ROOM -> isInternalVariableToken(variableToken)
|
||||
? canUseRoomInternalReference(getInternalVariableKey(variableToken))
|
||||
: isRoomCustomValue(room, getCustomItemId(variableToken));
|
||||
default -> false;
|
||||
};
|
||||
}
|
||||
|
||||
private static boolean isUserCustomValue(Room room, int itemId) {
|
||||
WiredVariableDefinitionInfo definition = (room != null) ? room.getUserVariableManager().getDefinitionInfo(itemId) : null;
|
||||
return definition != null && definition.hasValue();
|
||||
}
|
||||
|
||||
private static boolean isFurniCustomValue(Room room, int itemId) {
|
||||
WiredVariableDefinitionInfo definition = (room != null) ? room.getFurniVariableManager().getDefinitionInfo(itemId) : null;
|
||||
return definition != null && definition.hasValue();
|
||||
}
|
||||
|
||||
private static boolean isRoomCustomValue(Room room, int itemId) {
|
||||
WiredVariableDefinitionInfo definition = (room != null) ? room.getRoomVariableManager().getDefinitionInfo(itemId) : null;
|
||||
return definition != null && definition.hasValue();
|
||||
}
|
||||
|
||||
private static boolean isContextCustomValue(Room room, int itemId) {
|
||||
WiredVariableDefinitionInfo definition = WiredContextVariableSupport.getDefinitionInfo(room, itemId);
|
||||
return definition != null && definition.hasValue();
|
||||
}
|
||||
|
||||
private static boolean canUseUserInternalReference(String key) {
|
||||
return WiredInternalVariableSupport.canUseUserReference(key);
|
||||
}
|
||||
|
||||
private static boolean canUseFurniInternalReference(String key) {
|
||||
return WiredInternalVariableSupport.canUseFurniReference(key);
|
||||
}
|
||||
|
||||
private static boolean canUseRoomInternalReference(String key) {
|
||||
return WiredInternalVariableSupport.canUseRoomReference(key);
|
||||
}
|
||||
|
||||
static class JsonData {
|
||||
int targetType;
|
||||
String variableToken;
|
||||
int variableItemId;
|
||||
int displayType;
|
||||
int placeholderType;
|
||||
int userSource;
|
||||
int furniSource;
|
||||
String placeholderName;
|
||||
String delimiter;
|
||||
List<Integer> itemIds;
|
||||
|
||||
JsonData(int targetType, String variableToken, int variableItemId, int displayType, int placeholderType, int userSource, int furniSource, String placeholderName, String delimiter, List<Integer> itemIds) {
|
||||
this.targetType = targetType;
|
||||
this.variableToken = variableToken;
|
||||
this.variableItemId = variableItemId;
|
||||
this.displayType = displayType;
|
||||
this.placeholderType = placeholderType;
|
||||
this.userSource = userSource;
|
||||
this.furniSource = furniSource;
|
||||
this.placeholderName = placeholderName;
|
||||
this.delimiter = delimiter;
|
||||
this.itemIds = itemIds;
|
||||
}
|
||||
}
|
||||
}
|
||||
+162
@@ -0,0 +1,162 @@
|
||||
package com.eu.habbo.habbohotel.items.interactions.wired.extra;
|
||||
|
||||
import com.eu.habbo.Emulator;
|
||||
import com.eu.habbo.habbohotel.gameclients.GameClient;
|
||||
import com.eu.habbo.habbohotel.items.Item;
|
||||
import com.eu.habbo.habbohotel.items.interactions.InteractionWiredExtra;
|
||||
import com.eu.habbo.habbohotel.items.interactions.wired.WiredSettings;
|
||||
import com.eu.habbo.habbohotel.rooms.Room;
|
||||
import com.eu.habbo.habbohotel.rooms.RoomUnit;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredManager;
|
||||
import com.eu.habbo.messages.ServerMessage;
|
||||
import com.eu.habbo.messages.incoming.wired.WiredSaveException;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
public class WiredExtraUserVariable extends InteractionWiredExtra {
|
||||
public static final int CODE = 70;
|
||||
public static final int AVAILABILITY_ROOM = 0;
|
||||
public static final int AVAILABILITY_PERMANENT = 10;
|
||||
public static final int AVAILABILITY_SHARED = 11;
|
||||
|
||||
private String variableName = "";
|
||||
private boolean hasValue = false;
|
||||
private int availability = AVAILABILITY_ROOM;
|
||||
|
||||
public WiredExtraUserVariable(ResultSet set, Item baseItem) throws SQLException {
|
||||
super(set, baseItem);
|
||||
}
|
||||
|
||||
public WiredExtraUserVariable(int id, int userId, Item item, String extradata, int limitedStack, int limitedSells) {
|
||||
super(id, userId, item, extradata, limitedStack, limitedSells);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean execute(RoomUnit roomUnit, Room room, Object[] stuff) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean saveData(WiredSettings settings, GameClient gameClient) throws WiredSaveException {
|
||||
int[] intParams = settings.getIntParams();
|
||||
String normalizedName = WiredVariableNameValidator.normalizeForSave(settings.getStringParam());
|
||||
|
||||
Room room = Emulator.getGameEnvironment().getRoomManager().getRoom(this.getRoomId());
|
||||
|
||||
if (room == null) {
|
||||
throw new WiredSaveException("Room not found");
|
||||
}
|
||||
|
||||
WiredVariableNameValidator.validateDefinitionName(room, this.getId(), normalizedName);
|
||||
|
||||
this.variableName = normalizedName;
|
||||
this.hasValue = (intParams.length > 0) && (intParams[0] == 1);
|
||||
this.availability = normalizeAvailability((intParams.length > 1) ? intParams[1] : AVAILABILITY_ROOM);
|
||||
|
||||
room.getUserVariableManager().handleDefinitionUpdated(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getWiredData() {
|
||||
return WiredManager.getGson().toJson(new JsonData(this.variableName, this.hasValue, this.availability));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serializeWiredData(ServerMessage message, Room room) {
|
||||
message.appendBoolean(false);
|
||||
message.appendInt(0);
|
||||
message.appendInt(0);
|
||||
message.appendInt(this.getBaseItem().getSpriteId());
|
||||
message.appendInt(this.getId());
|
||||
message.appendString(this.variableName);
|
||||
message.appendInt(2);
|
||||
message.appendInt(this.hasValue ? 1 : 0);
|
||||
message.appendInt(this.availability);
|
||||
message.appendInt(0);
|
||||
message.appendInt(CODE);
|
||||
message.appendInt(0);
|
||||
message.appendInt(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadWiredData(ResultSet set, Room room) throws SQLException {
|
||||
this.onPickUp();
|
||||
|
||||
String wiredData = set.getString("wired_data");
|
||||
if (wiredData == null || wiredData.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (wiredData.startsWith("{")) {
|
||||
JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class);
|
||||
|
||||
if (data != null) {
|
||||
this.variableName = WiredVariableNameValidator.normalizeLegacy(data.variableName);
|
||||
this.hasValue = data.hasValue;
|
||||
this.availability = normalizeAvailability(data.availability);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.variableName = WiredVariableNameValidator.normalizeLegacy(wiredData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPickUp() {
|
||||
this.variableName = "";
|
||||
this.hasValue = false;
|
||||
this.availability = AVAILABILITY_ROOM;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWalk(RoomUnit roomUnit, Room room, Object[] objects) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasConfiguration() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public String getVariableName() {
|
||||
return variableName;
|
||||
}
|
||||
|
||||
public boolean hasValue() {
|
||||
return hasValue;
|
||||
}
|
||||
|
||||
public int getAvailability() {
|
||||
return availability;
|
||||
}
|
||||
|
||||
public boolean isPermanentAvailability() {
|
||||
return this.availability == AVAILABILITY_PERMANENT || this.availability == AVAILABILITY_SHARED;
|
||||
}
|
||||
|
||||
public boolean isSharedAvailability() {
|
||||
return this.availability == AVAILABILITY_SHARED;
|
||||
}
|
||||
|
||||
private static int normalizeAvailability(int value) {
|
||||
if (value == AVAILABILITY_PERMANENT || value == AVAILABILITY_SHARED) {
|
||||
return value;
|
||||
}
|
||||
|
||||
return AVAILABILITY_ROOM;
|
||||
}
|
||||
|
||||
static class JsonData {
|
||||
String variableName;
|
||||
boolean hasValue;
|
||||
int availability;
|
||||
|
||||
JsonData(String variableName, boolean hasValue, int availability) {
|
||||
this.variableName = variableName;
|
||||
this.hasValue = hasValue;
|
||||
this.availability = availability;
|
||||
}
|
||||
}
|
||||
}
|
||||
+808
@@ -0,0 +1,808 @@
|
||||
package com.eu.habbo.habbohotel.items.interactions.wired.extra;
|
||||
|
||||
import com.eu.habbo.Emulator;
|
||||
import com.eu.habbo.habbohotel.bots.Bot;
|
||||
import com.eu.habbo.habbohotel.gameclients.GameClient;
|
||||
import com.eu.habbo.habbohotel.games.Game;
|
||||
import com.eu.habbo.habbohotel.games.GamePlayer;
|
||||
import com.eu.habbo.habbohotel.games.GameTeam;
|
||||
import com.eu.habbo.habbohotel.games.GameTeamColors;
|
||||
import com.eu.habbo.habbohotel.items.FurnitureType;
|
||||
import com.eu.habbo.habbohotel.items.Item;
|
||||
import com.eu.habbo.habbohotel.items.interactions.InteractionWiredExtra;
|
||||
import com.eu.habbo.habbohotel.items.interactions.wired.WiredSettings;
|
||||
import com.eu.habbo.habbohotel.pets.Pet;
|
||||
import com.eu.habbo.habbohotel.rooms.FurnitureMovementError;
|
||||
import com.eu.habbo.habbohotel.rooms.Room;
|
||||
import com.eu.habbo.habbohotel.rooms.RoomTile;
|
||||
import com.eu.habbo.habbohotel.rooms.RoomTileState;
|
||||
import com.eu.habbo.habbohotel.rooms.RoomUnit;
|
||||
import com.eu.habbo.habbohotel.rooms.RoomRightLevels;
|
||||
import com.eu.habbo.habbohotel.rooms.RoomUserRotation;
|
||||
import com.eu.habbo.habbohotel.rooms.RoomUnitStatus;
|
||||
import com.eu.habbo.habbohotel.rooms.WiredVariableDefinitionInfo;
|
||||
import com.eu.habbo.habbohotel.users.DanceType;
|
||||
import com.eu.habbo.habbohotel.users.HabboGender;
|
||||
import com.eu.habbo.habbohotel.users.Habbo;
|
||||
import com.eu.habbo.habbohotel.users.HabboItem;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredManager;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredFreezeUtil;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredInternalVariableSupport;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredUserMovementHelper;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredVariableLevelSystemSupport;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredVariableTextConnectorSupport;
|
||||
import com.eu.habbo.messages.ServerMessage;
|
||||
import com.eu.habbo.messages.incoming.wired.WiredSaveException;
|
||||
import com.eu.habbo.util.HotelDateTimeUtil;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.temporal.WeekFields;
|
||||
import java.util.Locale;
|
||||
|
||||
public class WiredExtraVariableEcho extends InteractionWiredExtra {
|
||||
public static final int CODE = 83;
|
||||
public static final int TARGET_USER = 0;
|
||||
public static final int TARGET_FURNI = 1;
|
||||
public static final int TARGET_ROOM = 3;
|
||||
|
||||
private static final String CUSTOM_TOKEN_PREFIX = "custom:";
|
||||
private static final String INTERNAL_TOKEN_PREFIX = "internal:";
|
||||
private static final int DEFAULT_USER_AVAILABILITY = WiredExtraUserVariable.AVAILABILITY_ROOM;
|
||||
private static final int DEFAULT_FURNI_AVAILABILITY = WiredExtraFurniVariable.AVAILABILITY_ROOM_ACTIVE;
|
||||
private static final int DEFAULT_ROOM_AVAILABILITY = WiredExtraRoomVariable.AVAILABILITY_ROOM_ACTIVE;
|
||||
|
||||
private String variableName = "";
|
||||
private int sourceTargetType = TARGET_USER;
|
||||
private String sourceVariableToken = "";
|
||||
private int sourceVariableItemId = 0;
|
||||
private String sourceVariableName = "";
|
||||
|
||||
public WiredExtraVariableEcho(ResultSet set, Item baseItem) throws SQLException {
|
||||
super(set, baseItem);
|
||||
}
|
||||
|
||||
public WiredExtraVariableEcho(int id, int userId, Item item, String extradata, int limitedStack, int limitedSells) {
|
||||
super(id, userId, item, extradata, limitedStack, limitedSells);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean execute(RoomUnit roomUnit, Room room, Object[] stuff) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean saveData(WiredSettings settings, GameClient gameClient) throws WiredSaveException {
|
||||
Room room = Emulator.getGameEnvironment().getRoomManager().getRoom(this.getRoomId());
|
||||
|
||||
if (room == null) {
|
||||
throw new WiredSaveException("Room not found");
|
||||
}
|
||||
|
||||
ConfigData config = parseConfigData(settings.getStringParam());
|
||||
int normalizedTargetType = normalizeTargetType(config.sourceTargetType);
|
||||
String normalizedToken = normalizeVariableToken(config.sourceVariableToken, config.sourceVariableItemId);
|
||||
int normalizedItemId = getCustomVariableItemId(normalizedToken);
|
||||
SourceState sourceState = this.resolveSourceState(room, normalizedTargetType, normalizedToken, normalizedItemId);
|
||||
|
||||
if (normalizedToken.isEmpty()) {
|
||||
throw new WiredSaveException("wiredfurni.params.variables.validation.missing_variable");
|
||||
}
|
||||
|
||||
if (sourceState == null || !sourceState.hasValue()) {
|
||||
throw new WiredSaveException("wiredfurni.params.variables.validation.invalid_variable");
|
||||
}
|
||||
|
||||
if (!isAllowedEchoSource(sourceState, normalizedToken)) {
|
||||
throw new WiredSaveException("wiredfurni.params.variables.validation.invalid_variable");
|
||||
}
|
||||
|
||||
if (!WiredVariableTextConnectorSupport.isTextConnected(room, this)) {
|
||||
throw new WiredSaveException("wiredfurni.params.variables.validation.invalid_variable");
|
||||
}
|
||||
|
||||
if (createsCycle(room, this.getId(), normalizedTargetType, normalizedToken, normalizedItemId)) {
|
||||
throw new WiredSaveException("wiredfurni.params.variables.validation.invalid_variable");
|
||||
}
|
||||
|
||||
String normalizedName = deriveVariableName(config.variableName, sourceState.getName());
|
||||
WiredVariableNameValidator.validateDefinitionName(room, this.getId(), normalizedName);
|
||||
|
||||
this.variableName = normalizedName;
|
||||
this.sourceTargetType = normalizedTargetType;
|
||||
this.sourceVariableToken = normalizedToken;
|
||||
this.sourceVariableItemId = normalizedItemId;
|
||||
this.sourceVariableName = sourceState.getName();
|
||||
|
||||
room.getUserVariableManager().broadcastSnapshot();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getWiredData() {
|
||||
return WiredManager.getGson().toJson(new JsonData(this.variableName, this.sourceTargetType, this.sourceVariableToken, this.sourceVariableItemId, this.sourceVariableName));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serializeWiredData(ServerMessage message, Room room) {
|
||||
message.appendBoolean(false);
|
||||
message.appendInt(0);
|
||||
message.appendInt(0);
|
||||
message.appendInt(this.getBaseItem().getSpriteId());
|
||||
message.appendInt(this.getId());
|
||||
message.appendString(WiredManager.getGson().toJson(new EditorPayload(this.variableName, this.sourceTargetType, this.sourceVariableToken, this.sourceVariableItemId, this.getResolvedSourceName(room))));
|
||||
message.appendInt(0);
|
||||
message.appendInt(0);
|
||||
message.appendInt(CODE);
|
||||
message.appendInt(0);
|
||||
message.appendInt(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadWiredData(ResultSet set, Room room) throws SQLException {
|
||||
this.onPickUp();
|
||||
|
||||
String wiredData = set.getString("wired_data");
|
||||
if (wiredData == null || wiredData.isEmpty() || !wiredData.startsWith("{")) {
|
||||
return;
|
||||
}
|
||||
|
||||
JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class);
|
||||
if (data == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.variableName = WiredVariableNameValidator.normalizeLegacy(data.variableName);
|
||||
this.sourceTargetType = normalizeTargetType(data.sourceTargetType);
|
||||
this.sourceVariableToken = normalizeVariableToken(data.sourceVariableToken, data.sourceVariableItemId);
|
||||
this.sourceVariableItemId = getCustomVariableItemId(this.sourceVariableToken);
|
||||
this.sourceVariableName = normalizeSourceName(data.sourceVariableName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPickUp() {
|
||||
this.variableName = "";
|
||||
this.sourceTargetType = TARGET_USER;
|
||||
this.sourceVariableToken = "";
|
||||
this.sourceVariableItemId = 0;
|
||||
this.sourceVariableName = "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWalk(RoomUnit roomUnit, Room room, Object[] objects) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasConfiguration() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public String getVariableName() {
|
||||
return this.variableName;
|
||||
}
|
||||
|
||||
public int getSourceTargetType() {
|
||||
return this.sourceTargetType;
|
||||
}
|
||||
|
||||
public String getSourceVariableToken() {
|
||||
return this.sourceVariableToken;
|
||||
}
|
||||
|
||||
public int getSourceVariableItemId() {
|
||||
return this.sourceVariableItemId;
|
||||
}
|
||||
|
||||
public String getSourceVariableName() {
|
||||
return this.sourceVariableName;
|
||||
}
|
||||
|
||||
public boolean isUserEcho() {
|
||||
return this.sourceTargetType == TARGET_USER;
|
||||
}
|
||||
|
||||
public boolean isFurniEcho() {
|
||||
return this.sourceTargetType == TARGET_FURNI;
|
||||
}
|
||||
|
||||
public boolean isRoomEcho() {
|
||||
return this.sourceTargetType == TARGET_ROOM;
|
||||
}
|
||||
|
||||
public WiredVariableDefinitionInfo createDefinitionInfo(Room room) {
|
||||
SourceState sourceState = this.resolveSourceState(room, this.sourceTargetType, this.sourceVariableToken, this.sourceVariableItemId);
|
||||
int availability = (sourceState != null) ? sourceState.getAvailability() : defaultAvailability(this.sourceTargetType);
|
||||
boolean hasValue = (sourceState == null) || sourceState.hasValue();
|
||||
boolean readOnly = sourceState == null || sourceState.isReadOnly();
|
||||
|
||||
return new WiredVariableDefinitionInfo(
|
||||
this.getId(),
|
||||
this.variableName,
|
||||
hasValue,
|
||||
availability,
|
||||
WiredVariableTextConnectorSupport.isTextConnected(room, this),
|
||||
readOnly
|
||||
);
|
||||
}
|
||||
|
||||
public boolean hasVariable(Room room, int entityId) {
|
||||
if (room == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isCustomVariableToken(this.sourceVariableToken)) {
|
||||
return switch (this.sourceTargetType) {
|
||||
case TARGET_FURNI -> room.getFurniVariableManager().hasVariable(entityId, this.sourceVariableItemId);
|
||||
case TARGET_ROOM -> room.getRoomVariableManager().hasVariable(this.sourceVariableItemId);
|
||||
default -> room.getUserVariableManager().hasVariable(entityId, this.sourceVariableItemId);
|
||||
};
|
||||
}
|
||||
|
||||
return this.readCurrentValue(room, entityId) != null;
|
||||
}
|
||||
|
||||
public int getCurrentValue(Room room, int entityId) {
|
||||
Integer value = this.readCurrentValue(room, entityId);
|
||||
return (value != null) ? value : 0;
|
||||
}
|
||||
|
||||
public int getCreatedAt(Room room, int entityId) {
|
||||
if (room == null || !isCustomVariableToken(this.sourceVariableToken)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return switch (this.sourceTargetType) {
|
||||
case TARGET_FURNI -> room.getFurniVariableManager().getCreatedAt(entityId, this.sourceVariableItemId);
|
||||
case TARGET_ROOM -> room.getRoomVariableManager().getCreatedAt(this.sourceVariableItemId);
|
||||
default -> room.getUserVariableManager().getCreatedAt(entityId, this.sourceVariableItemId);
|
||||
};
|
||||
}
|
||||
|
||||
public int getUpdatedAt(Room room, int entityId) {
|
||||
if (room == null || !isCustomVariableToken(this.sourceVariableToken)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return switch (this.sourceTargetType) {
|
||||
case TARGET_FURNI -> room.getFurniVariableManager().getUpdatedAt(entityId, this.sourceVariableItemId);
|
||||
case TARGET_ROOM -> room.getRoomVariableManager().getUpdatedAt(this.sourceVariableItemId);
|
||||
default -> room.getUserVariableManager().getUpdatedAt(entityId, this.sourceVariableItemId);
|
||||
};
|
||||
}
|
||||
|
||||
public boolean assignValue(Room room, int entityId, Integer value, boolean overrideExisting) {
|
||||
if (room == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SourceState sourceState = this.resolveSourceState(room, this.sourceTargetType, this.sourceVariableToken, this.sourceVariableItemId);
|
||||
if (sourceState == null || sourceState.isReadOnly()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isCustomVariableToken(this.sourceVariableToken)) {
|
||||
return switch (this.sourceTargetType) {
|
||||
case TARGET_FURNI -> room.getFurniVariableManager().assignVariable(room.getHabboItem(entityId), this.sourceVariableItemId, value, overrideExisting);
|
||||
case TARGET_ROOM -> room.getRoomVariableManager().updateVariableValue(this.sourceVariableItemId, (value != null) ? value : 0);
|
||||
default -> room.getUserVariableManager().assignVariable(room.getHabbo(entityId), this.sourceVariableItemId, value, overrideExisting);
|
||||
};
|
||||
}
|
||||
|
||||
return value != null && this.writeCurrentValue(room, entityId, value);
|
||||
}
|
||||
|
||||
public boolean updateValue(Room room, int entityId, Integer value) {
|
||||
if (room == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SourceState sourceState = this.resolveSourceState(room, this.sourceTargetType, this.sourceVariableToken, this.sourceVariableItemId);
|
||||
if (sourceState == null || sourceState.isReadOnly() || !sourceState.hasValue()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isCustomVariableToken(this.sourceVariableToken)) {
|
||||
return switch (this.sourceTargetType) {
|
||||
case TARGET_FURNI -> room.getFurniVariableManager().updateVariableValue(entityId, this.sourceVariableItemId, value);
|
||||
case TARGET_ROOM -> room.getRoomVariableManager().updateVariableValue(this.sourceVariableItemId, (value != null) ? value : 0);
|
||||
default -> room.getUserVariableManager().updateVariableValue(entityId, this.sourceVariableItemId, value);
|
||||
};
|
||||
}
|
||||
|
||||
return value != null && this.writeCurrentValue(room, entityId, value);
|
||||
}
|
||||
|
||||
public boolean removeValue(Room room, int entityId) {
|
||||
if (room == null || !isCustomVariableToken(this.sourceVariableToken)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SourceState sourceState = this.resolveSourceState(room, this.sourceTargetType, this.sourceVariableToken, this.sourceVariableItemId);
|
||||
if (sourceState == null || sourceState.isReadOnly()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return switch (this.sourceTargetType) {
|
||||
case TARGET_FURNI -> room.getFurniVariableManager().removeVariable(entityId, this.sourceVariableItemId);
|
||||
case TARGET_ROOM -> room.getRoomVariableManager().removeVariable(this.sourceVariableItemId);
|
||||
default -> room.getUserVariableManager().removeVariable(entityId, this.sourceVariableItemId);
|
||||
};
|
||||
}
|
||||
|
||||
private Integer readCurrentValue(Room room, int entityId) {
|
||||
if (room == null || this.sourceVariableToken == null || this.sourceVariableToken.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (isCustomVariableToken(this.sourceVariableToken)) {
|
||||
return switch (this.sourceTargetType) {
|
||||
case TARGET_FURNI -> room.getFurniVariableManager().hasVariable(entityId, this.sourceVariableItemId)
|
||||
? room.getFurniVariableManager().getCurrentValue(entityId, this.sourceVariableItemId)
|
||||
: null;
|
||||
case TARGET_ROOM -> room.getRoomVariableManager().getCurrentValue(this.sourceVariableItemId);
|
||||
default -> room.getUserVariableManager().hasVariable(entityId, this.sourceVariableItemId)
|
||||
? room.getUserVariableManager().getCurrentValue(entityId, this.sourceVariableItemId)
|
||||
: null;
|
||||
};
|
||||
}
|
||||
|
||||
String key = getInternalVariableKey(this.sourceVariableToken);
|
||||
if (key.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return switch (this.sourceTargetType) {
|
||||
case TARGET_FURNI -> this.readFurniInternalValue(room, room.getHabboItem(entityId), key);
|
||||
case TARGET_ROOM -> this.readRoomInternalValue(room, key);
|
||||
default -> {
|
||||
Habbo habbo = room.getHabbo(entityId);
|
||||
yield this.readUserInternalValue(room, (habbo != null) ? habbo.getRoomUnit() : null, key);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private boolean writeCurrentValue(Room room, int entityId, int value) {
|
||||
if (room == null || !isInternalVariableToken(this.sourceVariableToken)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String key = getInternalVariableKey(this.sourceVariableToken);
|
||||
if (key.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return switch (this.sourceTargetType) {
|
||||
case TARGET_FURNI -> this.writeFurniInternalValue(room, room.getHabboItem(entityId), key, value);
|
||||
case TARGET_ROOM -> false;
|
||||
default -> {
|
||||
Habbo habbo = room.getHabbo(entityId);
|
||||
yield this.writeUserInternalValue(room, (habbo != null) ? habbo.getRoomUnit() : null, key, value);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private SourceState resolveSourceState(Room room, int targetType, String token, int variableItemId) {
|
||||
if (room == null || token == null || token.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (isCustomVariableToken(token)) {
|
||||
WiredVariableDefinitionInfo definitionInfo = switch (targetType) {
|
||||
case TARGET_FURNI -> room.getFurniVariableManager().getDefinitionInfo(variableItemId);
|
||||
case TARGET_ROOM -> room.getRoomVariableManager().getDefinitionInfo(variableItemId);
|
||||
default -> room.getUserVariableManager().getDefinitionInfo(variableItemId);
|
||||
};
|
||||
|
||||
if (definitionInfo == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new SourceState(definitionInfo.getName(), definitionInfo.hasValue(), definitionInfo.getAvailability(), definitionInfo.isReadOnly());
|
||||
}
|
||||
|
||||
String key = getInternalVariableKey(token);
|
||||
if (key.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return switch (targetType) {
|
||||
case TARGET_FURNI -> canUseFurniInternalReference(key)
|
||||
? new SourceState(key, true, DEFAULT_FURNI_AVAILABILITY, !canUseFurniInternalDestination(key))
|
||||
: null;
|
||||
case TARGET_ROOM -> canUseRoomInternalReference(key)
|
||||
? new SourceState(key, true, DEFAULT_ROOM_AVAILABILITY, true)
|
||||
: null;
|
||||
default -> canUseUserInternalReference(key)
|
||||
? new SourceState(key, true, DEFAULT_USER_AVAILABILITY, !canUseUserInternalDestination(key))
|
||||
: null;
|
||||
};
|
||||
}
|
||||
|
||||
private String getResolvedSourceName(Room room) {
|
||||
SourceState sourceState = this.resolveSourceState(room, this.sourceTargetType, this.sourceVariableToken, this.sourceVariableItemId);
|
||||
return (sourceState != null) ? sourceState.getName() : this.sourceVariableName;
|
||||
}
|
||||
|
||||
private static boolean createsCycle(Room room, int currentItemId, int targetType, String token, int variableItemId) {
|
||||
if (room == null || currentItemId <= 0 || !isCustomVariableToken(token) || variableItemId <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (variableItemId == currentItemId) {
|
||||
return true;
|
||||
}
|
||||
|
||||
WiredVariableLevelSystemSupport.DerivedDefinition derivedDefinition = WiredVariableLevelSystemSupport.resolveDerivedDefinition(room, targetType, variableItemId);
|
||||
if (derivedDefinition != null) {
|
||||
return createsCycle(room, currentItemId, targetType, createCustomVariableToken(derivedDefinition.getBaseDefinitionItemId()), derivedDefinition.getBaseDefinitionItemId());
|
||||
}
|
||||
|
||||
if (room.getRoomSpecialTypes() == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
InteractionWiredExtra extra = room.getRoomSpecialTypes().getExtra(variableItemId);
|
||||
if (!(extra instanceof WiredExtraVariableEcho)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
WiredExtraVariableEcho echo = (WiredExtraVariableEcho) extra;
|
||||
return createsCycle(room, currentItemId, echo.getSourceTargetType(), echo.getSourceVariableToken(), echo.getSourceVariableItemId());
|
||||
}
|
||||
|
||||
private static String deriveVariableName(String requestedName, String sourceName) {
|
||||
String normalizedRequestedName = WiredVariableNameValidator.normalizeForSave(requestedName);
|
||||
if (!normalizedRequestedName.isEmpty()) {
|
||||
return normalizedRequestedName;
|
||||
}
|
||||
|
||||
String fallbackValue = normalizeSourceName(sourceName)
|
||||
.replaceAll("^[~@]+", "")
|
||||
.replaceAll("[^A-Za-z0-9_]+", "_")
|
||||
.replaceAll("_+", "_")
|
||||
.replaceAll("^_+", "")
|
||||
.replaceAll("_+$", "");
|
||||
|
||||
if (fallbackValue.length() > WiredVariableNameValidator.MAX_NAME_LENGTH) {
|
||||
fallbackValue = fallbackValue.substring(0, WiredVariableNameValidator.MAX_NAME_LENGTH);
|
||||
}
|
||||
|
||||
return fallbackValue;
|
||||
}
|
||||
|
||||
private static boolean isAllowedEchoSource(SourceState sourceState, String token) {
|
||||
if (sourceState == null || token == null || token.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isInternalVariableToken(token)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return isCustomVariableToken(token) && sourceState.getName() != null && sourceState.getName().contains(".");
|
||||
}
|
||||
|
||||
private static ConfigData parseConfigData(String value) {
|
||||
if (value == null || value.isEmpty() || !value.startsWith("{")) {
|
||||
return new ConfigData();
|
||||
}
|
||||
|
||||
ConfigData config = WiredManager.getGson().fromJson(value, ConfigData.class);
|
||||
return (config != null) ? config : new ConfigData();
|
||||
}
|
||||
|
||||
private static String normalizeSourceName(String value) {
|
||||
if (value == null) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return value.trim().replace("\t", "").replace("\r", "").replace("\n", "");
|
||||
}
|
||||
|
||||
private static int normalizeTargetType(int value) {
|
||||
if (value == TARGET_FURNI || value == TARGET_ROOM) {
|
||||
return value;
|
||||
}
|
||||
|
||||
return TARGET_USER;
|
||||
}
|
||||
|
||||
private static int defaultAvailability(int targetType) {
|
||||
return switch (targetType) {
|
||||
case TARGET_FURNI -> DEFAULT_FURNI_AVAILABILITY;
|
||||
case TARGET_ROOM -> DEFAULT_ROOM_AVAILABILITY;
|
||||
default -> DEFAULT_USER_AVAILABILITY;
|
||||
};
|
||||
}
|
||||
|
||||
private static boolean isCustomVariableToken(String token) {
|
||||
return token != null && token.startsWith(CUSTOM_TOKEN_PREFIX);
|
||||
}
|
||||
|
||||
private static boolean isInternalVariableToken(String token) {
|
||||
return token != null && token.startsWith(INTERNAL_TOKEN_PREFIX);
|
||||
}
|
||||
|
||||
private static String getInternalVariableKey(String token) {
|
||||
return isInternalVariableToken(token) ? WiredInternalVariableSupport.normalizeKey(token.substring(INTERNAL_TOKEN_PREFIX.length())) : "";
|
||||
}
|
||||
|
||||
private static int getCustomVariableItemId(String token) {
|
||||
if (!isCustomVariableToken(token)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
try {
|
||||
return Integer.parseInt(token.substring(CUSTOM_TOKEN_PREFIX.length()));
|
||||
} catch (NumberFormatException ignored) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
private static String createCustomVariableToken(int itemId) {
|
||||
return itemId > 0 ? CUSTOM_TOKEN_PREFIX + itemId : "";
|
||||
}
|
||||
|
||||
private static String normalizeVariableToken(String token, int fallbackItemId) {
|
||||
String normalizedToken = (token != null) ? token.trim() : "";
|
||||
|
||||
if (isCustomVariableToken(normalizedToken)) {
|
||||
return normalizedToken;
|
||||
}
|
||||
|
||||
if (isInternalVariableToken(normalizedToken)) {
|
||||
return INTERNAL_TOKEN_PREFIX + WiredInternalVariableSupport.normalizeKey(normalizedToken.substring(INTERNAL_TOKEN_PREFIX.length()));
|
||||
}
|
||||
|
||||
if (fallbackItemId > 0) {
|
||||
return createCustomVariableToken(fallbackItemId);
|
||||
}
|
||||
|
||||
if (normalizedToken.isEmpty()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
try {
|
||||
return createCustomVariableToken(Integer.parseInt(normalizedToken));
|
||||
} catch (NumberFormatException ignored) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
private Integer readUserInternalValue(Room room, RoomUnit roomUnit, String key) {
|
||||
return WiredInternalVariableSupport.readUserValue(room, roomUnit, key);
|
||||
}
|
||||
|
||||
private Integer getUserTypeValue(Habbo habbo, Bot bot, Pet pet) {
|
||||
if (habbo != null) return 1;
|
||||
if (bot != null) return 2;
|
||||
if (pet != null) return 3;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private Integer getGenderValue(Habbo habbo, Bot bot) {
|
||||
HabboGender gender = null;
|
||||
|
||||
if (habbo != null && habbo.getHabboInfo() != null) {
|
||||
gender = habbo.getHabboInfo().getGender();
|
||||
} else if (bot != null) {
|
||||
gender = bot.getGender();
|
||||
}
|
||||
|
||||
if (gender == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return gender == HabboGender.F ? 1 : 2;
|
||||
}
|
||||
|
||||
private boolean writeUserInternalValue(Room room, RoomUnit roomUnit, String key, int value) {
|
||||
return WiredInternalVariableSupport.writeUserValue(room, roomUnit, key, value);
|
||||
}
|
||||
|
||||
private Integer readFurniInternalValue(Room room, HabboItem item, String key) {
|
||||
return WiredInternalVariableSupport.readFurniValue(room, item, key);
|
||||
}
|
||||
|
||||
private boolean writeFurniInternalValue(Room room, HabboItem item, String key, int value) {
|
||||
return WiredInternalVariableSupport.writeFurniValue(room, item, key, value);
|
||||
}
|
||||
|
||||
private Integer readRoomInternalValue(Room room, String key) {
|
||||
return WiredInternalVariableSupport.readRoomValue(room, key);
|
||||
}
|
||||
|
||||
private Integer getUserTeamScore(Room room, Habbo habbo) {
|
||||
if (room == null || habbo == null || habbo.getHabboInfo() == null || habbo.getHabboInfo().getGamePlayer() == null) return null;
|
||||
|
||||
Game game = this.resolveTeamGame(room, habbo);
|
||||
GamePlayer gamePlayer = habbo.getHabboInfo().getGamePlayer();
|
||||
|
||||
if (game == null || gamePlayer.getTeamColor() == null) return gamePlayer.getScore();
|
||||
|
||||
GameTeam team = game.getTeam(gamePlayer.getTeamColor());
|
||||
return (team != null) ? team.getTotalScore() : gamePlayer.getScore();
|
||||
}
|
||||
|
||||
private int getTeamMetric(Room room, GameTeamColors color, boolean score) {
|
||||
Game game = this.resolveTeamGame(room, null);
|
||||
if (game == null || color == null) return 0;
|
||||
|
||||
GameTeam team = game.getTeam(color);
|
||||
if (team == null) return 0;
|
||||
|
||||
return score ? team.getTotalScore() : team.getMembers().size();
|
||||
}
|
||||
|
||||
private int getTeamColorId(int effectId) {
|
||||
if (effectId >= 33 && effectId <= 36) return effectId - 32;
|
||||
if (effectId >= 40 && effectId <= 43) return effectId - 39;
|
||||
return 0;
|
||||
}
|
||||
|
||||
private int getTeamTypeId(int effectId) {
|
||||
if (effectId >= 33 && effectId <= 36) return 1;
|
||||
if (effectId >= 40 && effectId <= 43) return 2;
|
||||
return 0;
|
||||
}
|
||||
|
||||
private Game resolveTeamGame(Room room, Habbo habbo) {
|
||||
if (room == null) return null;
|
||||
|
||||
if (habbo != null && habbo.getHabboInfo() != null && habbo.getHabboInfo().getCurrentGame() != null) {
|
||||
Game game = room.getGame(habbo.getHabboInfo().getCurrentGame());
|
||||
if (game != null) return game;
|
||||
}
|
||||
|
||||
Game game = room.getGame(com.eu.habbo.habbohotel.games.battlebanzai.BattleBanzaiGame.class);
|
||||
if (game != null) return game;
|
||||
|
||||
game = room.getGame(com.eu.habbo.habbohotel.games.freeze.FreezeGame.class);
|
||||
if (game != null) return game;
|
||||
|
||||
return room.getGame(com.eu.habbo.habbohotel.games.wired.WiredGame.class);
|
||||
}
|
||||
|
||||
private boolean moveUserTo(Room room, RoomUnit roomUnit, int x, int y) {
|
||||
if (room == null || roomUnit == null || room.getLayout() == null) return false;
|
||||
|
||||
RoomTile targetTile = room.getLayout().getTile((short) x, (short) y);
|
||||
if (targetTile == null || targetTile.state == RoomTileState.INVALID) return false;
|
||||
|
||||
double targetZ = WiredUserMovementHelper.resolveUserTargetZ(room, targetTile);
|
||||
return WiredUserMovementHelper.moveUser(
|
||||
room,
|
||||
roomUnit,
|
||||
targetTile,
|
||||
targetZ,
|
||||
roomUnit.getBodyRotation(),
|
||||
roomUnit.getHeadRotation(),
|
||||
WiredUserMovementHelper.DEFAULT_ANIMATION_DURATION,
|
||||
false);
|
||||
}
|
||||
|
||||
private boolean moveFurniTo(Room room, HabboItem item, int x, int y, int rotation, double z) {
|
||||
if (room == null || item == null || room.getLayout() == null) return false;
|
||||
|
||||
RoomTile targetTile = room.getLayout().getTile((short) x, (short) y);
|
||||
if (targetTile == null || targetTile.state == RoomTileState.INVALID) return false;
|
||||
|
||||
FurnitureMovementError error = room.moveFurniTo(item, targetTile, rotation, z, null, true, true);
|
||||
return error == FurnitureMovementError.NONE;
|
||||
}
|
||||
|
||||
private static Integer parseInteger(String value) {
|
||||
if (value == null || value.isEmpty()) return 0;
|
||||
|
||||
try {
|
||||
return Integer.parseInt(value.trim());
|
||||
} catch (NumberFormatException ignored) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean canUseUserInternalDestination(String key) {
|
||||
return WiredInternalVariableSupport.canUseUserDestination(key);
|
||||
}
|
||||
|
||||
private static boolean canUseFurniInternalDestination(String key) {
|
||||
return WiredInternalVariableSupport.canUseFurniDestination(key);
|
||||
}
|
||||
|
||||
private static boolean canUseUserInternalReference(String key) {
|
||||
return WiredInternalVariableSupport.canUseUserReference(key);
|
||||
}
|
||||
|
||||
private static boolean canUseFurniInternalReference(String key) {
|
||||
return WiredInternalVariableSupport.canUseFurniReference(key);
|
||||
}
|
||||
|
||||
private static boolean canUseRoomInternalReference(String key) {
|
||||
return WiredInternalVariableSupport.canUseRoomReference(key);
|
||||
}
|
||||
|
||||
private Integer getRoomEntryMethodValue(Habbo habbo) {
|
||||
if (habbo == null || habbo.getHabboInfo() == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String roomEntryMethod = habbo.getHabboInfo().getRoomEntryMethod();
|
||||
|
||||
if (roomEntryMethod == null || roomEntryMethod.trim().isEmpty()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return switch (roomEntryMethod.trim().toLowerCase(Locale.ROOT)) {
|
||||
case "door" -> 1;
|
||||
case "teleport" -> 2;
|
||||
default -> 3;
|
||||
};
|
||||
}
|
||||
|
||||
static class JsonData {
|
||||
String variableName;
|
||||
int sourceTargetType;
|
||||
String sourceVariableToken;
|
||||
int sourceVariableItemId;
|
||||
String sourceVariableName;
|
||||
|
||||
JsonData(String variableName, int sourceTargetType, String sourceVariableToken, int sourceVariableItemId, String sourceVariableName) {
|
||||
this.variableName = variableName;
|
||||
this.sourceTargetType = sourceTargetType;
|
||||
this.sourceVariableToken = sourceVariableToken;
|
||||
this.sourceVariableItemId = sourceVariableItemId;
|
||||
this.sourceVariableName = sourceVariableName;
|
||||
}
|
||||
}
|
||||
|
||||
static class ConfigData {
|
||||
String variableName = "";
|
||||
int sourceTargetType = TARGET_USER;
|
||||
String sourceVariableToken = "";
|
||||
int sourceVariableItemId = 0;
|
||||
}
|
||||
|
||||
static class EditorPayload extends ConfigData {
|
||||
String sourceVariableName;
|
||||
|
||||
EditorPayload(String variableName, int sourceTargetType, String sourceVariableToken, int sourceVariableItemId, String sourceVariableName) {
|
||||
this.variableName = variableName;
|
||||
this.sourceTargetType = sourceTargetType;
|
||||
this.sourceVariableToken = sourceVariableToken;
|
||||
this.sourceVariableItemId = sourceVariableItemId;
|
||||
this.sourceVariableName = sourceVariableName;
|
||||
}
|
||||
}
|
||||
|
||||
private static class SourceState {
|
||||
private final String name;
|
||||
private final boolean hasValue;
|
||||
private final int availability;
|
||||
private final boolean readOnly;
|
||||
|
||||
private SourceState(String name, boolean hasValue, int availability, boolean readOnly) {
|
||||
this.name = name;
|
||||
this.hasValue = hasValue;
|
||||
this.availability = availability;
|
||||
this.readOnly = readOnly;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public boolean hasValue() {
|
||||
return this.hasValue;
|
||||
}
|
||||
|
||||
public int getAvailability() {
|
||||
return this.availability;
|
||||
}
|
||||
|
||||
public boolean isReadOnly() {
|
||||
return this.readOnly;
|
||||
}
|
||||
}
|
||||
}
|
||||
+757
@@ -0,0 +1,757 @@
|
||||
package com.eu.habbo.habbohotel.items.interactions.wired.extra;
|
||||
|
||||
import com.eu.habbo.Emulator;
|
||||
import com.eu.habbo.habbohotel.bots.Bot;
|
||||
import com.eu.habbo.habbohotel.gameclients.GameClient;
|
||||
import com.eu.habbo.habbohotel.games.Game;
|
||||
import com.eu.habbo.habbohotel.games.GamePlayer;
|
||||
import com.eu.habbo.habbohotel.games.GameTeam;
|
||||
import com.eu.habbo.habbohotel.games.GameTeamColors;
|
||||
import com.eu.habbo.habbohotel.games.battlebanzai.BattleBanzaiGame;
|
||||
import com.eu.habbo.habbohotel.games.freeze.FreezeGame;
|
||||
import com.eu.habbo.habbohotel.games.wired.WiredGame;
|
||||
import com.eu.habbo.habbohotel.items.FurnitureType;
|
||||
import com.eu.habbo.habbohotel.items.Item;
|
||||
import com.eu.habbo.habbohotel.items.interactions.InteractionWiredExtra;
|
||||
import com.eu.habbo.habbohotel.items.interactions.wired.WiredSettings;
|
||||
import com.eu.habbo.habbohotel.rooms.WiredVariableDefinitionInfo;
|
||||
import com.eu.habbo.habbohotel.pets.Pet;
|
||||
import com.eu.habbo.habbohotel.rooms.Room;
|
||||
import com.eu.habbo.habbohotel.rooms.RoomUnit;
|
||||
import com.eu.habbo.habbohotel.users.DanceType;
|
||||
import com.eu.habbo.habbohotel.users.Habbo;
|
||||
import com.eu.habbo.habbohotel.users.HabboItem;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredContext;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredContextVariableSupport;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredFreezeUtil;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredInternalVariableSupport;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredManager;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredSourceUtil;
|
||||
import com.eu.habbo.messages.ServerMessage;
|
||||
import com.eu.habbo.messages.incoming.wired.WiredSaveException;
|
||||
import com.eu.habbo.util.HotelDateTimeUtil;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.temporal.WeekFields;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
public abstract class WiredExtraVariableFilterBase extends InteractionWiredExtra {
|
||||
protected static final int TARGET_USER = 0;
|
||||
protected static final int TARGET_FURNI = 1;
|
||||
protected static final int TARGET_CONTEXT = 2;
|
||||
protected static final int TARGET_ROOM = 3;
|
||||
|
||||
protected static final int AMOUNT_CONSTANT = 0;
|
||||
protected static final int AMOUNT_VARIABLE = 1;
|
||||
protected static final int SOURCE_SECONDARY_SELECTED = 101;
|
||||
|
||||
protected static final int SORT_VALUE_HIGHEST = 0;
|
||||
protected static final int SORT_VALUE_LOWEST = 1;
|
||||
protected static final int SORT_CREATION_OLDEST = 2;
|
||||
protected static final int SORT_CREATION_LATEST = 3;
|
||||
protected static final int SORT_UPDATE_OLDEST = 4;
|
||||
protected static final int SORT_UPDATE_LATEST = 5;
|
||||
|
||||
private static final int MAX_FILTER_AMOUNT = 10000;
|
||||
private static final String CUSTOM_TOKEN_PREFIX = "custom:";
|
||||
private static final String INTERNAL_TOKEN_PREFIX = "internal:";
|
||||
private static final String DELIM = "\t";
|
||||
|
||||
protected int sortBy = SORT_VALUE_HIGHEST;
|
||||
protected int amountMode = AMOUNT_CONSTANT;
|
||||
protected int amountConstantValue = 1;
|
||||
protected int referenceTargetType = TARGET_USER;
|
||||
protected int referenceUserSource = WiredSourceUtil.SOURCE_TRIGGER;
|
||||
protected int referenceFurniSource = WiredSourceUtil.SOURCE_TRIGGER;
|
||||
protected String variableToken = "";
|
||||
protected int variableItemId = 0;
|
||||
protected String referenceVariableToken = "";
|
||||
protected int referenceVariableItemId = 0;
|
||||
protected final List<HabboItem> referenceSelectedItems = new ArrayList<>();
|
||||
|
||||
protected WiredExtraVariableFilterBase(ResultSet set, Item baseItem) throws SQLException {
|
||||
super(set, baseItem);
|
||||
}
|
||||
|
||||
protected WiredExtraVariableFilterBase(int id, int userId, Item item, String extradata, int limitedStack, int limitedSells) {
|
||||
super(id, userId, item, extradata, limitedStack, limitedSells);
|
||||
}
|
||||
|
||||
protected abstract int getVariableTargetType();
|
||||
|
||||
protected abstract int getCode();
|
||||
|
||||
public List<RoomUnit> filterUsers(Room room, WiredContext ctx, Iterable<RoomUnit> values) {
|
||||
if (room == null || ctx == null || this.getVariableTargetType() != TARGET_USER || this.variableToken.isEmpty()) {
|
||||
return toUserList(values);
|
||||
}
|
||||
|
||||
int amount = this.resolveAmount(ctx, room);
|
||||
if (amount <= 0) return new ArrayList<>();
|
||||
|
||||
List<SortableEntry<RoomUnit>> matches = new ArrayList<>();
|
||||
|
||||
for (RoomUnit roomUnit : values) {
|
||||
if (roomUnit == null) continue;
|
||||
|
||||
MetricSnapshot metric = this.resolveUserMetric(room, roomUnit);
|
||||
if (metric == null) continue;
|
||||
|
||||
matches.add(new SortableEntry<>(roomUnit, metric));
|
||||
}
|
||||
|
||||
matches.sort(this.metricComparator());
|
||||
return trimUsers(matches, amount);
|
||||
}
|
||||
|
||||
public List<HabboItem> filterItems(Room room, WiredContext ctx, Iterable<HabboItem> values) {
|
||||
if (room == null || ctx == null || this.getVariableTargetType() != TARGET_FURNI || this.variableToken.isEmpty()) {
|
||||
return toItemList(values);
|
||||
}
|
||||
|
||||
int amount = this.resolveAmount(ctx, room);
|
||||
if (amount <= 0) return new ArrayList<>();
|
||||
|
||||
List<SortableEntry<HabboItem>> matches = new ArrayList<>();
|
||||
|
||||
for (HabboItem item : values) {
|
||||
if (item == null) continue;
|
||||
|
||||
MetricSnapshot metric = this.resolveFurniMetric(room, item);
|
||||
if (metric == null) continue;
|
||||
|
||||
matches.add(new SortableEntry<>(item, metric));
|
||||
}
|
||||
|
||||
matches.sort(this.metricComparator());
|
||||
return trimItems(matches, amount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean saveData(WiredSettings settings, GameClient gameClient) throws WiredSaveException {
|
||||
Room room = Emulator.getGameEnvironment().getRoomManager().getRoom(this.getRoomId());
|
||||
if (room == null) throw new WiredSaveException("Room not found");
|
||||
|
||||
int[] params = settings.getIntParams();
|
||||
String[] stringParts = parseStringData(settings.getStringParam());
|
||||
String nextVariableToken = normalizeVariableToken((stringParts.length > 0) ? stringParts[0] : "");
|
||||
String nextReferenceVariableToken = normalizeVariableToken((stringParts.length > 1) ? stringParts[1] : "");
|
||||
int nextSortBy = normalizeSortBy(param(params, 0, SORT_VALUE_HIGHEST));
|
||||
int nextAmountMode = normalizeAmountMode(param(params, 1, AMOUNT_CONSTANT));
|
||||
int nextAmountConstantValue = normalizeAmount(param(params, 2, 1));
|
||||
int nextReferenceTargetType = normalizeReferenceTargetType(param(params, 3, TARGET_USER));
|
||||
int nextReferenceUserSource = normalizeUserSource(param(params, 4, WiredSourceUtil.SOURCE_TRIGGER));
|
||||
int nextReferenceFurniSource = normalizeReferenceFurniSource(param(params, 5, WiredSourceUtil.SOURCE_TRIGGER));
|
||||
|
||||
if (!this.isValidMainVariable(room, nextVariableToken)) throw new WiredSaveException("wiredfurni.params.variables.validation.invalid_variable");
|
||||
if (nextAmountMode == AMOUNT_VARIABLE && !this.isValidReference(room, nextReferenceTargetType, nextReferenceVariableToken)) throw new WiredSaveException("wiredfurni.params.variables.validation.invalid_variable");
|
||||
|
||||
List<HabboItem> nextReferenceItems = new ArrayList<>();
|
||||
if (nextAmountMode == AMOUNT_VARIABLE && nextReferenceTargetType == TARGET_FURNI && nextReferenceFurniSource == SOURCE_SECONDARY_SELECTED) {
|
||||
int selectionLimit = Emulator.getConfig().getInt("hotel.wired.furni.selection.count");
|
||||
if (settings.getFurniIds().length > selectionLimit) throw new WiredSaveException("Too many furni selected");
|
||||
|
||||
for (int furniId : settings.getFurniIds()) {
|
||||
HabboItem item = room.getHabboItem(furniId);
|
||||
if (item != null) nextReferenceItems.add(item);
|
||||
}
|
||||
}
|
||||
|
||||
this.sortBy = nextSortBy;
|
||||
this.amountMode = nextAmountMode;
|
||||
this.amountConstantValue = nextAmountConstantValue;
|
||||
this.referenceTargetType = nextReferenceTargetType;
|
||||
this.referenceUserSource = nextReferenceUserSource;
|
||||
this.referenceFurniSource = nextReferenceFurniSource;
|
||||
this.setVariableToken(nextVariableToken);
|
||||
this.setReferenceVariableToken(nextReferenceVariableToken);
|
||||
this.referenceSelectedItems.clear();
|
||||
this.referenceSelectedItems.addAll(nextReferenceItems);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getWiredData() {
|
||||
this.refreshReferenceItems();
|
||||
return WiredManager.getGson().toJson(new JsonData(this.sortBy, this.amountMode, this.amountConstantValue, this.referenceTargetType, this.referenceUserSource, this.referenceFurniSource, this.variableToken, this.variableItemId, this.referenceVariableToken, this.referenceVariableItemId, this.toIds(this.referenceSelectedItems)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serializeWiredData(ServerMessage message, Room room) {
|
||||
this.refreshReferenceItems();
|
||||
List<HabboItem> selectedItems = new ArrayList<>();
|
||||
if (this.amountMode == AMOUNT_VARIABLE && this.referenceTargetType == TARGET_FURNI && this.referenceFurniSource == SOURCE_SECONDARY_SELECTED) {
|
||||
selectedItems.addAll(this.referenceSelectedItems);
|
||||
}
|
||||
|
||||
message.appendBoolean(false);
|
||||
message.appendInt(WiredManager.MAXIMUM_FURNI_SELECTION);
|
||||
message.appendInt(selectedItems.size());
|
||||
for (HabboItem item : selectedItems) message.appendInt(item.getId());
|
||||
message.appendInt(this.getBaseItem().getSpriteId());
|
||||
message.appendInt(this.getId());
|
||||
message.appendString(this.serializeStringData());
|
||||
message.appendInt(6);
|
||||
message.appendInt(this.sortBy);
|
||||
message.appendInt(this.amountMode);
|
||||
message.appendInt(this.amountConstantValue);
|
||||
message.appendInt(this.referenceTargetType);
|
||||
message.appendInt(this.referenceUserSource);
|
||||
message.appendInt(this.referenceFurniSource);
|
||||
message.appendInt(0);
|
||||
message.appendInt(this.getCode());
|
||||
message.appendInt(0);
|
||||
message.appendInt(0);
|
||||
}
|
||||
@Override
|
||||
public void loadWiredData(ResultSet set, Room room) throws SQLException {
|
||||
this.onPickUp();
|
||||
|
||||
String wiredData = set.getString("wired_data");
|
||||
if (wiredData == null || wiredData.isEmpty() || !wiredData.startsWith("{")) return;
|
||||
|
||||
JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class);
|
||||
if (data == null) return;
|
||||
|
||||
this.sortBy = normalizeSortBy(data.sortBy);
|
||||
this.amountMode = normalizeAmountMode(data.amountMode);
|
||||
this.amountConstantValue = normalizeAmount(data.amountConstantValue);
|
||||
this.referenceTargetType = normalizeReferenceTargetType(data.referenceTargetType);
|
||||
this.referenceUserSource = normalizeUserSource(data.referenceUserSource);
|
||||
this.referenceFurniSource = normalizeReferenceFurniSource(data.referenceFurniSource);
|
||||
this.setVariableToken(normalizeVariableToken((data.variableToken != null) ? data.variableToken : ((data.variableItemId > 0) ? String.valueOf(data.variableItemId) : "")));
|
||||
this.setReferenceVariableToken(normalizeVariableToken((data.referenceVariableToken != null) ? data.referenceVariableToken : ((data.referenceVariableItemId > 0) ? String.valueOf(data.referenceVariableItemId) : "")));
|
||||
|
||||
if (room == null || data.selectedItemIds == null) return;
|
||||
|
||||
for (Integer itemId : data.selectedItemIds) {
|
||||
if (itemId == null || itemId <= 0) continue;
|
||||
|
||||
HabboItem item = room.getHabboItem(itemId);
|
||||
if (item != null) this.referenceSelectedItems.add(item);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPickUp() {
|
||||
this.sortBy = SORT_VALUE_HIGHEST;
|
||||
this.amountMode = AMOUNT_CONSTANT;
|
||||
this.amountConstantValue = 1;
|
||||
this.referenceTargetType = TARGET_USER;
|
||||
this.referenceUserSource = WiredSourceUtil.SOURCE_TRIGGER;
|
||||
this.referenceFurniSource = WiredSourceUtil.SOURCE_TRIGGER;
|
||||
this.referenceSelectedItems.clear();
|
||||
this.setVariableToken("");
|
||||
this.setReferenceVariableToken("");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean execute(RoomUnit roomUnit, Room room, Object[] stuff) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWalk(RoomUnit roomUnit, Room room, Object[] objects) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasConfiguration() {
|
||||
return true;
|
||||
}
|
||||
|
||||
private int resolveAmount(WiredContext ctx, Room room) {
|
||||
if (this.amountMode != AMOUNT_VARIABLE) return normalizeAmount(this.amountConstantValue);
|
||||
|
||||
Integer value = this.resolveReferenceValue(ctx, room);
|
||||
return value == null ? 0 : normalizeAmount(value);
|
||||
}
|
||||
|
||||
private Integer resolveReferenceValue(WiredContext ctx, Room room) {
|
||||
if (room == null) return null;
|
||||
|
||||
if (this.referenceTargetType == TARGET_FURNI) {
|
||||
int source = (this.referenceFurniSource == SOURCE_SECONDARY_SELECTED) ? WiredSourceUtil.SOURCE_SELECTED : this.referenceFurniSource;
|
||||
if (source == WiredSourceUtil.SOURCE_SELECTED) this.refreshReferenceItems();
|
||||
|
||||
for (HabboItem item : WiredSourceUtil.resolveItems(ctx, source, this.referenceSelectedItems)) {
|
||||
Integer value = this.readFurniReferenceValue(room, item);
|
||||
if (value != null) return value;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
if (this.referenceTargetType == TARGET_CONTEXT) {
|
||||
return this.readContextReferenceValue(ctx, room);
|
||||
}
|
||||
|
||||
if (this.referenceTargetType == TARGET_ROOM) {
|
||||
return this.readRoomReferenceValue(room);
|
||||
}
|
||||
|
||||
for (RoomUnit roomUnit : WiredSourceUtil.resolveUsers(ctx, this.referenceUserSource)) {
|
||||
Integer value = this.readUserReferenceValue(room, roomUnit);
|
||||
if (value != null) return value;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private Integer readUserReferenceValue(Room room, RoomUnit roomUnit) {
|
||||
if (room == null || roomUnit == null) return null;
|
||||
|
||||
if (isInternalVariableToken(this.referenceVariableToken)) {
|
||||
String key = getInternalVariableKey(this.referenceVariableToken);
|
||||
return canUseUserInternalReference(key) ? this.readUserInternalValue(room, roomUnit, key) : null;
|
||||
}
|
||||
|
||||
WiredVariableDefinitionInfo definition = room.getUserVariableManager().getDefinitionInfo(this.referenceVariableItemId);
|
||||
if (definition == null || !definition.hasValue()) return null;
|
||||
|
||||
Habbo habbo = room.getHabbo(roomUnit);
|
||||
return (habbo != null) ? room.getUserVariableManager().getCurrentValue(habbo.getHabboInfo().getId(), this.referenceVariableItemId) : null;
|
||||
}
|
||||
|
||||
private Integer readFurniReferenceValue(Room room, HabboItem item) {
|
||||
if (room == null || item == null) return null;
|
||||
|
||||
if (isInternalVariableToken(this.referenceVariableToken)) {
|
||||
String key = getInternalVariableKey(this.referenceVariableToken);
|
||||
return canUseFurniInternalReference(key) ? this.readFurniInternalValue(room, item, key) : null;
|
||||
}
|
||||
|
||||
WiredVariableDefinitionInfo definition = room.getFurniVariableManager().getDefinitionInfo(this.referenceVariableItemId);
|
||||
return (definition != null && definition.hasValue()) ? room.getFurniVariableManager().getCurrentValue(item.getId(), this.referenceVariableItemId) : null;
|
||||
}
|
||||
|
||||
private Integer readRoomReferenceValue(Room room) {
|
||||
if (room == null) return null;
|
||||
|
||||
if (isInternalVariableToken(this.referenceVariableToken)) {
|
||||
String key = getInternalVariableKey(this.referenceVariableToken);
|
||||
return canUseRoomInternalReference(key) ? this.readRoomInternalValue(room, key) : null;
|
||||
}
|
||||
|
||||
WiredVariableDefinitionInfo definition = room.getRoomVariableManager().getDefinitionInfo(this.referenceVariableItemId);
|
||||
return (definition != null && definition.hasValue()) ? room.getRoomVariableManager().getCurrentValue(this.referenceVariableItemId) : null;
|
||||
}
|
||||
|
||||
private Integer readContextReferenceValue(WiredContext ctx, Room room) {
|
||||
if (ctx == null) return null;
|
||||
|
||||
if (isInternalVariableToken(this.referenceVariableToken)) {
|
||||
String key = getInternalVariableKey(this.referenceVariableToken);
|
||||
return canUseContextInternalReference(key) ? WiredInternalVariableSupport.readContextValue(ctx, key) : null;
|
||||
}
|
||||
|
||||
WiredVariableDefinitionInfo definition = WiredContextVariableSupport.getDefinitionInfo(room, this.referenceVariableItemId);
|
||||
if (definition == null || !definition.hasValue() || !WiredContextVariableSupport.hasVariable(ctx, this.referenceVariableItemId)) return null;
|
||||
|
||||
return WiredContextVariableSupport.getCurrentValue(ctx, this.referenceVariableItemId);
|
||||
}
|
||||
|
||||
private MetricSnapshot resolveUserMetric(Room room, RoomUnit roomUnit) {
|
||||
if (room == null || roomUnit == null) return null;
|
||||
|
||||
if (isInternalVariableToken(this.variableToken)) {
|
||||
String key = getInternalVariableKey(this.variableToken);
|
||||
Integer value = canUseUserInternalReference(key) ? this.readUserInternalValue(room, roomUnit, key) : null;
|
||||
return (value != null) ? new MetricSnapshot(roomUnit.getId(), value, 0, 0) : null;
|
||||
}
|
||||
|
||||
WiredVariableDefinitionInfo definition = room.getUserVariableManager().getDefinitionInfo(this.variableItemId);
|
||||
Habbo habbo = room.getHabbo(roomUnit);
|
||||
if (definition == null || habbo == null) return null;
|
||||
if (!room.getUserVariableManager().hasVariable(habbo.getHabboInfo().getId(), this.variableItemId)) return null;
|
||||
|
||||
return new MetricSnapshot(
|
||||
roomUnit.getId(),
|
||||
definition.hasValue() ? room.getUserVariableManager().getCurrentValue(habbo.getHabboInfo().getId(), this.variableItemId) : 0,
|
||||
room.getUserVariableManager().getCreatedAt(habbo.getHabboInfo().getId(), this.variableItemId),
|
||||
room.getUserVariableManager().getUpdatedAt(habbo.getHabboInfo().getId(), this.variableItemId));
|
||||
}
|
||||
|
||||
private MetricSnapshot resolveFurniMetric(Room room, HabboItem item) {
|
||||
if (room == null || item == null) return null;
|
||||
|
||||
if (isInternalVariableToken(this.variableToken)) {
|
||||
String key = getInternalVariableKey(this.variableToken);
|
||||
Integer value = canUseFurniInternalReference(key) ? this.readFurniInternalValue(room, item, key) : null;
|
||||
return (value != null) ? new MetricSnapshot(item.getId(), value, 0, 0) : null;
|
||||
}
|
||||
|
||||
WiredVariableDefinitionInfo definition = room.getFurniVariableManager().getDefinitionInfo(this.variableItemId);
|
||||
if (definition == null) return null;
|
||||
if (!room.getFurniVariableManager().hasVariable(item.getId(), this.variableItemId)) return null;
|
||||
|
||||
return new MetricSnapshot(
|
||||
item.getId(),
|
||||
definition.hasValue() ? room.getFurniVariableManager().getCurrentValue(item.getId(), this.variableItemId) : 0,
|
||||
room.getFurniVariableManager().getCreatedAt(item.getId(), this.variableItemId),
|
||||
room.getFurniVariableManager().getUpdatedAt(item.getId(), this.variableItemId));
|
||||
}
|
||||
|
||||
private Comparator<SortableEntry<?>> metricComparator() {
|
||||
return switch (this.sortBy) {
|
||||
case SORT_VALUE_LOWEST -> Comparator.comparingInt((SortableEntry<?> entry) -> entry.metric.value).thenComparingInt(entry -> entry.metric.entityId);
|
||||
case SORT_CREATION_OLDEST -> Comparator.comparingInt((SortableEntry<?> entry) -> entry.metric.createdAt).thenComparingInt(entry -> entry.metric.entityId);
|
||||
case SORT_CREATION_LATEST -> Comparator.<SortableEntry<?>, Integer>comparing(entry -> entry.metric.createdAt).reversed().thenComparingInt(entry -> entry.metric.entityId);
|
||||
case SORT_UPDATE_OLDEST -> Comparator.comparingInt((SortableEntry<?> entry) -> entry.metric.updatedAt).thenComparingInt(entry -> entry.metric.entityId);
|
||||
case SORT_UPDATE_LATEST -> Comparator.<SortableEntry<?>, Integer>comparing(entry -> entry.metric.updatedAt).reversed().thenComparingInt(entry -> entry.metric.entityId);
|
||||
default -> Comparator.<SortableEntry<?>, Integer>comparing(entry -> entry.metric.value).reversed().thenComparingInt(entry -> entry.metric.entityId);
|
||||
};
|
||||
}
|
||||
|
||||
private boolean isValidMainVariable(Room room, String token) {
|
||||
if (token == null || token.isEmpty()) return false;
|
||||
|
||||
if (isInternalVariableToken(token)) {
|
||||
String key = getInternalVariableKey(token);
|
||||
return this.getVariableTargetType() == TARGET_FURNI ? canUseFurniInternalReference(key) : canUseUserInternalReference(key);
|
||||
}
|
||||
|
||||
if (this.getVariableTargetType() == TARGET_FURNI) {
|
||||
return room != null && room.getFurniVariableManager().getDefinitionInfo(getCustomItemId(token)) != null;
|
||||
}
|
||||
|
||||
return room != null && room.getUserVariableManager().getDefinitionInfo(getCustomItemId(token)) != null;
|
||||
}
|
||||
|
||||
private boolean isValidReference(Room room, int targetType, String token) {
|
||||
if (token == null || token.isEmpty()) return false;
|
||||
|
||||
if (isInternalVariableToken(token)) {
|
||||
String key = getInternalVariableKey(token);
|
||||
return switch (targetType) {
|
||||
case TARGET_FURNI -> canUseFurniInternalReference(key);
|
||||
case TARGET_CONTEXT -> canUseContextInternalReference(key);
|
||||
case TARGET_ROOM -> canUseRoomInternalReference(key);
|
||||
default -> canUseUserInternalReference(key);
|
||||
};
|
||||
}
|
||||
|
||||
return switch (targetType) {
|
||||
case TARGET_FURNI -> {
|
||||
WiredVariableDefinitionInfo definition = (room != null) ? room.getFurniVariableManager().getDefinitionInfo(getCustomItemId(token)) : null;
|
||||
yield definition != null && definition.hasValue();
|
||||
}
|
||||
case TARGET_CONTEXT -> this.isValidContextCustomReference(room, getCustomItemId(token));
|
||||
case TARGET_ROOM -> {
|
||||
WiredVariableDefinitionInfo definition = (room != null) ? room.getRoomVariableManager().getDefinitionInfo(getCustomItemId(token)) : null;
|
||||
yield definition != null && definition.hasValue();
|
||||
}
|
||||
default -> {
|
||||
WiredVariableDefinitionInfo definition = (room != null) ? room.getUserVariableManager().getDefinitionInfo(getCustomItemId(token)) : null;
|
||||
yield definition != null && definition.hasValue();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private boolean isValidContextCustomReference(Room room, int variableItemId) {
|
||||
WiredVariableDefinitionInfo definition = WiredContextVariableSupport.getDefinitionInfo(room, variableItemId);
|
||||
return definition != null && definition.hasValue();
|
||||
}
|
||||
private static List<RoomUnit> trimUsers(List<SortableEntry<RoomUnit>> matches, int amount) {
|
||||
List<RoomUnit> result = new ArrayList<>();
|
||||
for (SortableEntry<RoomUnit> match : matches) {
|
||||
if (result.size() >= amount) break;
|
||||
result.add(match.entity);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static List<HabboItem> trimItems(List<SortableEntry<HabboItem>> matches, int amount) {
|
||||
List<HabboItem> result = new ArrayList<>();
|
||||
for (SortableEntry<HabboItem> match : matches) {
|
||||
if (result.size() >= amount) break;
|
||||
result.add(match.entity);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static List<RoomUnit> toUserList(Iterable<RoomUnit> values) {
|
||||
List<RoomUnit> result = new ArrayList<>();
|
||||
if (values == null) return result;
|
||||
for (RoomUnit value : values) if (value != null) result.add(value);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static List<HabboItem> toItemList(Iterable<HabboItem> values) {
|
||||
List<HabboItem> result = new ArrayList<>();
|
||||
if (values == null) return result;
|
||||
for (HabboItem value : values) if (value != null) result.add(value);
|
||||
return result;
|
||||
}
|
||||
|
||||
private String serializeStringData() {
|
||||
return (this.variableToken == null ? "" : this.variableToken) + DELIM + (this.referenceVariableToken == null ? "" : this.referenceVariableToken);
|
||||
}
|
||||
|
||||
private void refreshReferenceItems() {
|
||||
Room room = Emulator.getGameEnvironment().getRoomManager().getRoom(this.getRoomId());
|
||||
if (room == null) {
|
||||
this.referenceSelectedItems.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
this.referenceSelectedItems.removeIf(item -> item == null || item.getRoomId() != room.getId() || room.getHabboItem(item.getId()) == null);
|
||||
}
|
||||
|
||||
private void setVariableToken(String token) {
|
||||
this.variableToken = normalizeVariableToken(token);
|
||||
this.variableItemId = getCustomItemId(this.variableToken);
|
||||
}
|
||||
|
||||
private void setReferenceVariableToken(String token) {
|
||||
this.referenceVariableToken = normalizeVariableToken(token);
|
||||
this.referenceVariableItemId = getCustomItemId(this.referenceVariableToken);
|
||||
}
|
||||
|
||||
private List<Integer> toIds(List<HabboItem> items) {
|
||||
List<Integer> ids = new ArrayList<>();
|
||||
for (HabboItem item : items) if (item != null) ids.add(item.getId());
|
||||
return ids;
|
||||
}
|
||||
|
||||
private Integer readUserInternalValue(Room room, RoomUnit roomUnit, String key) {
|
||||
return WiredInternalVariableSupport.readUserValue(room, roomUnit, key);
|
||||
}
|
||||
|
||||
private Integer readFurniInternalValue(Room room, HabboItem item, String key) {
|
||||
return WiredInternalVariableSupport.readFurniValue(room, item, key);
|
||||
}
|
||||
|
||||
private Integer readRoomInternalValue(Room room, String key) {
|
||||
return WiredInternalVariableSupport.readRoomValue(room, key);
|
||||
}
|
||||
private int getUserTeamScore(Room room, Habbo habbo) {
|
||||
if (room == null || habbo == null || habbo.getHabboInfo() == null || habbo.getHabboInfo().getGamePlayer() == null) return 0;
|
||||
|
||||
Game game = this.resolveTeamGame(room, habbo);
|
||||
if (game == null) return 0;
|
||||
|
||||
GamePlayer player = habbo.getHabboInfo().getGamePlayer();
|
||||
return player.getScore();
|
||||
}
|
||||
|
||||
private int getTeamColorId(int effectValue) {
|
||||
TeamEffectData effectData = this.getTeamEffectData(effectValue);
|
||||
return (effectData != null) ? effectData.colorId : 0;
|
||||
}
|
||||
|
||||
private int getTeamTypeId(int effectValue) {
|
||||
TeamEffectData effectData = this.getTeamEffectData(effectValue);
|
||||
return (effectData != null) ? effectData.typeId : 0;
|
||||
}
|
||||
|
||||
private int getTeamMetric(Room room, GameTeamColors color, boolean score) {
|
||||
Game game = room.getGame(WiredGame.class);
|
||||
if (game == null) game = room.getGame(FreezeGame.class);
|
||||
if (game == null) game = room.getGame(BattleBanzaiGame.class);
|
||||
if (game == null) return 0;
|
||||
|
||||
GameTeam team = game.getTeam(color);
|
||||
if (team == null) return 0;
|
||||
|
||||
return score ? team.getTotalScore() : team.getMembers().size();
|
||||
}
|
||||
|
||||
private Game resolveTeamGame(Room room, Habbo habbo) {
|
||||
if (room == null) return null;
|
||||
|
||||
if (habbo != null && habbo.getHabboInfo() != null && habbo.getHabboInfo().getCurrentGame() != null) {
|
||||
Game game = room.getGame(habbo.getHabboInfo().getCurrentGame());
|
||||
if (game != null) return game;
|
||||
}
|
||||
|
||||
Game wiredGame = room.getGame(WiredGame.class);
|
||||
if (wiredGame != null) return wiredGame;
|
||||
|
||||
Game freezeGame = room.getGame(FreezeGame.class);
|
||||
if (freezeGame != null) return freezeGame;
|
||||
|
||||
return room.getGame(BattleBanzaiGame.class);
|
||||
}
|
||||
|
||||
private TeamEffectData getTeamEffectData(int effectValue) {
|
||||
if (effectValue <= 0) return null;
|
||||
|
||||
if (effectValue >= 223 && effectValue <= 226) return new TeamEffectData(effectValue - 222, 0);
|
||||
if (effectValue >= 33 && effectValue <= 36) return new TeamEffectData(effectValue - 32, 1);
|
||||
if (effectValue >= 40 && effectValue <= 43) return new TeamEffectData(effectValue - 39, 2);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static int normalizeSortBy(int value) {
|
||||
return switch (value) {
|
||||
case SORT_VALUE_LOWEST, SORT_CREATION_OLDEST, SORT_CREATION_LATEST, SORT_UPDATE_OLDEST, SORT_UPDATE_LATEST -> value;
|
||||
default -> SORT_VALUE_HIGHEST;
|
||||
};
|
||||
}
|
||||
|
||||
private static int normalizeAmountMode(int value) {
|
||||
return (value == AMOUNT_VARIABLE) ? AMOUNT_VARIABLE : AMOUNT_CONSTANT;
|
||||
}
|
||||
|
||||
private static int normalizeReferenceTargetType(int value) {
|
||||
return switch (value) {
|
||||
case TARGET_FURNI, TARGET_CONTEXT, TARGET_ROOM -> value;
|
||||
default -> TARGET_USER;
|
||||
};
|
||||
}
|
||||
|
||||
private static int normalizeUserSource(int value) {
|
||||
return WiredSourceUtil.isDefaultUserSource(value) ? value : WiredSourceUtil.SOURCE_TRIGGER;
|
||||
}
|
||||
|
||||
private static int normalizeReferenceFurniSource(int value) {
|
||||
return switch (value) {
|
||||
case SOURCE_SECONDARY_SELECTED, WiredSourceUtil.SOURCE_SELECTOR, WiredSourceUtil.SOURCE_SIGNAL -> value;
|
||||
default -> WiredSourceUtil.SOURCE_TRIGGER;
|
||||
};
|
||||
}
|
||||
|
||||
protected static String normalizeVariableToken(String token) {
|
||||
if (token == null) return "";
|
||||
|
||||
String normalized = token.trim();
|
||||
if (normalized.isEmpty()) return "";
|
||||
if (normalized.startsWith(INTERNAL_TOKEN_PREFIX)) {
|
||||
return INTERNAL_TOKEN_PREFIX + WiredInternalVariableSupport.normalizeKey(normalized.substring(INTERNAL_TOKEN_PREFIX.length()));
|
||||
}
|
||||
if (isCustomVariableToken(normalized) || isInternalVariableToken(normalized)) return normalized;
|
||||
|
||||
try {
|
||||
int parsed = Integer.parseInt(normalized);
|
||||
return (parsed > 0) ? (CUSTOM_TOKEN_PREFIX + parsed) : "";
|
||||
} catch (NumberFormatException e) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
protected static boolean isCustomVariableToken(String token) {
|
||||
return token != null && token.startsWith(CUSTOM_TOKEN_PREFIX);
|
||||
}
|
||||
|
||||
protected static boolean isInternalVariableToken(String token) {
|
||||
return token != null && token.startsWith(INTERNAL_TOKEN_PREFIX);
|
||||
}
|
||||
|
||||
protected static int getCustomItemId(String token) {
|
||||
if (!isCustomVariableToken(token)) return 0;
|
||||
|
||||
try {
|
||||
return Integer.parseInt(token.substring(CUSTOM_TOKEN_PREFIX.length()));
|
||||
} catch (NumberFormatException e) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
protected static String getInternalVariableKey(String token) {
|
||||
return isInternalVariableToken(token) ? WiredInternalVariableSupport.normalizeKey(token.substring(INTERNAL_TOKEN_PREFIX.length())) : "";
|
||||
}
|
||||
|
||||
private static boolean canUseUserInternalReference(String key) {
|
||||
return WiredInternalVariableSupport.canUseUserReference(key);
|
||||
}
|
||||
|
||||
private static boolean canUseFurniInternalReference(String key) {
|
||||
return WiredInternalVariableSupport.canUseFurniReference(key);
|
||||
}
|
||||
|
||||
private static boolean canUseRoomInternalReference(String key) {
|
||||
return WiredInternalVariableSupport.canUseRoomReference(key);
|
||||
}
|
||||
|
||||
private static boolean canUseContextInternalReference(String key) {
|
||||
return WiredInternalVariableSupport.canUseContextReference(key);
|
||||
}
|
||||
|
||||
private static int param(int[] params, int index, int fallback) {
|
||||
return (params != null && params.length > index) ? params[index] : fallback;
|
||||
}
|
||||
|
||||
private static String[] parseStringData(String value) {
|
||||
return (value == null || value.isEmpty()) ? new String[0] : value.split("\\t", -1);
|
||||
}
|
||||
|
||||
private static int parseInteger(String value) {
|
||||
try {
|
||||
return (value == null || value.trim().isEmpty()) ? 0 : Integer.parseInt(value.trim());
|
||||
} catch (NumberFormatException e) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
private static int normalizeAmount(int value) {
|
||||
return Math.max(0, Math.min(MAX_FILTER_AMOUNT, value));
|
||||
}
|
||||
|
||||
protected static class JsonData {
|
||||
int sortBy;
|
||||
int amountMode;
|
||||
int amountConstantValue;
|
||||
int referenceTargetType;
|
||||
int referenceUserSource;
|
||||
int referenceFurniSource;
|
||||
String variableToken;
|
||||
int variableItemId;
|
||||
String referenceVariableToken;
|
||||
int referenceVariableItemId;
|
||||
List<Integer> selectedItemIds;
|
||||
|
||||
JsonData(int sortBy, int amountMode, int amountConstantValue, int referenceTargetType, int referenceUserSource, int referenceFurniSource, String variableToken, int variableItemId, String referenceVariableToken, int referenceVariableItemId, List<Integer> selectedItemIds) {
|
||||
this.sortBy = sortBy;
|
||||
this.amountMode = amountMode;
|
||||
this.amountConstantValue = amountConstantValue;
|
||||
this.referenceTargetType = referenceTargetType;
|
||||
this.referenceUserSource = referenceUserSource;
|
||||
this.referenceFurniSource = referenceFurniSource;
|
||||
this.variableToken = variableToken;
|
||||
this.variableItemId = variableItemId;
|
||||
this.referenceVariableToken = referenceVariableToken;
|
||||
this.referenceVariableItemId = referenceVariableItemId;
|
||||
this.selectedItemIds = selectedItemIds;
|
||||
}
|
||||
}
|
||||
|
||||
private static class SortableEntry<T> {
|
||||
final T entity;
|
||||
final MetricSnapshot metric;
|
||||
|
||||
SortableEntry(T entity, MetricSnapshot metric) {
|
||||
this.entity = entity;
|
||||
this.metric = metric;
|
||||
}
|
||||
}
|
||||
|
||||
private static class MetricSnapshot {
|
||||
final int entityId;
|
||||
final int value;
|
||||
final int createdAt;
|
||||
final int updatedAt;
|
||||
|
||||
MetricSnapshot(int entityId, int value, int createdAt, int updatedAt) {
|
||||
this.entityId = entityId;
|
||||
this.value = value;
|
||||
this.createdAt = createdAt;
|
||||
this.updatedAt = updatedAt;
|
||||
}
|
||||
}
|
||||
|
||||
private static class TeamEffectData {
|
||||
final int colorId;
|
||||
final int typeId;
|
||||
|
||||
TeamEffectData(int colorId, int typeId) {
|
||||
this.colorId = colorId;
|
||||
this.typeId = typeId;
|
||||
}
|
||||
}
|
||||
}
|
||||
+270
@@ -0,0 +1,270 @@
|
||||
package com.eu.habbo.habbohotel.items.interactions.wired.extra;
|
||||
|
||||
import com.eu.habbo.habbohotel.gameclients.GameClient;
|
||||
import com.eu.habbo.habbohotel.items.Item;
|
||||
import com.eu.habbo.habbohotel.items.interactions.InteractionWiredExtra;
|
||||
import com.eu.habbo.habbohotel.items.interactions.wired.WiredSettings;
|
||||
import com.eu.habbo.habbohotel.rooms.Room;
|
||||
import com.eu.habbo.habbohotel.rooms.RoomUnit;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredManager;
|
||||
import com.eu.habbo.messages.ServerMessage;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class WiredExtraVariableLevelUpSystem extends InteractionWiredExtra {
|
||||
public static final int CODE = 82;
|
||||
|
||||
public static final int MODE_LINEAR = 1;
|
||||
public static final int MODE_EXPONENTIAL = 2;
|
||||
public static final int MODE_MANUAL = 3;
|
||||
|
||||
public static final int SUB_CURRENT_LEVEL = 0;
|
||||
public static final int SUB_CURRENT_XP = 1;
|
||||
public static final int SUB_LEVEL_PROGRESS = 2;
|
||||
public static final int SUB_LEVEL_PROGRESS_PERCENT = 3;
|
||||
public static final int SUB_TOTAL_XP_REQUIRED = 4;
|
||||
public static final int SUB_XP_REMAINING = 5;
|
||||
public static final int SUB_IS_AT_MAX = 6;
|
||||
public static final int SUB_MAX_LEVEL = 7;
|
||||
public static final int SUBVARIABLE_COUNT = 8;
|
||||
|
||||
private static final int DEFAULT_STEP_SIZE = 100;
|
||||
private static final int DEFAULT_MAX_LEVEL = 10;
|
||||
private static final int DEFAULT_FIRST_LEVEL_XP = 100;
|
||||
private static final int DEFAULT_INCREASE_FACTOR = 100;
|
||||
private static final int MAX_MANUAL_TEXT_LENGTH = 4096;
|
||||
|
||||
private int mode = MODE_LINEAR;
|
||||
private int stepSize = DEFAULT_STEP_SIZE;
|
||||
private int maxLevel = DEFAULT_MAX_LEVEL;
|
||||
private int firstLevelXp = DEFAULT_FIRST_LEVEL_XP;
|
||||
private int increaseFactor = DEFAULT_INCREASE_FACTOR;
|
||||
private String interpolationText = "";
|
||||
private int subvariableMask = (1 << SUB_CURRENT_LEVEL) | (1 << SUB_CURRENT_XP);
|
||||
|
||||
public WiredExtraVariableLevelUpSystem(ResultSet set, Item baseItem) throws SQLException {
|
||||
super(set, baseItem);
|
||||
}
|
||||
|
||||
public WiredExtraVariableLevelUpSystem(int id, int userId, Item item, String extradata, int limitedStack, int limitedSells) {
|
||||
super(id, userId, item, extradata, limitedStack, limitedSells);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean execute(RoomUnit roomUnit, Room room, Object[] stuff) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean saveData(WiredSettings settings, GameClient gameClient) {
|
||||
this.applyConfig(parseJsonData(settings.getStringParam()));
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getWiredData() {
|
||||
return WiredManager.getGson().toJson(new JsonData(
|
||||
this.mode,
|
||||
this.stepSize,
|
||||
this.maxLevel,
|
||||
this.firstLevelXp,
|
||||
this.increaseFactor,
|
||||
this.interpolationText,
|
||||
this.getSelectedSubvariables()
|
||||
));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serializeWiredData(ServerMessage message, Room room) {
|
||||
message.appendBoolean(false);
|
||||
message.appendInt(0);
|
||||
message.appendInt(0);
|
||||
message.appendInt(this.getBaseItem().getSpriteId());
|
||||
message.appendInt(this.getId());
|
||||
message.appendString(this.getWiredData());
|
||||
message.appendInt(0);
|
||||
message.appendInt(0);
|
||||
message.appendInt(CODE);
|
||||
message.appendInt(0);
|
||||
message.appendInt(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadWiredData(ResultSet set, Room room) throws SQLException {
|
||||
this.onPickUp();
|
||||
|
||||
String wiredData = set.getString("wired_data");
|
||||
if (wiredData == null || wiredData.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.applyConfig(parseJsonData(wiredData));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPickUp() {
|
||||
this.mode = MODE_LINEAR;
|
||||
this.stepSize = DEFAULT_STEP_SIZE;
|
||||
this.maxLevel = DEFAULT_MAX_LEVEL;
|
||||
this.firstLevelXp = DEFAULT_FIRST_LEVEL_XP;
|
||||
this.increaseFactor = DEFAULT_INCREASE_FACTOR;
|
||||
this.interpolationText = "";
|
||||
this.subvariableMask = (1 << SUB_CURRENT_LEVEL) | (1 << SUB_CURRENT_XP);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWalk(RoomUnit roomUnit, Room room, Object[] objects) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasConfiguration() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public int getMode() {
|
||||
return this.mode;
|
||||
}
|
||||
|
||||
public int getStepSize() {
|
||||
return this.stepSize;
|
||||
}
|
||||
|
||||
public int getMaxLevel() {
|
||||
return this.maxLevel;
|
||||
}
|
||||
|
||||
public int getFirstLevelXp() {
|
||||
return this.firstLevelXp;
|
||||
}
|
||||
|
||||
public int getIncreaseFactor() {
|
||||
return this.increaseFactor;
|
||||
}
|
||||
|
||||
public String getInterpolationText() {
|
||||
return this.interpolationText;
|
||||
}
|
||||
|
||||
public boolean hasSubvariable(int subvariableType) {
|
||||
return subvariableType >= 0
|
||||
&& subvariableType < SUBVARIABLE_COUNT
|
||||
&& ((this.subvariableMask & (1 << subvariableType)) != 0);
|
||||
}
|
||||
|
||||
public List<Integer> getSelectedSubvariables() {
|
||||
List<Integer> result = new ArrayList<>();
|
||||
|
||||
for (int index = 0; index < SUBVARIABLE_COUNT; index++) {
|
||||
if (this.hasSubvariable(index)) {
|
||||
result.add(index);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private void applyConfig(JsonData data) {
|
||||
if (data == null) {
|
||||
this.onPickUp();
|
||||
return;
|
||||
}
|
||||
|
||||
this.mode = normalizeMode(data.mode);
|
||||
this.stepSize = normalizeNonNegative(data.stepSize, DEFAULT_STEP_SIZE);
|
||||
this.maxLevel = normalizeMaxLevel(data.maxLevel);
|
||||
this.firstLevelXp = normalizeNonNegative(data.firstLevelXp, DEFAULT_FIRST_LEVEL_XP);
|
||||
this.increaseFactor = normalizeNonNegative(data.increaseFactor, DEFAULT_INCREASE_FACTOR);
|
||||
this.interpolationText = normalizeInterpolationText(data.interpolationText);
|
||||
this.subvariableMask = normalizeSubvariableMask(data.subvariables);
|
||||
}
|
||||
|
||||
private static JsonData parseJsonData(String value) {
|
||||
if (value == null || value.trim().isEmpty()) {
|
||||
return new JsonData();
|
||||
}
|
||||
|
||||
try {
|
||||
if (value.trim().startsWith("{")) {
|
||||
JsonData data = WiredManager.getGson().fromJson(value, JsonData.class);
|
||||
return (data != null) ? data : new JsonData();
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
|
||||
JsonData fallback = new JsonData();
|
||||
fallback.interpolationText = normalizeInterpolationText(value);
|
||||
fallback.mode = MODE_MANUAL;
|
||||
return fallback;
|
||||
}
|
||||
|
||||
private static int normalizeMode(int value) {
|
||||
return switch (value) {
|
||||
case MODE_EXPONENTIAL, MODE_MANUAL -> value;
|
||||
default -> MODE_LINEAR;
|
||||
};
|
||||
}
|
||||
|
||||
private static int normalizeNonNegative(int value, int fallback) {
|
||||
return Math.max(0, (value > 0) ? value : fallback);
|
||||
}
|
||||
|
||||
private static int normalizeMaxLevel(int value) {
|
||||
return Math.max(1, (value > 0) ? value : DEFAULT_MAX_LEVEL);
|
||||
}
|
||||
|
||||
private static String normalizeInterpolationText(String value) {
|
||||
if (value == null) {
|
||||
return "";
|
||||
}
|
||||
|
||||
String normalized = value.replace("\r", "");
|
||||
if (normalized.length() > MAX_MANUAL_TEXT_LENGTH) {
|
||||
normalized = normalized.substring(0, MAX_MANUAL_TEXT_LENGTH);
|
||||
}
|
||||
|
||||
return normalized;
|
||||
}
|
||||
|
||||
private static int normalizeSubvariableMask(List<Integer> subvariables) {
|
||||
if (subvariables == null) {
|
||||
return (1 << SUB_CURRENT_LEVEL) | (1 << SUB_CURRENT_XP);
|
||||
}
|
||||
|
||||
int mask = 0;
|
||||
for (Integer subvariable : subvariables) {
|
||||
if (subvariable == null || subvariable < 0 || subvariable >= SUBVARIABLE_COUNT) {
|
||||
continue;
|
||||
}
|
||||
|
||||
mask |= (1 << subvariable);
|
||||
}
|
||||
|
||||
return mask;
|
||||
}
|
||||
|
||||
static class JsonData {
|
||||
int mode = MODE_LINEAR;
|
||||
int stepSize = DEFAULT_STEP_SIZE;
|
||||
int maxLevel = DEFAULT_MAX_LEVEL;
|
||||
int firstLevelXp = DEFAULT_FIRST_LEVEL_XP;
|
||||
int increaseFactor = DEFAULT_INCREASE_FACTOR;
|
||||
String interpolationText = "";
|
||||
List<Integer> subvariables = null;
|
||||
|
||||
JsonData() {
|
||||
}
|
||||
|
||||
JsonData(int mode, int stepSize, int maxLevel, int firstLevelXp, int increaseFactor, String interpolationText, List<Integer> subvariables) {
|
||||
this.mode = mode;
|
||||
this.stepSize = stepSize;
|
||||
this.maxLevel = maxLevel;
|
||||
this.firstLevelXp = firstLevelXp;
|
||||
this.increaseFactor = increaseFactor;
|
||||
this.interpolationText = interpolationText;
|
||||
this.subvariables = subvariables;
|
||||
}
|
||||
}
|
||||
}
|
||||
+321
@@ -0,0 +1,321 @@
|
||||
package com.eu.habbo.habbohotel.items.interactions.wired.extra;
|
||||
|
||||
import com.eu.habbo.Emulator;
|
||||
import com.eu.habbo.habbohotel.gameclients.GameClient;
|
||||
import com.eu.habbo.habbohotel.items.Item;
|
||||
import com.eu.habbo.habbohotel.items.interactions.InteractionWiredExtra;
|
||||
import com.eu.habbo.habbohotel.items.interactions.wired.WiredSettings;
|
||||
import com.eu.habbo.habbohotel.rooms.Room;
|
||||
import com.eu.habbo.habbohotel.rooms.RoomUnit;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredManager;
|
||||
import com.eu.habbo.messages.ServerMessage;
|
||||
import com.eu.habbo.messages.incoming.wired.WiredSaveException;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class WiredExtraVariableReference extends InteractionWiredExtra {
|
||||
public static final int CODE = 81;
|
||||
|
||||
private String variableName = "";
|
||||
private int sourceRoomId = 0;
|
||||
private String sourceRoomName = "";
|
||||
private int sourceVariableItemId = 0;
|
||||
private String sourceVariableName = "";
|
||||
private int sourceTargetType = WiredVariableReferenceSupport.TARGET_USER;
|
||||
private boolean hasValue = false;
|
||||
private boolean readOnly = true;
|
||||
|
||||
public WiredExtraVariableReference(ResultSet set, Item baseItem) throws SQLException {
|
||||
super(set, baseItem);
|
||||
}
|
||||
|
||||
public WiredExtraVariableReference(int id, int userId, Item item, String extradata, int limitedStack, int limitedSells) {
|
||||
super(id, userId, item, extradata, limitedStack, limitedSells);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean execute(RoomUnit roomUnit, Room room, Object[] stuff) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean saveData(WiredSettings settings, GameClient gameClient) throws WiredSaveException {
|
||||
Room room = Emulator.getGameEnvironment().getRoomManager().getRoom(this.getRoomId());
|
||||
|
||||
if (room == null) {
|
||||
throw new WiredSaveException("Room not found");
|
||||
}
|
||||
|
||||
ConfigData config = parseConfigData(settings.getStringParam());
|
||||
String normalizedName = WiredVariableNameValidator.normalizeForSave(config.variableName);
|
||||
|
||||
WiredVariableNameValidator.validateDefinitionName(room, this.getId(), normalizedName);
|
||||
|
||||
if (config.sourceRoomId <= 0 || config.sourceVariableItemId <= 0) {
|
||||
throw new WiredSaveException("wiredfurni.params.variables.validation.missing_variable");
|
||||
}
|
||||
|
||||
WiredVariableReferenceSupport.SharedDefinitionOption definition = WiredVariableReferenceSupport.findSharedDefinition(
|
||||
room,
|
||||
config.sourceRoomId,
|
||||
config.sourceVariableItemId,
|
||||
config.sourceTargetType
|
||||
);
|
||||
|
||||
if (definition == null) {
|
||||
throw new WiredSaveException("wiredfurni.params.variables.validation.invalid_variable");
|
||||
}
|
||||
|
||||
this.variableName = normalizedName;
|
||||
this.sourceRoomId = definition.getRoomId();
|
||||
this.sourceRoomName = sanitizeLabel(definition.getRoomName());
|
||||
this.sourceVariableItemId = definition.getItemId();
|
||||
this.sourceVariableName = definition.getName();
|
||||
this.sourceTargetType = definition.getTargetType();
|
||||
this.hasValue = definition.hasValue();
|
||||
this.readOnly = config.readOnly;
|
||||
|
||||
room.getUserVariableManager().broadcastSnapshot();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getWiredData() {
|
||||
return WiredManager.getGson().toJson(new JsonData(
|
||||
this.variableName,
|
||||
this.sourceRoomId,
|
||||
this.sourceRoomName,
|
||||
this.sourceVariableItemId,
|
||||
this.sourceVariableName,
|
||||
this.sourceTargetType,
|
||||
this.hasValue,
|
||||
this.readOnly
|
||||
));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serializeWiredData(ServerMessage message, Room room) {
|
||||
message.appendBoolean(false);
|
||||
message.appendInt(0);
|
||||
message.appendInt(0);
|
||||
message.appendInt(this.getBaseItem().getSpriteId());
|
||||
message.appendInt(this.getId());
|
||||
message.appendString(buildEditorPayload(room));
|
||||
message.appendInt(0);
|
||||
message.appendInt(0);
|
||||
message.appendInt(CODE);
|
||||
message.appendInt(0);
|
||||
message.appendInt(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadWiredData(ResultSet set, Room room) throws SQLException {
|
||||
this.onPickUp();
|
||||
|
||||
String wiredData = set.getString("wired_data");
|
||||
if (wiredData == null || wiredData.isEmpty() || !wiredData.startsWith("{")) {
|
||||
return;
|
||||
}
|
||||
|
||||
JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class);
|
||||
if (data == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.variableName = WiredVariableNameValidator.normalizeLegacy(data.variableName);
|
||||
this.sourceRoomId = Math.max(0, data.sourceRoomId);
|
||||
this.sourceRoomName = sanitizeLabel(data.sourceRoomName);
|
||||
this.sourceVariableItemId = Math.max(0, data.sourceVariableItemId);
|
||||
this.sourceVariableName = WiredVariableNameValidator.normalizeLegacy(data.sourceVariableName);
|
||||
this.sourceTargetType = normalizeTargetType(data.sourceTargetType);
|
||||
this.hasValue = data.hasValue;
|
||||
this.readOnly = data.readOnly;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPickUp() {
|
||||
this.variableName = "";
|
||||
this.sourceRoomId = 0;
|
||||
this.sourceRoomName = "";
|
||||
this.sourceVariableItemId = 0;
|
||||
this.sourceVariableName = "";
|
||||
this.sourceTargetType = WiredVariableReferenceSupport.TARGET_USER;
|
||||
this.hasValue = false;
|
||||
this.readOnly = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWalk(RoomUnit roomUnit, Room room, Object[] objects) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasConfiguration() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public String getVariableName() {
|
||||
return this.variableName;
|
||||
}
|
||||
|
||||
public int getSourceRoomId() {
|
||||
return this.sourceRoomId;
|
||||
}
|
||||
|
||||
public String getSourceRoomName() {
|
||||
return this.sourceRoomName;
|
||||
}
|
||||
|
||||
public int getSourceVariableItemId() {
|
||||
return this.sourceVariableItemId;
|
||||
}
|
||||
|
||||
public String getSourceVariableName() {
|
||||
return this.sourceVariableName;
|
||||
}
|
||||
|
||||
public int getSourceTargetType() {
|
||||
return this.sourceTargetType;
|
||||
}
|
||||
|
||||
public boolean hasValue() {
|
||||
return this.hasValue;
|
||||
}
|
||||
|
||||
public boolean isReadOnly() {
|
||||
return this.readOnly;
|
||||
}
|
||||
|
||||
public int getAvailability() {
|
||||
return WiredVariableReferenceSupport.SHARED_AVAILABILITY;
|
||||
}
|
||||
|
||||
public boolean isUserReference() {
|
||||
return this.sourceTargetType == WiredVariableReferenceSupport.TARGET_USER;
|
||||
}
|
||||
|
||||
public boolean isRoomReference() {
|
||||
return this.sourceTargetType == WiredVariableReferenceSupport.TARGET_ROOM;
|
||||
}
|
||||
|
||||
private String buildEditorPayload(Room room) {
|
||||
List<RoomEditorData> roomOptions = new ArrayList<>();
|
||||
|
||||
for (WiredVariableReferenceSupport.RoomOption option : WiredVariableReferenceSupport.loadRoomOptions(room)) {
|
||||
List<VariableEditorData> variables = new ArrayList<>();
|
||||
|
||||
for (WiredVariableReferenceSupport.SharedDefinitionOption definition : option.getVariables()) {
|
||||
variables.add(new VariableEditorData(definition.getItemId(), definition.getName(), definition.getTargetType(), definition.hasValue()));
|
||||
}
|
||||
|
||||
roomOptions.add(new RoomEditorData(option.getRoomId(), option.getRoomName(), variables));
|
||||
}
|
||||
|
||||
return WiredManager.getGson().toJson(new EditorPayload(
|
||||
this.variableName,
|
||||
this.sourceRoomId,
|
||||
this.sourceRoomName,
|
||||
this.sourceVariableItemId,
|
||||
this.sourceVariableName,
|
||||
this.sourceTargetType,
|
||||
this.readOnly,
|
||||
roomOptions
|
||||
));
|
||||
}
|
||||
|
||||
private static ConfigData parseConfigData(String value) {
|
||||
if (value == null || value.isEmpty() || !value.startsWith("{")) {
|
||||
return new ConfigData();
|
||||
}
|
||||
|
||||
ConfigData config = WiredManager.getGson().fromJson(value, ConfigData.class);
|
||||
return (config != null) ? config : new ConfigData();
|
||||
}
|
||||
|
||||
private static int normalizeTargetType(int value) {
|
||||
return (value == WiredVariableReferenceSupport.TARGET_ROOM) ? WiredVariableReferenceSupport.TARGET_ROOM : WiredVariableReferenceSupport.TARGET_USER;
|
||||
}
|
||||
|
||||
private static String sanitizeLabel(String value) {
|
||||
if (value == null) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return value.trim().replace("\t", "").replace("\r", "").replace("\n", "");
|
||||
}
|
||||
|
||||
static class JsonData {
|
||||
String variableName;
|
||||
int sourceRoomId;
|
||||
String sourceRoomName;
|
||||
int sourceVariableItemId;
|
||||
String sourceVariableName;
|
||||
int sourceTargetType;
|
||||
boolean hasValue;
|
||||
boolean readOnly;
|
||||
|
||||
JsonData(String variableName, int sourceRoomId, String sourceRoomName, int sourceVariableItemId, String sourceVariableName, int sourceTargetType, boolean hasValue, boolean readOnly) {
|
||||
this.variableName = variableName;
|
||||
this.sourceRoomId = sourceRoomId;
|
||||
this.sourceRoomName = sourceRoomName;
|
||||
this.sourceVariableItemId = sourceVariableItemId;
|
||||
this.sourceVariableName = sourceVariableName;
|
||||
this.sourceTargetType = sourceTargetType;
|
||||
this.hasValue = hasValue;
|
||||
this.readOnly = readOnly;
|
||||
}
|
||||
}
|
||||
|
||||
static class ConfigData {
|
||||
String variableName = "";
|
||||
int sourceRoomId = 0;
|
||||
int sourceVariableItemId = 0;
|
||||
int sourceTargetType = WiredVariableReferenceSupport.TARGET_USER;
|
||||
boolean readOnly = true;
|
||||
}
|
||||
|
||||
static class EditorPayload extends ConfigData {
|
||||
String sourceRoomName;
|
||||
String sourceVariableName;
|
||||
List<RoomEditorData> rooms;
|
||||
|
||||
EditorPayload(String variableName, int sourceRoomId, String sourceRoomName, int sourceVariableItemId, String sourceVariableName, int sourceTargetType, boolean readOnly, List<RoomEditorData> rooms) {
|
||||
this.variableName = variableName;
|
||||
this.sourceRoomId = sourceRoomId;
|
||||
this.sourceRoomName = sourceRoomName;
|
||||
this.sourceVariableItemId = sourceVariableItemId;
|
||||
this.sourceVariableName = sourceVariableName;
|
||||
this.sourceTargetType = sourceTargetType;
|
||||
this.readOnly = readOnly;
|
||||
this.rooms = rooms;
|
||||
}
|
||||
}
|
||||
|
||||
static class RoomEditorData {
|
||||
int roomId;
|
||||
String roomName;
|
||||
List<VariableEditorData> variables;
|
||||
|
||||
RoomEditorData(int roomId, String roomName, List<VariableEditorData> variables) {
|
||||
this.roomId = roomId;
|
||||
this.roomName = roomName;
|
||||
this.variables = variables;
|
||||
}
|
||||
}
|
||||
|
||||
static class VariableEditorData {
|
||||
int itemId;
|
||||
String name;
|
||||
int targetType;
|
||||
boolean hasValue;
|
||||
|
||||
VariableEditorData(int itemId, String name, int targetType, boolean hasValue) {
|
||||
this.itemId = itemId;
|
||||
this.name = name;
|
||||
this.targetType = targetType;
|
||||
this.hasValue = hasValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
+231
@@ -0,0 +1,231 @@
|
||||
package com.eu.habbo.habbohotel.items.interactions.wired.extra;
|
||||
|
||||
import com.eu.habbo.Emulator;
|
||||
import com.eu.habbo.habbohotel.gameclients.GameClient;
|
||||
import com.eu.habbo.habbohotel.items.Item;
|
||||
import com.eu.habbo.habbohotel.items.interactions.InteractionWiredExtra;
|
||||
import com.eu.habbo.habbohotel.items.interactions.wired.WiredSettings;
|
||||
import com.eu.habbo.habbohotel.rooms.Room;
|
||||
import com.eu.habbo.habbohotel.rooms.RoomUnit;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredContextVariableSupport;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredManager;
|
||||
import com.eu.habbo.messages.ServerMessage;
|
||||
import com.eu.habbo.messages.incoming.wired.WiredSaveException;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class WiredExtraVariableTextConnector extends InteractionWiredExtra {
|
||||
public static final int CODE = 79;
|
||||
public static final int MAX_MAPPING_LENGTH = 1000;
|
||||
public static final int MAX_MAPPING_LINES = 30;
|
||||
|
||||
private String mappingsText = "";
|
||||
private LinkedHashMap<Integer, String> mappings = new LinkedHashMap<>();
|
||||
|
||||
public WiredExtraVariableTextConnector(ResultSet set, Item baseItem) throws SQLException {
|
||||
super(set, baseItem);
|
||||
}
|
||||
|
||||
public WiredExtraVariableTextConnector(int id, int userId, Item item, String extradata, int limitedStack, int limitedSells) {
|
||||
super(id, userId, item, extradata, limitedStack, limitedSells);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean execute(RoomUnit roomUnit, Room room, Object[] stuff) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean saveData(WiredSettings settings, GameClient gameClient) throws WiredSaveException {
|
||||
String mappingsText = normalizeMappingsText(settings.getStringParam());
|
||||
validateMappingsText(mappingsText);
|
||||
this.setMappingsText(mappingsText);
|
||||
|
||||
Room room = Emulator.getGameEnvironment().getRoomManager().getRoom(this.getRoomId());
|
||||
if (room != null) {
|
||||
WiredContextVariableSupport.broadcastDefinitions(room);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getWiredData() {
|
||||
return WiredManager.getGson().toJson(new JsonData(this.mappingsText));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serializeWiredData(ServerMessage message, Room room) {
|
||||
message.appendBoolean(false);
|
||||
message.appendInt(0);
|
||||
message.appendInt(0);
|
||||
message.appendInt(this.getBaseItem().getSpriteId());
|
||||
message.appendInt(this.getId());
|
||||
message.appendString(this.mappingsText);
|
||||
message.appendInt(0);
|
||||
message.appendInt(0);
|
||||
message.appendInt(CODE);
|
||||
message.appendInt(0);
|
||||
message.appendInt(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadWiredData(ResultSet set, Room room) throws SQLException {
|
||||
this.onPickUp();
|
||||
|
||||
String wiredData = set.getString("wired_data");
|
||||
if (wiredData == null || wiredData.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (wiredData.startsWith("{")) {
|
||||
JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class);
|
||||
|
||||
if (data != null) {
|
||||
this.setMappingsText(data.mappingsText);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
this.setMappingsText(wiredData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPickUp() {
|
||||
this.mappingsText = "";
|
||||
this.mappings = new LinkedHashMap<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWalk(RoomUnit roomUnit, Room room, Object[] objects) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasConfiguration() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public String getMappingsText() {
|
||||
return this.mappingsText;
|
||||
}
|
||||
|
||||
public Map<Integer, String> getMappings() {
|
||||
return Collections.unmodifiableMap(this.mappings);
|
||||
}
|
||||
|
||||
public String resolveText(Integer value) {
|
||||
if (value == null) {
|
||||
return "";
|
||||
}
|
||||
|
||||
String mappedValue = this.mappings.get(value);
|
||||
return mappedValue != null ? mappedValue : String.valueOf(value);
|
||||
}
|
||||
|
||||
public Integer resolveValue(String text) {
|
||||
if (text == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String normalizedText = text.trim();
|
||||
if (normalizedText.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (Map.Entry<Integer, String> entry : this.mappings.entrySet()) {
|
||||
if (entry == null || entry.getKey() == null || entry.getValue() == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (entry.getValue().trim().equalsIgnoreCase(normalizedText)) {
|
||||
return entry.getKey();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void setMappingsText(String value) {
|
||||
this.mappingsText = normalizeMappingsText(value);
|
||||
this.mappings = parseMappings(this.mappingsText);
|
||||
}
|
||||
|
||||
private static String normalizeMappingsText(String value) {
|
||||
if (value == null) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return value.replace("\r", "");
|
||||
}
|
||||
|
||||
private static void validateMappingsText(String value) throws WiredSaveException {
|
||||
if (value == null || value.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (value.length() > MAX_MAPPING_LENGTH) {
|
||||
throw new WiredSaveException("Variable text connector can contain at most 1000 characters.");
|
||||
}
|
||||
|
||||
int lineCount = 1;
|
||||
for (int i = 0; i < value.length(); i++) {
|
||||
if (value.charAt(i) == '\n') {
|
||||
lineCount++;
|
||||
}
|
||||
}
|
||||
|
||||
if (lineCount > MAX_MAPPING_LINES) {
|
||||
throw new WiredSaveException("Variable text connector can contain at most 30 lines.");
|
||||
}
|
||||
}
|
||||
|
||||
private static LinkedHashMap<Integer, String> parseMappings(String value) {
|
||||
LinkedHashMap<Integer, String> result = new LinkedHashMap<>();
|
||||
if (value == null || value.isEmpty()) {
|
||||
return result;
|
||||
}
|
||||
|
||||
for (String rawLine : value.split("\n")) {
|
||||
if (rawLine == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String line = rawLine.trim();
|
||||
if (line.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int separatorIndex = line.indexOf('=');
|
||||
if (separatorIndex < 0) {
|
||||
separatorIndex = line.indexOf(',');
|
||||
}
|
||||
|
||||
if (separatorIndex <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String keyPart = line.substring(0, separatorIndex).trim();
|
||||
String valuePart = line.substring(separatorIndex + 1).trim();
|
||||
|
||||
try {
|
||||
result.put(Integer.parseInt(keyPart), valuePart);
|
||||
} catch (NumberFormatException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static class JsonData {
|
||||
String mappingsText;
|
||||
|
||||
JsonData(String mappingsText) {
|
||||
this.mappingsText = mappingsText;
|
||||
}
|
||||
}
|
||||
}
|
||||
+111
@@ -0,0 +1,111 @@
|
||||
package com.eu.habbo.habbohotel.items.interactions.wired.extra;
|
||||
|
||||
import com.eu.habbo.habbohotel.items.interactions.InteractionWiredExtra;
|
||||
import com.eu.habbo.habbohotel.rooms.Room;
|
||||
import com.eu.habbo.messages.incoming.wired.WiredSaveException;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
final class WiredVariableNameValidator {
|
||||
static final int MIN_NAME_LENGTH = 1;
|
||||
static final int MAX_NAME_LENGTH = 40;
|
||||
|
||||
private static final Pattern VALID_NAME_PATTERN = Pattern.compile("^[A-Za-z0-9_]+$");
|
||||
|
||||
private WiredVariableNameValidator() {
|
||||
}
|
||||
|
||||
static String normalizeForSave(String value) {
|
||||
if (value == null) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return value
|
||||
.replace("\t", "")
|
||||
.replace("\r", "")
|
||||
.replace("\n", "")
|
||||
.replaceAll("\\s+", "_");
|
||||
}
|
||||
|
||||
static String normalizeLegacy(String value) {
|
||||
String normalized = normalizeForSave(value);
|
||||
|
||||
if (normalized.contains("=")) {
|
||||
normalized = normalized.substring(0, normalized.indexOf('='));
|
||||
}
|
||||
|
||||
while (normalized.startsWith("@") || normalized.startsWith("~")) {
|
||||
normalized = normalized.substring(1);
|
||||
}
|
||||
|
||||
if (normalized.length() > MAX_NAME_LENGTH) {
|
||||
normalized = normalized.substring(0, MAX_NAME_LENGTH);
|
||||
}
|
||||
|
||||
return normalized;
|
||||
}
|
||||
|
||||
static void validateDefinitionName(Room room, int currentItemId, String variableName) throws WiredSaveException {
|
||||
String normalized = normalizeForSave(variableName);
|
||||
|
||||
if (normalized.length() < MIN_NAME_LENGTH || normalized.length() > MAX_NAME_LENGTH) {
|
||||
throw new WiredSaveException("wiredfurni.error.variables.name_length");
|
||||
}
|
||||
|
||||
if (!VALID_NAME_PATTERN.matcher(normalized).matches()) {
|
||||
throw new WiredSaveException("wiredfurni.error.variables.name_syntax");
|
||||
}
|
||||
|
||||
if (isNameInUse(room, currentItemId, normalized)) {
|
||||
throw new WiredSaveException("wiredfurni.error.variables.name_uniq");
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isNameInUse(Room room, int currentItemId, String variableName) {
|
||||
if (room == null || room.getRoomSpecialTypes() == null || variableName == null || variableName.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (InteractionWiredExtra extra : room.getRoomSpecialTypes().getExtras()) {
|
||||
if (extra == null || extra.getId() == currentItemId) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String existingName = getDefinitionName(extra);
|
||||
|
||||
if (existingName != null && existingName.equalsIgnoreCase(variableName)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static String getDefinitionName(InteractionWiredExtra extra) {
|
||||
if (extra instanceof WiredExtraUserVariable) {
|
||||
return ((WiredExtraUserVariable) extra).getVariableName();
|
||||
}
|
||||
|
||||
if (extra instanceof WiredExtraFurniVariable) {
|
||||
return ((WiredExtraFurniVariable) extra).getVariableName();
|
||||
}
|
||||
|
||||
if (extra instanceof WiredExtraRoomVariable) {
|
||||
return ((WiredExtraRoomVariable) extra).getVariableName();
|
||||
}
|
||||
|
||||
if (extra instanceof WiredExtraContextVariable) {
|
||||
return ((WiredExtraContextVariable) extra).getVariableName();
|
||||
}
|
||||
|
||||
if (extra instanceof WiredExtraVariableReference) {
|
||||
return ((WiredExtraVariableReference) extra).getVariableName();
|
||||
}
|
||||
|
||||
if (extra instanceof WiredExtraVariableEcho) {
|
||||
return ((WiredExtraVariableEcho) extra).getVariableName();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
+630
@@ -0,0 +1,630 @@
|
||||
package com.eu.habbo.habbohotel.items.interactions.wired.extra;
|
||||
|
||||
import com.eu.habbo.Emulator;
|
||||
import com.eu.habbo.habbohotel.rooms.Room;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredManager;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public final class WiredVariableReferenceSupport {
|
||||
public static final int TARGET_USER = 0;
|
||||
public static final int TARGET_ROOM = 3;
|
||||
public static final int SHARED_AVAILABILITY = 11;
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(WiredVariableReferenceSupport.class);
|
||||
|
||||
private static final ConcurrentHashMap<String, CachedUserAssignment> USER_ASSIGNMENT_CACHE = new ConcurrentHashMap<>();
|
||||
private static final ConcurrentHashMap<String, CachedRoomAssignment> ROOM_ASSIGNMENT_CACHE = new ConcurrentHashMap<>();
|
||||
|
||||
private WiredVariableReferenceSupport() {
|
||||
}
|
||||
|
||||
public static boolean isSharedAvailability(int availability) {
|
||||
return availability == SHARED_AVAILABILITY;
|
||||
}
|
||||
|
||||
public static SharedDefinitionOption findSharedDefinition(Room room, int sourceRoomId, int sourceVariableItemId, int sourceTargetType) {
|
||||
if (room == null || sourceRoomId <= 0 || sourceVariableItemId <= 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (RoomOption roomOption : loadRoomOptions(room)) {
|
||||
if (roomOption.getRoomId() != sourceRoomId) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (SharedDefinitionOption definition : roomOption.getVariables()) {
|
||||
if (definition.getItemId() == sourceVariableItemId && definition.getTargetType() == sourceTargetType) {
|
||||
return definition;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static List<RoomOption> loadRoomOptions(Room room) {
|
||||
if (room == null || room.getOwnerId() <= 0) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
Map<Integer, RoomOption> optionsByRoomId = new LinkedHashMap<>();
|
||||
|
||||
try (Connection connection = Emulator.getDatabase().getDataSource().getConnection();
|
||||
PreparedStatement statement = connection.prepareStatement(
|
||||
"SELECT rooms.id AS room_id, rooms.name AS room_name, items.id AS item_id, items.wired_data, items_base.interaction_type " +
|
||||
"FROM rooms " +
|
||||
"INNER JOIN items ON rooms.id = items.room_id " +
|
||||
"INNER JOIN items_base ON items.item_id = items_base.id " +
|
||||
"WHERE rooms.owner_id = ? AND rooms.id <> ? AND items_base.interaction_type IN ('wf_var_user', 'wf_var_room') " +
|
||||
"ORDER BY rooms.name ASC, items.id ASC")) {
|
||||
statement.setInt(1, room.getOwnerId());
|
||||
statement.setInt(2, room.getId());
|
||||
|
||||
try (ResultSet set = statement.executeQuery()) {
|
||||
while (set.next()) {
|
||||
SharedDefinitionOption definition = parseSharedDefinition(
|
||||
set.getString("interaction_type"),
|
||||
set.getInt("item_id"),
|
||||
set.getString("wired_data"),
|
||||
set.getInt("room_id"),
|
||||
set.getString("room_name")
|
||||
);
|
||||
|
||||
if (definition == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
RoomOption roomOption = optionsByRoomId.computeIfAbsent(
|
||||
definition.getRoomId(),
|
||||
key -> new RoomOption(definition.getRoomId(), definition.getRoomName(), new ArrayList<>())
|
||||
);
|
||||
|
||||
roomOption.getVariables().add(definition);
|
||||
}
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
LOGGER.error("Failed to load shared variable reference options for room {}", room.getId(), e);
|
||||
}
|
||||
|
||||
List<RoomOption> result = new ArrayList<>(optionsByRoomId.values());
|
||||
|
||||
for (RoomOption option : result) {
|
||||
option.getVariables().sort(Comparator.comparing(SharedDefinitionOption::getName, String.CASE_INSENSITIVE_ORDER).thenComparingInt(SharedDefinitionOption::getItemId));
|
||||
}
|
||||
|
||||
result.sort(Comparator.comparing(RoomOption::getRoomName, String.CASE_INSENSITIVE_ORDER).thenComparingInt(RoomOption::getRoomId));
|
||||
return result;
|
||||
}
|
||||
|
||||
public static SharedUserAssignment getSharedUserAssignment(WiredExtraVariableReference reference, int userId) {
|
||||
if (reference == null || !reference.isUserReference() || userId <= 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String cacheKey = createUserCacheKey(reference.getSourceRoomId(), reference.getSourceVariableItemId(), userId);
|
||||
CachedUserAssignment cachedValue = USER_ASSIGNMENT_CACHE.get(cacheKey);
|
||||
|
||||
if (cachedValue != null) {
|
||||
return cachedValue.present ? cachedValue.toAssignment() : null;
|
||||
}
|
||||
|
||||
try (Connection connection = Emulator.getDatabase().getDataSource().getConnection();
|
||||
PreparedStatement statement = connection.prepareStatement("SELECT value, created_at, updated_at FROM room_user_wired_variables WHERE room_id = ? AND user_id = ? AND variable_item_id = ? LIMIT 1")) {
|
||||
statement.setInt(1, reference.getSourceRoomId());
|
||||
statement.setInt(2, userId);
|
||||
statement.setInt(3, reference.getSourceVariableItemId());
|
||||
|
||||
try (ResultSet set = statement.executeQuery()) {
|
||||
if (!set.next()) {
|
||||
USER_ASSIGNMENT_CACHE.put(cacheKey, CachedUserAssignment.missing());
|
||||
return null;
|
||||
}
|
||||
|
||||
Integer value = null;
|
||||
int rawValue = set.getInt("value");
|
||||
if (!set.wasNull()) {
|
||||
value = rawValue;
|
||||
}
|
||||
|
||||
int createdAt = normalizeTimestamp(set.getInt("created_at"), 0);
|
||||
SharedUserAssignment assignment = new SharedUserAssignment(
|
||||
value,
|
||||
createdAt,
|
||||
normalizeTimestamp(set.getInt("updated_at"), createdAt)
|
||||
);
|
||||
|
||||
USER_ASSIGNMENT_CACHE.put(cacheKey, CachedUserAssignment.present(assignment));
|
||||
return assignment;
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
LOGGER.error("Failed to load shared wired user variable {} for room {} user {}", reference.getSourceVariableItemId(), reference.getSourceRoomId(), userId, e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean assignSharedUserVariable(WiredExtraVariableReference reference, int userId, Integer value, boolean overrideExisting) {
|
||||
if (reference == null || !reference.isUserReference() || reference.isReadOnly() || userId <= 0 || !isSharedSourceStillAvailable(reference)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Integer normalizedValue = reference.hasValue() ? value : null;
|
||||
SharedUserAssignment existingAssignment = getSharedUserAssignment(reference, userId);
|
||||
|
||||
if (existingAssignment != null && !overrideExisting) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int now = Emulator.getIntUnixTimestamp();
|
||||
boolean overwritten = existingAssignment != null && overrideExisting;
|
||||
SharedUserAssignment nextAssignment = (existingAssignment == null || overwritten)
|
||||
? new SharedUserAssignment(normalizedValue, now, now)
|
||||
: new SharedUserAssignment(normalizedValue, existingAssignment.getCreatedAt(), Objects.equals(existingAssignment.getValue(), normalizedValue) ? existingAssignment.getUpdatedAt() : now);
|
||||
|
||||
if (!overwritten && existingAssignment != null && Objects.equals(existingAssignment.getValue(), normalizedValue)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
upsertSharedUserAssignment(reference.getSourceRoomId(), reference.getSourceVariableItemId(), userId, nextAssignment);
|
||||
USER_ASSIGNMENT_CACHE.put(createUserCacheKey(reference.getSourceRoomId(), reference.getSourceVariableItemId(), userId), CachedUserAssignment.present(nextAssignment));
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean updateSharedUserVariable(WiredExtraVariableReference reference, int userId, Integer value) {
|
||||
if (reference == null || !reference.isUserReference() || reference.isReadOnly() || userId <= 0 || !reference.hasValue() || !isSharedSourceStillAvailable(reference)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SharedUserAssignment existingAssignment = getSharedUserAssignment(reference, userId);
|
||||
if (existingAssignment == null || Objects.equals(existingAssignment.getValue(), value)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SharedUserAssignment nextAssignment = new SharedUserAssignment(value, existingAssignment.getCreatedAt(), Emulator.getIntUnixTimestamp());
|
||||
upsertSharedUserAssignment(reference.getSourceRoomId(), reference.getSourceVariableItemId(), userId, nextAssignment);
|
||||
USER_ASSIGNMENT_CACHE.put(createUserCacheKey(reference.getSourceRoomId(), reference.getSourceVariableItemId(), userId), CachedUserAssignment.present(nextAssignment));
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean removeSharedUserVariable(WiredExtraVariableReference reference, int userId) {
|
||||
if (reference == null || !reference.isUserReference() || reference.isReadOnly() || userId <= 0 || !isSharedSourceStillAvailable(reference)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SharedUserAssignment existingAssignment = getSharedUserAssignment(reference, userId);
|
||||
if (existingAssignment == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
deleteSharedUserAssignment(reference.getSourceRoomId(), reference.getSourceVariableItemId(), userId);
|
||||
USER_ASSIGNMENT_CACHE.put(createUserCacheKey(reference.getSourceRoomId(), reference.getSourceVariableItemId(), userId), CachedUserAssignment.missing());
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void cacheSharedUserAssignment(int sourceRoomId, int sourceVariableItemId, int userId, Integer value, int createdAt, int updatedAt) {
|
||||
USER_ASSIGNMENT_CACHE.put(createUserCacheKey(sourceRoomId, sourceVariableItemId, userId), CachedUserAssignment.present(new SharedUserAssignment(value, createdAt, updatedAt)));
|
||||
}
|
||||
|
||||
public static void clearSharedUserAssignment(int sourceRoomId, int sourceVariableItemId, int userId) {
|
||||
USER_ASSIGNMENT_CACHE.put(createUserCacheKey(sourceRoomId, sourceVariableItemId, userId), CachedUserAssignment.missing());
|
||||
}
|
||||
|
||||
public static void clearSharedUserDefinition(int sourceRoomId, int sourceVariableItemId) {
|
||||
String prefix = createDefinitionPrefix(sourceRoomId, sourceVariableItemId) + ":";
|
||||
USER_ASSIGNMENT_CACHE.entrySet().removeIf(entry -> entry.getKey().startsWith(prefix));
|
||||
}
|
||||
|
||||
public static SharedRoomAssignment getSharedRoomAssignment(WiredExtraVariableReference reference) {
|
||||
if (reference == null || !reference.isRoomReference()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String cacheKey = createRoomCacheKey(reference.getSourceRoomId(), reference.getSourceVariableItemId());
|
||||
CachedRoomAssignment cachedValue = ROOM_ASSIGNMENT_CACHE.get(cacheKey);
|
||||
|
||||
if (cachedValue != null) {
|
||||
return cachedValue.present ? cachedValue.toAssignment() : null;
|
||||
}
|
||||
|
||||
try (Connection connection = Emulator.getDatabase().getDataSource().getConnection();
|
||||
PreparedStatement statement = connection.prepareStatement("SELECT value, updated_at FROM room_wired_variables WHERE room_id = ? AND variable_item_id = ? LIMIT 1")) {
|
||||
statement.setInt(1, reference.getSourceRoomId());
|
||||
statement.setInt(2, reference.getSourceVariableItemId());
|
||||
|
||||
try (ResultSet set = statement.executeQuery()) {
|
||||
if (!set.next()) {
|
||||
ROOM_ASSIGNMENT_CACHE.put(cacheKey, CachedRoomAssignment.missing());
|
||||
return null;
|
||||
}
|
||||
|
||||
SharedRoomAssignment assignment = new SharedRoomAssignment(set.getInt("value"), normalizeTimestamp(set.getInt("updated_at"), 0));
|
||||
ROOM_ASSIGNMENT_CACHE.put(cacheKey, CachedRoomAssignment.present(assignment));
|
||||
return assignment;
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
LOGGER.error("Failed to load shared wired room variable {} for room {}", reference.getSourceVariableItemId(), reference.getSourceRoomId(), e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean updateSharedRoomVariable(WiredExtraVariableReference reference, int value) {
|
||||
if (reference == null || !reference.isRoomReference() || reference.isReadOnly() || !isSharedSourceStillAvailable(reference)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SharedRoomAssignment existingAssignment = getSharedRoomAssignment(reference);
|
||||
if (existingAssignment != null && existingAssignment.getValue() == value) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SharedRoomAssignment nextAssignment = new SharedRoomAssignment(value, Emulator.getIntUnixTimestamp());
|
||||
upsertSharedRoomAssignment(reference.getSourceRoomId(), reference.getSourceVariableItemId(), nextAssignment);
|
||||
ROOM_ASSIGNMENT_CACHE.put(createRoomCacheKey(reference.getSourceRoomId(), reference.getSourceVariableItemId()), CachedRoomAssignment.present(nextAssignment));
|
||||
return true;
|
||||
}
|
||||
|
||||
public static boolean removeSharedRoomVariable(WiredExtraVariableReference reference) {
|
||||
if (reference == null || !reference.isRoomReference() || reference.isReadOnly() || !isSharedSourceStillAvailable(reference)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SharedRoomAssignment existingAssignment = getSharedRoomAssignment(reference);
|
||||
if (existingAssignment == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
deleteSharedRoomAssignment(reference.getSourceRoomId(), reference.getSourceVariableItemId());
|
||||
ROOM_ASSIGNMENT_CACHE.put(createRoomCacheKey(reference.getSourceRoomId(), reference.getSourceVariableItemId()), CachedRoomAssignment.missing());
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void cacheSharedRoomAssignment(int sourceRoomId, int sourceVariableItemId, int value, int updatedAt) {
|
||||
ROOM_ASSIGNMENT_CACHE.put(createRoomCacheKey(sourceRoomId, sourceVariableItemId), CachedRoomAssignment.present(new SharedRoomAssignment(value, updatedAt)));
|
||||
}
|
||||
|
||||
public static void clearSharedRoomDefinition(int sourceRoomId, int sourceVariableItemId) {
|
||||
ROOM_ASSIGNMENT_CACHE.put(createRoomCacheKey(sourceRoomId, sourceVariableItemId), CachedRoomAssignment.missing());
|
||||
}
|
||||
|
||||
private static SharedDefinitionOption parseSharedDefinition(String interactionType, int itemId, String wiredData, int roomId, String roomName) {
|
||||
if ("wf_var_user".equals(interactionType)) {
|
||||
UserDefinitionData data = parseUserDefinitionData(wiredData);
|
||||
if (data == null || !isSharedAvailability(data.availability) || data.variableName.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new SharedDefinitionOption(roomId, roomName, itemId, data.variableName, TARGET_USER, data.hasValue);
|
||||
}
|
||||
|
||||
if ("wf_var_room".equals(interactionType)) {
|
||||
RoomDefinitionData data = parseRoomDefinitionData(wiredData);
|
||||
if (data == null || !isSharedAvailability(data.availability) || data.variableName.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new SharedDefinitionOption(roomId, roomName, itemId, data.variableName, TARGET_ROOM, true);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static UserDefinitionData parseUserDefinitionData(String wiredData) {
|
||||
if (wiredData == null || wiredData.isEmpty() || !wiredData.startsWith("{")) {
|
||||
return null;
|
||||
}
|
||||
|
||||
UserDefinitionData data = WiredManager.getGson().fromJson(wiredData, UserDefinitionData.class);
|
||||
if (data == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
data.variableName = WiredVariableNameValidator.normalizeLegacy(data.variableName);
|
||||
return data;
|
||||
}
|
||||
|
||||
private static RoomDefinitionData parseRoomDefinitionData(String wiredData) {
|
||||
if (wiredData == null || wiredData.isEmpty() || !wiredData.startsWith("{")) {
|
||||
return null;
|
||||
}
|
||||
|
||||
RoomDefinitionData data = WiredManager.getGson().fromJson(wiredData, RoomDefinitionData.class);
|
||||
if (data == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
data.variableName = WiredVariableNameValidator.normalizeLegacy(data.variableName);
|
||||
return data;
|
||||
}
|
||||
|
||||
private static boolean isSharedSourceStillAvailable(WiredExtraVariableReference reference) {
|
||||
if (reference == null || reference.getSourceRoomId() <= 0 || reference.getSourceVariableItemId() <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try (Connection connection = Emulator.getDatabase().getDataSource().getConnection();
|
||||
PreparedStatement statement = connection.prepareStatement(
|
||||
"SELECT items.wired_data, items_base.interaction_type " +
|
||||
"FROM items INNER JOIN items_base ON items.item_id = items_base.id " +
|
||||
"WHERE items.id = ? AND items.room_id = ? LIMIT 1")) {
|
||||
statement.setInt(1, reference.getSourceVariableItemId());
|
||||
statement.setInt(2, reference.getSourceRoomId());
|
||||
|
||||
try (ResultSet set = statement.executeQuery()) {
|
||||
if (!set.next()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
SharedDefinitionOption definition = parseSharedDefinition(
|
||||
set.getString("interaction_type"),
|
||||
reference.getSourceVariableItemId(),
|
||||
set.getString("wired_data"),
|
||||
reference.getSourceRoomId(),
|
||||
""
|
||||
);
|
||||
|
||||
return definition != null && definition.getTargetType() == reference.getSourceTargetType();
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
LOGGER.error("Failed to validate shared wired variable source {} in room {}", reference.getSourceVariableItemId(), reference.getSourceRoomId(), e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static void upsertSharedUserAssignment(int sourceRoomId, int sourceVariableItemId, int userId, SharedUserAssignment assignment) {
|
||||
try (Connection connection = Emulator.getDatabase().getDataSource().getConnection();
|
||||
PreparedStatement statement = connection.prepareStatement("INSERT INTO room_user_wired_variables (room_id, user_id, variable_item_id, value, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE value = VALUES(value), updated_at = VALUES(updated_at)")) {
|
||||
statement.setInt(1, sourceRoomId);
|
||||
statement.setInt(2, userId);
|
||||
statement.setInt(3, sourceVariableItemId);
|
||||
|
||||
if (assignment.getValue() == null) {
|
||||
statement.setNull(4, java.sql.Types.INTEGER);
|
||||
} else {
|
||||
statement.setInt(4, assignment.getValue());
|
||||
}
|
||||
|
||||
statement.setInt(5, assignment.getCreatedAt());
|
||||
statement.setInt(6, assignment.getUpdatedAt());
|
||||
statement.executeUpdate();
|
||||
} catch (SQLException e) {
|
||||
LOGGER.error("Failed to store shared wired user variable {} for room {} user {}", sourceVariableItemId, sourceRoomId, userId, e);
|
||||
}
|
||||
}
|
||||
|
||||
private static void deleteSharedUserAssignment(int sourceRoomId, int sourceVariableItemId, int userId) {
|
||||
try (Connection connection = Emulator.getDatabase().getDataSource().getConnection();
|
||||
PreparedStatement statement = connection.prepareStatement("DELETE FROM room_user_wired_variables WHERE room_id = ? AND user_id = ? AND variable_item_id = ?")) {
|
||||
statement.setInt(1, sourceRoomId);
|
||||
statement.setInt(2, userId);
|
||||
statement.setInt(3, sourceVariableItemId);
|
||||
statement.executeUpdate();
|
||||
} catch (SQLException e) {
|
||||
LOGGER.error("Failed to delete shared wired user variable {} for room {} user {}", sourceVariableItemId, sourceRoomId, userId, e);
|
||||
}
|
||||
}
|
||||
|
||||
private static void upsertSharedRoomAssignment(int sourceRoomId, int sourceVariableItemId, SharedRoomAssignment assignment) {
|
||||
try (Connection connection = Emulator.getDatabase().getDataSource().getConnection();
|
||||
PreparedStatement statement = connection.prepareStatement("INSERT INTO room_wired_variables (room_id, variable_item_id, value, created_at, updated_at) VALUES (?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE value = VALUES(value), updated_at = VALUES(updated_at)")) {
|
||||
statement.setInt(1, sourceRoomId);
|
||||
statement.setInt(2, sourceVariableItemId);
|
||||
statement.setInt(3, assignment.getValue());
|
||||
statement.setInt(4, 0);
|
||||
statement.setInt(5, assignment.getUpdatedAt());
|
||||
statement.executeUpdate();
|
||||
} catch (SQLException e) {
|
||||
LOGGER.error("Failed to store shared wired room variable {} for room {}", sourceVariableItemId, sourceRoomId, e);
|
||||
}
|
||||
}
|
||||
|
||||
private static void deleteSharedRoomAssignment(int sourceRoomId, int sourceVariableItemId) {
|
||||
try (Connection connection = Emulator.getDatabase().getDataSource().getConnection();
|
||||
PreparedStatement statement = connection.prepareStatement("DELETE FROM room_wired_variables WHERE room_id = ? AND variable_item_id = ?")) {
|
||||
statement.setInt(1, sourceRoomId);
|
||||
statement.setInt(2, sourceVariableItemId);
|
||||
statement.executeUpdate();
|
||||
} catch (SQLException e) {
|
||||
LOGGER.error("Failed to delete shared wired room variable {} for room {}", sourceVariableItemId, sourceRoomId, e);
|
||||
}
|
||||
}
|
||||
|
||||
private static String createDefinitionPrefix(int sourceRoomId, int sourceVariableItemId) {
|
||||
return sourceRoomId + ":" + sourceVariableItemId;
|
||||
}
|
||||
|
||||
private static String createUserCacheKey(int sourceRoomId, int sourceVariableItemId, int userId) {
|
||||
return createDefinitionPrefix(sourceRoomId, sourceVariableItemId) + ":" + userId;
|
||||
}
|
||||
|
||||
private static String createRoomCacheKey(int sourceRoomId, int sourceVariableItemId) {
|
||||
return createDefinitionPrefix(sourceRoomId, sourceVariableItemId);
|
||||
}
|
||||
|
||||
private static int normalizeTimestamp(int value, int fallback) {
|
||||
if (value > 0) {
|
||||
return value;
|
||||
}
|
||||
|
||||
if (fallback > 0) {
|
||||
return fallback;
|
||||
}
|
||||
|
||||
return Emulator.getIntUnixTimestamp();
|
||||
}
|
||||
|
||||
public static class RoomOption {
|
||||
private final int roomId;
|
||||
private final String roomName;
|
||||
private final List<SharedDefinitionOption> variables;
|
||||
|
||||
public RoomOption(int roomId, String roomName, List<SharedDefinitionOption> variables) {
|
||||
this.roomId = roomId;
|
||||
this.roomName = roomName;
|
||||
this.variables = variables;
|
||||
}
|
||||
|
||||
public int getRoomId() {
|
||||
return this.roomId;
|
||||
}
|
||||
|
||||
public String getRoomName() {
|
||||
return this.roomName;
|
||||
}
|
||||
|
||||
public List<SharedDefinitionOption> getVariables() {
|
||||
return this.variables;
|
||||
}
|
||||
}
|
||||
|
||||
public static class SharedDefinitionOption {
|
||||
private final int roomId;
|
||||
private final String roomName;
|
||||
private final int itemId;
|
||||
private final String name;
|
||||
private final int targetType;
|
||||
private final boolean hasValue;
|
||||
|
||||
public SharedDefinitionOption(int roomId, String roomName, int itemId, String name, int targetType, boolean hasValue) {
|
||||
this.roomId = roomId;
|
||||
this.roomName = roomName;
|
||||
this.itemId = itemId;
|
||||
this.name = name;
|
||||
this.targetType = targetType;
|
||||
this.hasValue = hasValue;
|
||||
}
|
||||
|
||||
public int getRoomId() {
|
||||
return this.roomId;
|
||||
}
|
||||
|
||||
public String getRoomName() {
|
||||
return this.roomName;
|
||||
}
|
||||
|
||||
public int getItemId() {
|
||||
return this.itemId;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public int getTargetType() {
|
||||
return this.targetType;
|
||||
}
|
||||
|
||||
public boolean hasValue() {
|
||||
return this.hasValue;
|
||||
}
|
||||
}
|
||||
|
||||
public static class SharedUserAssignment {
|
||||
private final Integer value;
|
||||
private final int createdAt;
|
||||
private final int updatedAt;
|
||||
|
||||
public SharedUserAssignment(Integer value, int createdAt, int updatedAt) {
|
||||
this.value = value;
|
||||
this.createdAt = createdAt;
|
||||
this.updatedAt = updatedAt;
|
||||
}
|
||||
|
||||
public Integer getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
public int getCreatedAt() {
|
||||
return this.createdAt;
|
||||
}
|
||||
|
||||
public int getUpdatedAt() {
|
||||
return this.updatedAt;
|
||||
}
|
||||
}
|
||||
|
||||
public static class SharedRoomAssignment {
|
||||
private final int value;
|
||||
private final int updatedAt;
|
||||
|
||||
public SharedRoomAssignment(int value, int updatedAt) {
|
||||
this.value = value;
|
||||
this.updatedAt = updatedAt;
|
||||
}
|
||||
|
||||
public int getValue() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
public int getUpdatedAt() {
|
||||
return this.updatedAt;
|
||||
}
|
||||
}
|
||||
|
||||
private static class CachedUserAssignment {
|
||||
private final boolean present;
|
||||
private final SharedUserAssignment assignment;
|
||||
|
||||
private CachedUserAssignment(boolean present, SharedUserAssignment assignment) {
|
||||
this.present = present;
|
||||
this.assignment = assignment;
|
||||
}
|
||||
|
||||
private static CachedUserAssignment present(SharedUserAssignment assignment) {
|
||||
return new CachedUserAssignment(true, assignment);
|
||||
}
|
||||
|
||||
private static CachedUserAssignment missing() {
|
||||
return new CachedUserAssignment(false, null);
|
||||
}
|
||||
|
||||
private SharedUserAssignment toAssignment() {
|
||||
return this.assignment;
|
||||
}
|
||||
}
|
||||
|
||||
private static class CachedRoomAssignment {
|
||||
private final boolean present;
|
||||
private final SharedRoomAssignment assignment;
|
||||
|
||||
private CachedRoomAssignment(boolean present, SharedRoomAssignment assignment) {
|
||||
this.present = present;
|
||||
this.assignment = assignment;
|
||||
}
|
||||
|
||||
private static CachedRoomAssignment present(SharedRoomAssignment assignment) {
|
||||
return new CachedRoomAssignment(true, assignment);
|
||||
}
|
||||
|
||||
private static CachedRoomAssignment missing() {
|
||||
return new CachedRoomAssignment(false, null);
|
||||
}
|
||||
|
||||
private SharedRoomAssignment toAssignment() {
|
||||
return this.assignment;
|
||||
}
|
||||
}
|
||||
|
||||
private static class UserDefinitionData {
|
||||
String variableName;
|
||||
boolean hasValue;
|
||||
int availability;
|
||||
}
|
||||
|
||||
private static class RoomDefinitionData {
|
||||
String variableName;
|
||||
int availability;
|
||||
}
|
||||
}
|
||||
+17
-8
@@ -11,6 +11,7 @@ import com.eu.habbo.habbohotel.users.HabboItem;
|
||||
import com.eu.habbo.habbohotel.wired.WiredEffectType;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredContext;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredManager;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredSourceUtil;
|
||||
import com.eu.habbo.messages.ServerMessage;
|
||||
import com.eu.habbo.messages.incoming.wired.WiredSaveException;
|
||||
|
||||
@@ -51,7 +52,6 @@ public class WiredEffectFurniByType extends InteractionWiredEffect {
|
||||
boolean includeWiredItems = this.includeWiredTargets(ctx);
|
||||
|
||||
List<HabboItem> sourceFurni = resolveSourceFurni(ctx, room);
|
||||
if (sourceFurni.isEmpty()) return;
|
||||
|
||||
Set<String> matchKeys = new LinkedHashSet<>();
|
||||
for (HabboItem src : sourceFurni) {
|
||||
@@ -85,12 +85,10 @@ public class WiredEffectFurniByType extends InteractionWiredEffect {
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
case SOURCE_FURNI_SIGNAL: {
|
||||
return new ArrayList<>(ctx.targets().items());
|
||||
return WiredSourceUtil.resolveItemsRaw(ctx, WiredSourceUtil.SOURCE_SIGNAL, null);
|
||||
}
|
||||
case SOURCE_FURNI_TRIGGER: {
|
||||
return ctx.sourceItem()
|
||||
.map(Collections::singletonList)
|
||||
.orElse(Collections.emptyList());
|
||||
return WiredSourceUtil.resolveItemsRaw(ctx, WiredSourceUtil.SOURCE_TRIGGER, null);
|
||||
}
|
||||
default:
|
||||
return Collections.emptyList();
|
||||
@@ -104,7 +102,7 @@ public class WiredEffectFurniByType extends InteractionWiredEffect {
|
||||
throw new WiredSaveException("wf_slc_furni_bytype: intParams must have at least 4 elements");
|
||||
}
|
||||
|
||||
this.sourceType = SOURCE_FURNI_PICKED;
|
||||
this.sourceType = normalizeSourceType(params[0]);
|
||||
this.matchState = params.length > 1 && params[1] == 1;
|
||||
this.filterExisting = params.length > 2 && params[2] == 1;
|
||||
this.invert = params.length > 3 && params[3] == 1;
|
||||
@@ -138,7 +136,7 @@ public class WiredEffectFurniByType extends InteractionWiredEffect {
|
||||
message.appendString("");
|
||||
|
||||
message.appendInt(4);
|
||||
message.appendInt(SOURCE_FURNI_PICKED);
|
||||
message.appendInt(this.sourceType);
|
||||
message.appendInt(matchState ? 1 : 0);
|
||||
message.appendInt(filterExisting ? 1 : 0);
|
||||
message.appendInt(invert ? 1 : 0);
|
||||
@@ -168,7 +166,7 @@ public class WiredEffectFurniByType extends InteractionWiredEffect {
|
||||
String wiredData = set.getString("wired_data");
|
||||
if (wiredData != null && wiredData.startsWith("{")) {
|
||||
JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class);
|
||||
this.sourceType = data.sourceType;
|
||||
this.sourceType = normalizeSourceType(data.sourceType);
|
||||
this.matchState = data.matchState;
|
||||
this.filterExisting = data.filterExisting;
|
||||
this.invert = data.invert;
|
||||
@@ -190,6 +188,17 @@ public class WiredEffectFurniByType extends InteractionWiredEffect {
|
||||
@Override
|
||||
public boolean execute(RoomUnit roomUnit, Room room, Object[] stuff) { return false; }
|
||||
|
||||
private int normalizeSourceType(int value) {
|
||||
switch (value) {
|
||||
case SOURCE_FURNI_SIGNAL:
|
||||
case SOURCE_FURNI_TRIGGER:
|
||||
case SOURCE_FURNI_PICKED:
|
||||
return value;
|
||||
default:
|
||||
return SOURCE_FURNI_PICKED;
|
||||
}
|
||||
}
|
||||
|
||||
static class JsonData {
|
||||
int sourceType;
|
||||
boolean matchState;
|
||||
|
||||
+48
-18
@@ -101,24 +101,46 @@ public class WiredEffectFurniNeighborhood extends InteractionWiredEffect {
|
||||
}
|
||||
|
||||
private List<int[]> resolveSourcePositions(WiredContext ctx, Room room) {
|
||||
|
||||
if (isUserGroup(sourceType)) {
|
||||
// Prefer the event tile for user-based sources because during walk-on/walk-off
|
||||
// events the user's position (getX/getY) hasn't been updated yet (stale position).
|
||||
// The event tile correctly represents where the triggering action occurred.
|
||||
if (ctx.tile().isPresent()) {
|
||||
return Collections.singletonList(new int[]{ ctx.tile().get().x, ctx.tile().get().y });
|
||||
}
|
||||
List<int[]> positions = ctx.targets().users().stream()
|
||||
.map(u -> new int[]{ u.getX(), u.getY() })
|
||||
.collect(Collectors.toList());
|
||||
if (positions.isEmpty()) {
|
||||
ctx.actor().ifPresent(a -> positions.add(new int[]{ a.getX(), a.getY() }));
|
||||
}
|
||||
return positions;
|
||||
}
|
||||
|
||||
switch (sourceType) {
|
||||
case SOURCE_USER_TRIGGER: {
|
||||
if (ctx.tile().isPresent()) {
|
||||
return Collections.singletonList(new int[]{ ctx.tile().get().x, ctx.tile().get().y });
|
||||
}
|
||||
|
||||
return ctx.actor()
|
||||
.map(actor -> Collections.singletonList(new int[]{ actor.getX(), actor.getY() }))
|
||||
.orElse(Collections.emptyList());
|
||||
}
|
||||
case SOURCE_USER_SIGNAL: {
|
||||
List<int[]> positions = ctx.targets().users().stream()
|
||||
.map(user -> new int[]{ user.getX(), user.getY() })
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (!positions.isEmpty()) {
|
||||
return positions;
|
||||
}
|
||||
|
||||
return ctx.actor()
|
||||
.map(actor -> Collections.singletonList(new int[]{ actor.getX(), actor.getY() }))
|
||||
.orElse(Collections.emptyList());
|
||||
}
|
||||
case SOURCE_USER_CLICKED: {
|
||||
if (ctx.event().getTargetUnit().isPresent()) {
|
||||
RoomUnit targetUnit = ctx.event().getTargetUnit().get();
|
||||
|
||||
return Collections.singletonList(new int[]{ targetUnit.getX(), targetUnit.getY() });
|
||||
}
|
||||
|
||||
List<int[]> positions = ctx.targets().users().stream()
|
||||
.map(user -> new int[]{ user.getX(), user.getY() })
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (!positions.isEmpty()) {
|
||||
return positions;
|
||||
}
|
||||
|
||||
return Collections.emptyList();
|
||||
}
|
||||
case SOURCE_FURNI_TRIGGER: {
|
||||
return ctx.sourceItem()
|
||||
.map(i -> Collections.singletonList(new int[]{ i.getX(), i.getY() }))
|
||||
@@ -132,9 +154,17 @@ public class WiredEffectFurniNeighborhood extends InteractionWiredEffect {
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
case SOURCE_FURNI_SIGNAL: {
|
||||
return ctx.targets().items().stream()
|
||||
List<int[]> positions = ctx.targets().items().stream()
|
||||
.map(i -> new int[]{ i.getX(), i.getY() })
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (!positions.isEmpty()) {
|
||||
return positions;
|
||||
}
|
||||
|
||||
return ctx.sourceItem()
|
||||
.map(item -> Collections.singletonList(new int[]{ item.getX(), item.getY() }))
|
||||
.orElse(Collections.emptyList());
|
||||
}
|
||||
default:
|
||||
return Collections.emptyList();
|
||||
|
||||
+4
@@ -92,6 +92,10 @@ public class WiredEffectFurniOnFurni extends InteractionWiredEffect {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (count > 0 && this.furniSource == WiredSourceUtil.SOURCE_TRIGGER) {
|
||||
this.furniSource = WiredSourceUtil.SOURCE_SELECTED;
|
||||
}
|
||||
|
||||
this.items.clear();
|
||||
|
||||
if (this.furniSource == WiredSourceUtil.SOURCE_SELECTED) {
|
||||
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
package com.eu.habbo.habbohotel.items.interactions.wired.selector;
|
||||
|
||||
import com.eu.habbo.habbohotel.items.Item;
|
||||
import com.eu.habbo.habbohotel.wired.WiredEffectType;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
public class WiredEffectFurniWithVariable extends WiredEffectVariableSelectorBase {
|
||||
public static final WiredEffectType type = WiredEffectType.FURNI_WITH_VAR_SELECTOR;
|
||||
|
||||
public WiredEffectFurniWithVariable(ResultSet set, Item baseItem) throws SQLException {
|
||||
super(set, baseItem);
|
||||
}
|
||||
|
||||
public WiredEffectFurniWithVariable(int id, int userId, Item item, String extradata, int limitedStack, int limitedSells) {
|
||||
super(id, userId, item, extradata, limitedStack, limitedSells);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getVariableTargetType() {
|
||||
return TARGET_FURNI;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WiredEffectType getType() {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
+48
-18
@@ -111,24 +111,46 @@ public class WiredEffectUsersNeighborhood extends InteractionWiredEffect {
|
||||
}
|
||||
|
||||
private List<int[]> resolveSourcePositions(WiredContext ctx, Room room) {
|
||||
|
||||
if (isUserGroup(sourceType)) {
|
||||
// Prefer the event tile for user-based sources because during walk-on/walk-off
|
||||
// events the user's position (getX/getY) hasn't been updated yet (stale position).
|
||||
// The event tile correctly represents where the triggering action occurred.
|
||||
if (ctx.tile().isPresent()) {
|
||||
return Collections.singletonList(new int[]{ ctx.tile().get().x, ctx.tile().get().y });
|
||||
}
|
||||
List<int[]> positions = ctx.targets().users().stream()
|
||||
.map(u -> new int[]{ u.getX(), u.getY() })
|
||||
.collect(Collectors.toList());
|
||||
if (positions.isEmpty()) {
|
||||
ctx.actor().ifPresent(a -> positions.add(new int[]{ a.getX(), a.getY() }));
|
||||
}
|
||||
return positions;
|
||||
}
|
||||
|
||||
switch (sourceType) {
|
||||
case SOURCE_USER_TRIGGER: {
|
||||
if (ctx.tile().isPresent()) {
|
||||
return Collections.singletonList(new int[]{ ctx.tile().get().x, ctx.tile().get().y });
|
||||
}
|
||||
|
||||
return ctx.actor()
|
||||
.map(actor -> Collections.singletonList(new int[]{ actor.getX(), actor.getY() }))
|
||||
.orElse(Collections.emptyList());
|
||||
}
|
||||
case SOURCE_USER_SIGNAL: {
|
||||
List<int[]> positions = ctx.targets().users().stream()
|
||||
.map(user -> new int[]{ user.getX(), user.getY() })
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (!positions.isEmpty()) {
|
||||
return positions;
|
||||
}
|
||||
|
||||
return ctx.actor()
|
||||
.map(actor -> Collections.singletonList(new int[]{ actor.getX(), actor.getY() }))
|
||||
.orElse(Collections.emptyList());
|
||||
}
|
||||
case SOURCE_USER_CLICKED: {
|
||||
if (ctx.event().getTargetUnit().isPresent()) {
|
||||
RoomUnit targetUnit = ctx.event().getTargetUnit().get();
|
||||
|
||||
return Collections.singletonList(new int[]{ targetUnit.getX(), targetUnit.getY() });
|
||||
}
|
||||
|
||||
List<int[]> positions = ctx.targets().users().stream()
|
||||
.map(user -> new int[]{ user.getX(), user.getY() })
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (!positions.isEmpty()) {
|
||||
return positions;
|
||||
}
|
||||
|
||||
return Collections.emptyList();
|
||||
}
|
||||
case SOURCE_FURNI_TRIGGER: {
|
||||
return ctx.sourceItem()
|
||||
.map(i -> Collections.singletonList(new int[]{ i.getX(), i.getY() }))
|
||||
@@ -142,9 +164,17 @@ public class WiredEffectUsersNeighborhood extends InteractionWiredEffect {
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
case SOURCE_FURNI_SIGNAL: {
|
||||
return ctx.targets().items().stream()
|
||||
List<int[]> positions = ctx.targets().items().stream()
|
||||
.map(i -> new int[]{ i.getX(), i.getY() })
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (!positions.isEmpty()) {
|
||||
return positions;
|
||||
}
|
||||
|
||||
return ctx.sourceItem()
|
||||
.map(item -> Collections.singletonList(new int[]{ item.getX(), item.getY() }))
|
||||
.orElse(Collections.emptyList());
|
||||
}
|
||||
default:
|
||||
return Collections.emptyList();
|
||||
|
||||
+4
@@ -79,6 +79,10 @@ public class WiredEffectUsersOnFurni extends InteractionWiredEffect {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (count > 0 && this.furniSource == WiredSourceUtil.SOURCE_TRIGGER) {
|
||||
this.furniSource = WiredSourceUtil.SOURCE_SELECTED;
|
||||
}
|
||||
|
||||
this.items.clear();
|
||||
|
||||
if (this.furniSource == WiredSourceUtil.SOURCE_SELECTED) {
|
||||
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
package com.eu.habbo.habbohotel.items.interactions.wired.selector;
|
||||
|
||||
import com.eu.habbo.habbohotel.items.Item;
|
||||
import com.eu.habbo.habbohotel.wired.WiredEffectType;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
public class WiredEffectUsersWithVariable extends WiredEffectVariableSelectorBase {
|
||||
public static final WiredEffectType type = WiredEffectType.USERS_WITH_VAR_SELECTOR;
|
||||
|
||||
public WiredEffectUsersWithVariable(ResultSet set, Item baseItem) throws SQLException {
|
||||
super(set, baseItem);
|
||||
}
|
||||
|
||||
public WiredEffectUsersWithVariable(int id, int userId, Item item, String extradata, int limitedStack, int limitedSells) {
|
||||
super(id, userId, item, extradata, limitedStack, limitedSells);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getVariableTargetType() {
|
||||
return TARGET_USER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WiredEffectType getType() {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
+862
@@ -0,0 +1,862 @@
|
||||
package com.eu.habbo.habbohotel.items.interactions.wired.selector;
|
||||
|
||||
import com.eu.habbo.Emulator;
|
||||
import com.eu.habbo.habbohotel.bots.Bot;
|
||||
import com.eu.habbo.habbohotel.gameclients.GameClient;
|
||||
import com.eu.habbo.habbohotel.games.Game;
|
||||
import com.eu.habbo.habbohotel.games.GamePlayer;
|
||||
import com.eu.habbo.habbohotel.games.GameTeam;
|
||||
import com.eu.habbo.habbohotel.games.GameTeamColors;
|
||||
import com.eu.habbo.habbohotel.games.battlebanzai.BattleBanzaiGame;
|
||||
import com.eu.habbo.habbohotel.games.freeze.FreezeGame;
|
||||
import com.eu.habbo.habbohotel.games.wired.WiredGame;
|
||||
import com.eu.habbo.habbohotel.items.FurnitureType;
|
||||
import com.eu.habbo.habbohotel.items.Item;
|
||||
import com.eu.habbo.habbohotel.items.interactions.InteractionWired;
|
||||
import com.eu.habbo.habbohotel.items.interactions.InteractionWiredEffect;
|
||||
import com.eu.habbo.habbohotel.items.interactions.wired.WiredSettings;
|
||||
import com.eu.habbo.habbohotel.pets.Pet;
|
||||
import com.eu.habbo.habbohotel.rooms.Room;
|
||||
import com.eu.habbo.habbohotel.rooms.RoomRightLevels;
|
||||
import com.eu.habbo.habbohotel.rooms.RoomUnit;
|
||||
import com.eu.habbo.habbohotel.rooms.RoomUnitStatus;
|
||||
import com.eu.habbo.habbohotel.rooms.WiredVariableDefinitionInfo;
|
||||
import com.eu.habbo.habbohotel.users.DanceType;
|
||||
import com.eu.habbo.habbohotel.users.Habbo;
|
||||
import com.eu.habbo.habbohotel.users.HabboItem;
|
||||
import com.eu.habbo.habbohotel.wired.WiredEffectType;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredContext;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredContextVariableSupport;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredFreezeUtil;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredInternalVariableSupport;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredManager;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredSourceUtil;
|
||||
import com.eu.habbo.messages.ServerMessage;
|
||||
import com.eu.habbo.messages.incoming.wired.WiredSaveException;
|
||||
import com.eu.habbo.util.HotelDateTimeUtil;
|
||||
import gnu.trove.set.hash.THashSet;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.time.temporal.WeekFields;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
public abstract class WiredEffectVariableSelectorBase extends InteractionWiredEffect {
|
||||
protected static final int TARGET_USER = 0;
|
||||
protected static final int TARGET_FURNI = 1;
|
||||
protected static final int TARGET_CONTEXT = 2;
|
||||
protected static final int TARGET_ROOM = 3;
|
||||
|
||||
protected static final int REFERENCE_CONSTANT = 0;
|
||||
protected static final int REFERENCE_VARIABLE = 1;
|
||||
|
||||
protected static final int SOURCE_SECONDARY_SELECTED = 101;
|
||||
|
||||
protected static final int COMPARISON_GREATER_THAN = 0;
|
||||
protected static final int COMPARISON_GREATER_THAN_OR_EQUAL = 1;
|
||||
protected static final int COMPARISON_EQUAL = 2;
|
||||
protected static final int COMPARISON_LESS_THAN_OR_EQUAL = 3;
|
||||
protected static final int COMPARISON_LESS_THAN = 4;
|
||||
protected static final int COMPARISON_NOT_EQUAL = 5;
|
||||
|
||||
private static final String CUSTOM_TOKEN_PREFIX = "custom:";
|
||||
private static final String INTERNAL_TOKEN_PREFIX = "internal:";
|
||||
private static final String DELIM = "\t";
|
||||
|
||||
protected boolean selectByValue = false;
|
||||
protected int comparison = COMPARISON_EQUAL;
|
||||
protected int referenceMode = REFERENCE_CONSTANT;
|
||||
protected int referenceConstantValue = 0;
|
||||
protected int referenceTargetType = TARGET_USER;
|
||||
protected int referenceUserSource = WiredSourceUtil.SOURCE_TRIGGER;
|
||||
protected int referenceFurniSource = WiredSourceUtil.SOURCE_TRIGGER;
|
||||
protected boolean filterExisting = false;
|
||||
protected boolean invert = false;
|
||||
protected String variableToken = "";
|
||||
protected int variableItemId = 0;
|
||||
protected String referenceVariableToken = "";
|
||||
protected int referenceVariableItemId = 0;
|
||||
protected final THashSet<HabboItem> referenceSelectedItems = new THashSet<>();
|
||||
|
||||
protected WiredEffectVariableSelectorBase(ResultSet set, Item baseItem) throws SQLException {
|
||||
super(set, baseItem);
|
||||
}
|
||||
|
||||
protected WiredEffectVariableSelectorBase(int id, int userId, Item item, String extradata, int limitedStack, int limitedSells) {
|
||||
super(id, userId, item, extradata, limitedStack, limitedSells);
|
||||
}
|
||||
|
||||
protected abstract int getVariableTargetType();
|
||||
|
||||
@Override
|
||||
public void execute(WiredContext ctx) {
|
||||
Room room = ctx.room();
|
||||
|
||||
if (room == null || this.variableToken == null || this.variableToken.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.getVariableTargetType() == TARGET_FURNI) {
|
||||
LinkedHashSet<HabboItem> matchedItems = new LinkedHashSet<>();
|
||||
|
||||
for (HabboItem item : this.getSelectableFloorItems(room, ctx)) {
|
||||
if (item == null) continue;
|
||||
if (!this.matchesFurni(room, item, ctx)) continue;
|
||||
|
||||
matchedItems.add(item);
|
||||
}
|
||||
|
||||
LinkedHashSet<HabboItem> result = this.applySelectorModifiers(matchedItems, this.getSelectableFloorItems(room, ctx), ctx.targets().items(), this.filterExisting, this.invert);
|
||||
ctx.targets().setItems(result);
|
||||
return;
|
||||
}
|
||||
|
||||
LinkedHashSet<RoomUnit> matchedUsers = new LinkedHashSet<>();
|
||||
|
||||
for (RoomUnit roomUnit : room.getRoomUnits()) {
|
||||
if (roomUnit == null) continue;
|
||||
if (!this.matchesUser(room, roomUnit, ctx)) continue;
|
||||
|
||||
matchedUsers.add(roomUnit);
|
||||
}
|
||||
|
||||
LinkedHashSet<RoomUnit> result = this.applySelectorModifiers(matchedUsers, room.getRoomUnits(), ctx.targets().users(), this.filterExisting, this.invert);
|
||||
ctx.targets().setUsers(result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean saveData(WiredSettings settings, GameClient gameClient) throws WiredSaveException {
|
||||
Room room = this.getRoom();
|
||||
if (room == null) return false;
|
||||
|
||||
int[] params = settings.getIntParams();
|
||||
String[] stringParts = parseStringData(settings.getStringParam());
|
||||
|
||||
boolean nextSelectByValue = param(params, 0, 0) == 1;
|
||||
int nextComparison = normalizeComparison(param(params, 1, COMPARISON_EQUAL));
|
||||
int nextReferenceMode = normalizeReferenceMode(param(params, 2, REFERENCE_CONSTANT));
|
||||
int nextReferenceConstantValue = param(params, 3, 0);
|
||||
int nextReferenceTargetType = normalizeReferenceTargetType(param(params, 4, TARGET_USER));
|
||||
int nextReferenceUserSource = normalizeUserSource(param(params, 5, WiredSourceUtil.SOURCE_TRIGGER));
|
||||
int nextReferenceFurniSource = normalizeReferenceFurniSource(param(params, 6, WiredSourceUtil.SOURCE_TRIGGER));
|
||||
boolean nextFilterExisting = param(params, 7, 0) == 1;
|
||||
boolean nextInvert = param(params, 8, 0) == 1;
|
||||
String nextVariableToken = normalizeVariableToken((stringParts.length > 0) ? stringParts[0] : settings.getStringParam());
|
||||
String nextReferenceVariableToken = normalizeVariableToken((stringParts.length > 1) ? stringParts[1] : "");
|
||||
|
||||
if (!this.isValidMainVariable(room, nextVariableToken, nextSelectByValue)) return false;
|
||||
if (nextSelectByValue && nextReferenceMode == REFERENCE_VARIABLE && !this.isValidReference(room, nextReferenceTargetType, nextReferenceVariableToken)) return false;
|
||||
|
||||
List<HabboItem> nextReferenceItems = new ArrayList<>();
|
||||
|
||||
if (nextSelectByValue && nextReferenceMode == REFERENCE_VARIABLE && nextReferenceTargetType == TARGET_FURNI && nextReferenceFurniSource == SOURCE_SECONDARY_SELECTED) {
|
||||
int[] furniIds = settings.getFurniIds();
|
||||
if (furniIds.length > Emulator.getConfig().getInt("hotel.wired.furni.selection.count")) return false;
|
||||
|
||||
for (int furniId : furniIds) {
|
||||
HabboItem item = room.getHabboItem(furniId);
|
||||
if (item != null) nextReferenceItems.add(item);
|
||||
}
|
||||
}
|
||||
|
||||
this.referenceSelectedItems.clear();
|
||||
this.referenceSelectedItems.addAll(nextReferenceItems);
|
||||
this.selectByValue = nextSelectByValue;
|
||||
this.comparison = nextComparison;
|
||||
this.referenceMode = nextReferenceMode;
|
||||
this.referenceConstantValue = nextReferenceConstantValue;
|
||||
this.referenceTargetType = nextReferenceTargetType;
|
||||
this.referenceUserSource = nextReferenceUserSource;
|
||||
this.referenceFurniSource = nextReferenceFurniSource;
|
||||
this.filterExisting = nextFilterExisting;
|
||||
this.invert = nextInvert;
|
||||
this.setVariableToken(nextVariableToken);
|
||||
this.setReferenceVariableToken(nextReferenceVariableToken);
|
||||
this.setDelay(settings.getDelay());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSelector() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getWiredData() {
|
||||
this.refreshReferenceItems();
|
||||
|
||||
return WiredManager.getGson().toJson(new JsonData(
|
||||
this.selectByValue,
|
||||
this.comparison,
|
||||
this.referenceMode,
|
||||
this.referenceConstantValue,
|
||||
this.referenceTargetType,
|
||||
this.referenceUserSource,
|
||||
this.referenceFurniSource,
|
||||
this.filterExisting,
|
||||
this.invert,
|
||||
this.variableToken,
|
||||
this.variableItemId,
|
||||
this.referenceVariableToken,
|
||||
this.referenceVariableItemId,
|
||||
this.toIds(this.referenceSelectedItems),
|
||||
this.getDelay()
|
||||
));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadWiredData(ResultSet set, Room room) throws SQLException {
|
||||
this.onPickUp();
|
||||
|
||||
String wiredData = set.getString("wired_data");
|
||||
if (wiredData == null || wiredData.isEmpty() || !wiredData.startsWith("{")) return;
|
||||
|
||||
JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class);
|
||||
if (data == null) return;
|
||||
|
||||
this.selectByValue = data.selectByValue;
|
||||
this.comparison = normalizeComparison(data.comparison);
|
||||
this.referenceMode = normalizeReferenceMode(data.referenceMode);
|
||||
this.referenceConstantValue = data.referenceConstantValue;
|
||||
this.referenceTargetType = normalizeReferenceTargetType(data.referenceTargetType);
|
||||
this.referenceUserSource = normalizeUserSource(data.referenceUserSource);
|
||||
this.referenceFurniSource = normalizeReferenceFurniSource(data.referenceFurniSource);
|
||||
this.filterExisting = data.filterExisting;
|
||||
this.invert = data.invert;
|
||||
this.setVariableToken(normalizeVariableToken((data.variableToken != null) ? data.variableToken : ((data.variableItemId > 0) ? String.valueOf(data.variableItemId) : "")));
|
||||
this.setReferenceVariableToken(normalizeVariableToken((data.referenceVariableToken != null) ? data.referenceVariableToken : ((data.referenceVariableItemId > 0) ? String.valueOf(data.referenceVariableItemId) : "")));
|
||||
this.setDelay(data.delay);
|
||||
|
||||
if (room == null || data.selectedItemIds == null) return;
|
||||
|
||||
for (Integer itemId : data.selectedItemIds) {
|
||||
if (itemId == null || itemId <= 0) continue;
|
||||
|
||||
HabboItem item = room.getHabboItem(itemId);
|
||||
if (item != null) this.referenceSelectedItems.add(item);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPickUp() {
|
||||
this.selectByValue = false;
|
||||
this.comparison = COMPARISON_EQUAL;
|
||||
this.referenceMode = REFERENCE_CONSTANT;
|
||||
this.referenceConstantValue = 0;
|
||||
this.referenceTargetType = TARGET_USER;
|
||||
this.referenceUserSource = WiredSourceUtil.SOURCE_TRIGGER;
|
||||
this.referenceFurniSource = WiredSourceUtil.SOURCE_TRIGGER;
|
||||
this.filterExisting = false;
|
||||
this.invert = false;
|
||||
this.referenceSelectedItems.clear();
|
||||
this.setVariableToken("");
|
||||
this.setReferenceVariableToken("");
|
||||
this.setDelay(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serializeWiredData(ServerMessage message, Room room) {
|
||||
this.refreshReferenceItems();
|
||||
|
||||
List<HabboItem> serializedItems = new ArrayList<>();
|
||||
if (this.selectByValue && this.referenceMode == REFERENCE_VARIABLE && this.referenceTargetType == TARGET_FURNI && this.referenceFurniSource == SOURCE_SECONDARY_SELECTED) {
|
||||
serializedItems.addAll(this.referenceSelectedItems);
|
||||
}
|
||||
|
||||
message.appendBoolean(false);
|
||||
message.appendInt(WiredManager.MAXIMUM_FURNI_SELECTION);
|
||||
message.appendInt(serializedItems.size());
|
||||
|
||||
for (HabboItem item : serializedItems) {
|
||||
message.appendInt(item.getId());
|
||||
}
|
||||
|
||||
message.appendInt(this.getBaseItem().getSpriteId());
|
||||
message.appendInt(this.getId());
|
||||
message.appendString(this.serializeStringData());
|
||||
message.appendInt(9);
|
||||
message.appendInt(this.selectByValue ? 1 : 0);
|
||||
message.appendInt(this.comparison);
|
||||
message.appendInt(this.referenceMode);
|
||||
message.appendInt(this.referenceConstantValue);
|
||||
message.appendInt(this.referenceTargetType);
|
||||
message.appendInt(this.referenceUserSource);
|
||||
message.appendInt(this.referenceFurniSource);
|
||||
message.appendInt(this.filterExisting ? 1 : 0);
|
||||
message.appendInt(this.invert ? 1 : 0);
|
||||
message.appendInt(0);
|
||||
message.appendInt(this.getType().code);
|
||||
message.appendInt(this.getDelay());
|
||||
message.appendInt(0);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@Override
|
||||
public boolean execute(RoomUnit roomUnit, Room room, Object[] stuff) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean requiresTriggeringUser() {
|
||||
return this.selectByValue && this.referenceMode == REFERENCE_VARIABLE && this.referenceTargetType == TARGET_USER && this.referenceUserSource == WiredSourceUtil.SOURCE_TRIGGER;
|
||||
}
|
||||
|
||||
private boolean matchesUser(Room room, RoomUnit roomUnit, WiredContext ctx) {
|
||||
if (!this.selectByValue) return this.hasUserVariable(room, roomUnit);
|
||||
|
||||
Integer currentValue = this.readUserValue(room, roomUnit);
|
||||
Integer referenceValue = this.resolveReferenceValue(ctx, room, roomUnit != null ? roomUnit.getId() : 0, TARGET_USER, -1);
|
||||
|
||||
return this.matchesComparison(currentValue, referenceValue);
|
||||
}
|
||||
|
||||
private boolean matchesFurni(Room room, HabboItem item, WiredContext ctx) {
|
||||
if (!this.selectByValue) return this.hasFurniVariable(room, item);
|
||||
|
||||
Integer currentValue = this.readFurniValue(room, item);
|
||||
Integer referenceValue = this.resolveReferenceValue(ctx, room, item != null ? item.getId() : 0, TARGET_FURNI, -1);
|
||||
|
||||
return this.matchesComparison(currentValue, referenceValue);
|
||||
}
|
||||
|
||||
private boolean hasUserVariable(Room room, RoomUnit roomUnit) {
|
||||
if (room == null || roomUnit == null) return false;
|
||||
|
||||
if (isCustomVariableToken(this.variableToken)) {
|
||||
Habbo habbo = room.getHabbo(roomUnit);
|
||||
return habbo != null && room.getUserVariableManager().hasVariable(habbo.getHabboInfo().getId(), this.variableItemId);
|
||||
}
|
||||
|
||||
return isInternalVariableToken(this.variableToken) && this.hasUserInternalVariable(room, roomUnit, getInternalVariableKey(this.variableToken));
|
||||
}
|
||||
|
||||
private boolean hasFurniVariable(Room room, HabboItem item) {
|
||||
if (room == null || item == null) return false;
|
||||
|
||||
if (isCustomVariableToken(this.variableToken)) {
|
||||
return room.getFurniVariableManager().hasVariable(item.getId(), this.variableItemId);
|
||||
}
|
||||
|
||||
return isInternalVariableToken(this.variableToken) && this.hasFurniInternalVariable(item, getInternalVariableKey(this.variableToken));
|
||||
}
|
||||
|
||||
private Integer resolveReferenceValue(WiredContext ctx, Room room, int destinationEntityId, int destinationTargetType, int destinationIndex) {
|
||||
if (!this.selectByValue || this.referenceMode != REFERENCE_VARIABLE) return this.referenceConstantValue;
|
||||
|
||||
ReferenceSnapshot snapshot = this.resolveReferences(ctx, room);
|
||||
if (snapshot == null || snapshot.isEmpty()) return null;
|
||||
if (snapshot.targetType == destinationTargetType && snapshot.values.containsKey(destinationEntityId)) return snapshot.values.get(destinationEntityId);
|
||||
if (destinationIndex >= 0 && destinationIndex < snapshot.values.size()) return new ArrayList<>(snapshot.values.values()).get(destinationIndex);
|
||||
|
||||
return new ArrayList<>(snapshot.values.values()).get(0);
|
||||
}
|
||||
|
||||
private ReferenceSnapshot resolveReferences(WiredContext ctx, Room room) {
|
||||
return switch (this.referenceTargetType) {
|
||||
case TARGET_FURNI -> this.furniReferences(ctx, room);
|
||||
case TARGET_CONTEXT -> this.contextReferences(ctx, room);
|
||||
case TARGET_ROOM -> this.roomReferences(room);
|
||||
default -> this.userReferences(ctx, room);
|
||||
};
|
||||
}
|
||||
|
||||
private ReferenceSnapshot userReferences(WiredContext ctx, Room room) {
|
||||
ReferenceSnapshot snapshot = new ReferenceSnapshot(TARGET_USER);
|
||||
|
||||
if (isInternalVariableToken(this.referenceVariableToken)) {
|
||||
String key = getInternalVariableKey(this.referenceVariableToken);
|
||||
if (!canUseUserInternalReference(key)) return null;
|
||||
|
||||
for (RoomUnit roomUnit : WiredSourceUtil.resolveUsers(ctx, this.referenceUserSource)) {
|
||||
Integer value = this.readUserInternalValue(room, roomUnit, key);
|
||||
if (value != null && roomUnit != null) snapshot.add(roomUnit.getId(), value);
|
||||
}
|
||||
|
||||
return snapshot.isEmpty() ? null : snapshot;
|
||||
}
|
||||
|
||||
WiredVariableDefinitionInfo definition = room.getUserVariableManager().getDefinitionInfo(this.referenceVariableItemId);
|
||||
if (definition == null || !definition.hasValue()) return null;
|
||||
|
||||
for (RoomUnit roomUnit : WiredSourceUtil.resolveUsers(ctx, this.referenceUserSource)) {
|
||||
if (roomUnit == null) continue;
|
||||
|
||||
Habbo habbo = room.getHabbo(roomUnit);
|
||||
if (habbo != null) snapshot.add(roomUnit.getId(), room.getUserVariableManager().getCurrentValue(habbo.getHabboInfo().getId(), this.referenceVariableItemId));
|
||||
}
|
||||
|
||||
return snapshot.isEmpty() ? null : snapshot;
|
||||
}
|
||||
|
||||
private ReferenceSnapshot furniReferences(WiredContext ctx, Room room) {
|
||||
int source = (this.referenceFurniSource == SOURCE_SECONDARY_SELECTED) ? WiredSourceUtil.SOURCE_SELECTED : this.referenceFurniSource;
|
||||
if (source == WiredSourceUtil.SOURCE_SELECTED) this.refreshReferenceItems();
|
||||
|
||||
ReferenceSnapshot snapshot = new ReferenceSnapshot(TARGET_FURNI);
|
||||
|
||||
if (isInternalVariableToken(this.referenceVariableToken)) {
|
||||
String key = getInternalVariableKey(this.referenceVariableToken);
|
||||
if (!canUseFurniInternalReference(key)) return null;
|
||||
|
||||
for (HabboItem item : WiredSourceUtil.resolveItems(ctx, source, this.referenceSelectedItems)) {
|
||||
Integer value = this.readFurniInternalValue(room, item, key);
|
||||
if (value != null && item != null) snapshot.add(item.getId(), value);
|
||||
}
|
||||
|
||||
return snapshot.isEmpty() ? null : snapshot;
|
||||
}
|
||||
|
||||
WiredVariableDefinitionInfo definition = room.getFurniVariableManager().getDefinitionInfo(this.referenceVariableItemId);
|
||||
if (definition == null || !definition.hasValue()) return null;
|
||||
|
||||
for (HabboItem item : WiredSourceUtil.resolveItems(ctx, source, this.referenceSelectedItems)) {
|
||||
if (item != null) snapshot.add(item.getId(), room.getFurniVariableManager().getCurrentValue(item.getId(), this.referenceVariableItemId));
|
||||
}
|
||||
|
||||
return snapshot.isEmpty() ? null : snapshot;
|
||||
}
|
||||
|
||||
private ReferenceSnapshot roomReferences(Room room) {
|
||||
ReferenceSnapshot snapshot = new ReferenceSnapshot(TARGET_ROOM);
|
||||
|
||||
if (isInternalVariableToken(this.referenceVariableToken)) {
|
||||
String key = getInternalVariableKey(this.referenceVariableToken);
|
||||
if (!canUseRoomInternalReference(key)) return null;
|
||||
|
||||
Integer value = this.readRoomInternalValue(room, key);
|
||||
if (value == null) return null;
|
||||
|
||||
snapshot.add(room.getId(), value);
|
||||
return snapshot;
|
||||
}
|
||||
|
||||
WiredVariableDefinitionInfo definition = room.getRoomVariableManager().getDefinitionInfo(this.referenceVariableItemId);
|
||||
if (definition == null || !definition.hasValue()) return null;
|
||||
|
||||
snapshot.add(room.getId(), room.getRoomVariableManager().getCurrentValue(this.referenceVariableItemId));
|
||||
return snapshot;
|
||||
}
|
||||
|
||||
private ReferenceSnapshot contextReferences(WiredContext ctx, Room room) {
|
||||
ReferenceSnapshot snapshot = new ReferenceSnapshot(TARGET_CONTEXT);
|
||||
|
||||
if (isInternalVariableToken(this.referenceVariableToken)) {
|
||||
String key = getInternalVariableKey(this.referenceVariableToken);
|
||||
if (!canUseContextInternalReference(key)) return null;
|
||||
|
||||
Integer value = WiredInternalVariableSupport.readContextValue(ctx, key);
|
||||
if (value == null) return null;
|
||||
|
||||
snapshot.add(this.referenceVariableItemId > 0 ? this.referenceVariableItemId : (room != null ? room.getId() : 0), value);
|
||||
return snapshot;
|
||||
}
|
||||
|
||||
WiredVariableDefinitionInfo definition = WiredContextVariableSupport.getDefinitionInfo(room, this.referenceVariableItemId);
|
||||
if (definition == null || !definition.hasValue() || !WiredContextVariableSupport.hasVariable(ctx, this.referenceVariableItemId)) return null;
|
||||
|
||||
Integer value = WiredContextVariableSupport.getCurrentValue(ctx, this.referenceVariableItemId);
|
||||
if (value == null) return null;
|
||||
|
||||
snapshot.add(this.referenceVariableItemId, value);
|
||||
return snapshot;
|
||||
}
|
||||
|
||||
private boolean isValidMainVariable(Room room, String token, boolean requireValue) {
|
||||
if (token == null || token.isEmpty()) return false;
|
||||
|
||||
int targetType = this.getVariableTargetType();
|
||||
|
||||
if (isInternalVariableToken(token)) {
|
||||
String key = getInternalVariableKey(token);
|
||||
return targetType == TARGET_FURNI
|
||||
? (requireValue ? canUseFurniInternalReference(key) : this.hasFurniInternalKey(key))
|
||||
: (requireValue ? canUseUserInternalReference(key) : this.hasUserInternalKey(key));
|
||||
}
|
||||
|
||||
if (targetType == TARGET_FURNI) {
|
||||
WiredVariableDefinitionInfo definition = (room != null) ? room.getFurniVariableManager().getDefinitionInfo(getCustomItemId(token)) : null;
|
||||
return definition != null && (!requireValue || definition.hasValue());
|
||||
}
|
||||
|
||||
WiredVariableDefinitionInfo definition = (room != null) ? room.getUserVariableManager().getDefinitionInfo(getCustomItemId(token)) : null;
|
||||
return definition != null && (!requireValue || definition.hasValue());
|
||||
}
|
||||
|
||||
private boolean isValidReference(Room room, int targetType, String token) {
|
||||
if (token == null || token.isEmpty()) return false;
|
||||
|
||||
if (isInternalVariableToken(token)) {
|
||||
String key = getInternalVariableKey(token);
|
||||
return switch (targetType) {
|
||||
case TARGET_FURNI -> canUseFurniInternalReference(key);
|
||||
case TARGET_CONTEXT -> canUseContextInternalReference(key);
|
||||
case TARGET_ROOM -> canUseRoomInternalReference(key);
|
||||
default -> canUseUserInternalReference(key);
|
||||
};
|
||||
}
|
||||
|
||||
return switch (targetType) {
|
||||
case TARGET_FURNI -> {
|
||||
WiredVariableDefinitionInfo definition = (room != null) ? room.getFurniVariableManager().getDefinitionInfo(getCustomItemId(token)) : null;
|
||||
yield definition != null && definition.hasValue();
|
||||
}
|
||||
case TARGET_CONTEXT -> this.isValidContextCustomReference(room, getCustomItemId(token));
|
||||
case TARGET_ROOM -> {
|
||||
WiredVariableDefinitionInfo definition = (room != null) ? room.getRoomVariableManager().getDefinitionInfo(getCustomItemId(token)) : null;
|
||||
yield definition != null && definition.hasValue();
|
||||
}
|
||||
default -> {
|
||||
WiredVariableDefinitionInfo definition = (room != null) ? room.getUserVariableManager().getDefinitionInfo(getCustomItemId(token)) : null;
|
||||
yield definition != null && definition.hasValue();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private boolean isValidContextCustomReference(Room room, int variableItemId) {
|
||||
WiredVariableDefinitionInfo definition = WiredContextVariableSupport.getDefinitionInfo(room, variableItemId);
|
||||
return definition != null && definition.hasValue();
|
||||
}
|
||||
|
||||
private boolean matchesComparison(Integer currentValue, Integer referenceValue) {
|
||||
if (currentValue == null || referenceValue == null) return false;
|
||||
|
||||
return switch (this.comparison) {
|
||||
case COMPARISON_GREATER_THAN -> currentValue > referenceValue;
|
||||
case COMPARISON_GREATER_THAN_OR_EQUAL -> currentValue >= referenceValue;
|
||||
case COMPARISON_LESS_THAN_OR_EQUAL -> currentValue <= referenceValue;
|
||||
case COMPARISON_LESS_THAN -> currentValue < referenceValue;
|
||||
case COMPARISON_NOT_EQUAL -> !currentValue.equals(referenceValue);
|
||||
default -> currentValue.equals(referenceValue);
|
||||
};
|
||||
}
|
||||
|
||||
private Integer readUserValue(Room room, RoomUnit roomUnit) {
|
||||
if (room == null || roomUnit == null) return null;
|
||||
|
||||
if (isInternalVariableToken(this.variableToken)) {
|
||||
String key = getInternalVariableKey(this.variableToken);
|
||||
return canUseUserInternalReference(key) ? this.readUserInternalValue(room, roomUnit, key) : null;
|
||||
}
|
||||
|
||||
WiredVariableDefinitionInfo definition = room.getUserVariableManager().getDefinitionInfo(this.variableItemId);
|
||||
if (definition == null || !definition.hasValue()) return null;
|
||||
|
||||
Habbo habbo = room.getHabbo(roomUnit);
|
||||
return (habbo != null) ? room.getUserVariableManager().getCurrentValue(habbo.getHabboInfo().getId(), this.variableItemId) : null;
|
||||
}
|
||||
|
||||
private Integer readFurniValue(Room room, HabboItem item) {
|
||||
if (room == null || item == null) return null;
|
||||
|
||||
if (isInternalVariableToken(this.variableToken)) {
|
||||
String key = getInternalVariableKey(this.variableToken);
|
||||
return canUseFurniInternalReference(key) ? this.readFurniInternalValue(room, item, key) : null;
|
||||
}
|
||||
|
||||
WiredVariableDefinitionInfo definition = room.getFurniVariableManager().getDefinitionInfo(this.variableItemId);
|
||||
return (definition != null && definition.hasValue()) ? room.getFurniVariableManager().getCurrentValue(item.getId(), this.variableItemId) : null;
|
||||
}
|
||||
|
||||
private boolean hasUserInternalVariable(Room room, RoomUnit roomUnit, String key) {
|
||||
return WiredInternalVariableSupport.hasUserValue(room, roomUnit, key);
|
||||
}
|
||||
|
||||
private boolean hasFurniInternalVariable(HabboItem item, String key) {
|
||||
return WiredInternalVariableSupport.hasFurniValue(item, key);
|
||||
}
|
||||
|
||||
private boolean hasUserInternalKey(String key) {
|
||||
return WiredInternalVariableSupport.canUseUserReference(key);
|
||||
}
|
||||
|
||||
private boolean hasFurniInternalKey(String key) {
|
||||
return WiredInternalVariableSupport.canUseFurniReference(key) || "@wallitem_offset".equals(WiredInternalVariableSupport.normalizeKey(key));
|
||||
}
|
||||
|
||||
private boolean hasRoomEntryMethod(Habbo habbo) {
|
||||
if (habbo == null) return false;
|
||||
|
||||
String roomEntryMethod = habbo.getHabboInfo().getRoomEntryMethod();
|
||||
return roomEntryMethod != null && !roomEntryMethod.trim().isEmpty() && !"unknown".equalsIgnoreCase(roomEntryMethod);
|
||||
}
|
||||
|
||||
private Integer readUserInternalValue(Room room, RoomUnit roomUnit, String key) {
|
||||
return WiredInternalVariableSupport.readUserValue(room, roomUnit, key);
|
||||
}
|
||||
|
||||
private Integer readFurniInternalValue(Room room, HabboItem item, String key) {
|
||||
return WiredInternalVariableSupport.readFurniValue(room, item, key);
|
||||
}
|
||||
|
||||
private Integer readRoomInternalValue(Room room, String key) {
|
||||
return WiredInternalVariableSupport.readRoomValue(room, key);
|
||||
}
|
||||
|
||||
private Integer getUserTeamScore(Room room, Habbo habbo) {
|
||||
if (room == null || habbo == null || habbo.getHabboInfo().getGamePlayer() == null) return null;
|
||||
|
||||
Game game = this.resolveTeamGame(room, habbo);
|
||||
GamePlayer gamePlayer = habbo.getHabboInfo().getGamePlayer();
|
||||
|
||||
if (game == null || gamePlayer.getTeamColor() == null) return gamePlayer.getScore();
|
||||
|
||||
GameTeam team = game.getTeam(gamePlayer.getTeamColor());
|
||||
return (team != null) ? team.getTotalScore() : gamePlayer.getScore();
|
||||
}
|
||||
|
||||
private Integer getTeamColorId(int effectId) {
|
||||
TeamEffectData data = this.getTeamEffectData(effectId);
|
||||
return data == null ? null : data.colorId;
|
||||
}
|
||||
|
||||
private Integer getTeamTypeId(int effectId) {
|
||||
TeamEffectData data = this.getTeamEffectData(effectId);
|
||||
return data == null ? null : data.typeId;
|
||||
}
|
||||
|
||||
private int getTeamMetric(Room room, GameTeamColors color, boolean score) {
|
||||
Game game = this.resolveTeamGame(room, null);
|
||||
if (game == null || color == null) return 0;
|
||||
|
||||
GameTeam team = game.getTeam(color);
|
||||
if (team == null) return 0;
|
||||
|
||||
return score ? team.getTotalScore() : team.getMembers().size();
|
||||
}
|
||||
|
||||
private Game resolveTeamGame(Room room, Habbo habbo) {
|
||||
if (room == null) return null;
|
||||
|
||||
if (habbo != null && habbo.getHabboInfo() != null && habbo.getHabboInfo().getCurrentGame() != null) {
|
||||
Game game = room.getGame(habbo.getHabboInfo().getCurrentGame());
|
||||
if (game != null) return game;
|
||||
}
|
||||
|
||||
Game wiredGame = room.getGame(WiredGame.class);
|
||||
if (wiredGame != null) return wiredGame;
|
||||
|
||||
Game freezeGame = room.getGame(FreezeGame.class);
|
||||
if (freezeGame != null) return freezeGame;
|
||||
|
||||
return room.getGame(BattleBanzaiGame.class);
|
||||
}
|
||||
|
||||
private TeamEffectData getTeamEffectData(int effectValue) {
|
||||
if (effectValue <= 0) return null;
|
||||
|
||||
if (effectValue >= 223 && effectValue <= 226) return new TeamEffectData(effectValue - 222, 0);
|
||||
if (effectValue >= 33 && effectValue <= 36) return new TeamEffectData(effectValue - 32, 1);
|
||||
if (effectValue >= 40 && effectValue <= 43) return new TeamEffectData(effectValue - 39, 2);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private void refreshReferenceItems() {
|
||||
THashSet<HabboItem> staleItems = new THashSet<>();
|
||||
Room room = this.getRoom();
|
||||
|
||||
if (room == null) {
|
||||
staleItems.addAll(this.referenceSelectedItems);
|
||||
} else {
|
||||
for (HabboItem item : this.referenceSelectedItems) {
|
||||
if (item == null || item.getRoomId() != room.getId() || room.getHabboItem(item.getId()) == null) {
|
||||
staleItems.add(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.referenceSelectedItems.removeAll(staleItems);
|
||||
}
|
||||
|
||||
private String serializeStringData() {
|
||||
return (this.variableToken == null ? "" : this.variableToken) + DELIM + (this.referenceVariableToken == null ? "" : this.referenceVariableToken);
|
||||
}
|
||||
|
||||
private void setVariableToken(String token) {
|
||||
this.variableToken = normalizeVariableToken(token);
|
||||
this.variableItemId = getCustomItemId(this.variableToken);
|
||||
}
|
||||
|
||||
private void setReferenceVariableToken(String token) {
|
||||
this.referenceVariableToken = normalizeVariableToken(token);
|
||||
this.referenceVariableItemId = getCustomItemId(this.referenceVariableToken);
|
||||
}
|
||||
|
||||
private List<Integer> toIds(THashSet<HabboItem> items) {
|
||||
List<Integer> ids = new ArrayList<>();
|
||||
|
||||
for (HabboItem item : items) {
|
||||
if (item != null) ids.add(item.getId());
|
||||
}
|
||||
|
||||
return ids;
|
||||
}
|
||||
|
||||
private static int normalizeReferenceMode(int value) {
|
||||
return (value == REFERENCE_VARIABLE) ? REFERENCE_VARIABLE : REFERENCE_CONSTANT;
|
||||
}
|
||||
|
||||
private static int normalizeReferenceTargetType(int value) {
|
||||
return switch (value) {
|
||||
case TARGET_FURNI, TARGET_CONTEXT, TARGET_ROOM -> value;
|
||||
default -> TARGET_USER;
|
||||
};
|
||||
}
|
||||
|
||||
private static int normalizeReferenceFurniSource(int value) {
|
||||
return switch (value) {
|
||||
case SOURCE_SECONDARY_SELECTED, WiredSourceUtil.SOURCE_SELECTOR, WiredSourceUtil.SOURCE_SIGNAL -> value;
|
||||
default -> WiredSourceUtil.SOURCE_TRIGGER;
|
||||
};
|
||||
}
|
||||
|
||||
private static int normalizeComparison(int value) {
|
||||
return switch (value) {
|
||||
case COMPARISON_GREATER_THAN, COMPARISON_GREATER_THAN_OR_EQUAL, COMPARISON_LESS_THAN_OR_EQUAL, COMPARISON_LESS_THAN, COMPARISON_NOT_EQUAL -> value;
|
||||
default -> COMPARISON_EQUAL;
|
||||
};
|
||||
}
|
||||
|
||||
private static int normalizeUserSource(int value) {
|
||||
return WiredSourceUtil.isDefaultUserSource(value) ? value : WiredSourceUtil.SOURCE_TRIGGER;
|
||||
}
|
||||
|
||||
protected static boolean isCustomVariableToken(String token) {
|
||||
return token != null && token.startsWith(CUSTOM_TOKEN_PREFIX);
|
||||
}
|
||||
|
||||
protected static boolean isInternalVariableToken(String token) {
|
||||
return token != null && token.startsWith(INTERNAL_TOKEN_PREFIX);
|
||||
}
|
||||
|
||||
private static int getCustomItemId(String token) {
|
||||
if (!isCustomVariableToken(token)) return 0;
|
||||
|
||||
try {
|
||||
return Integer.parseInt(token.substring(CUSTOM_TOKEN_PREFIX.length()));
|
||||
} catch (NumberFormatException e) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
private static String getInternalVariableKey(String token) {
|
||||
return isInternalVariableToken(token) ? WiredInternalVariableSupport.normalizeKey(token.substring(INTERNAL_TOKEN_PREFIX.length())) : "";
|
||||
}
|
||||
|
||||
protected static String normalizeVariableToken(String token) {
|
||||
if (token == null) return "";
|
||||
|
||||
String normalized = token.trim();
|
||||
if (normalized.isEmpty()) return "";
|
||||
if (isCustomVariableToken(normalized)) return normalized;
|
||||
if (isInternalVariableToken(normalized)) return INTERNAL_TOKEN_PREFIX + WiredInternalVariableSupport.normalizeKey(normalized.substring(INTERNAL_TOKEN_PREFIX.length()));
|
||||
|
||||
try {
|
||||
int parsed = Integer.parseInt(normalized);
|
||||
return (parsed > 0) ? (CUSTOM_TOKEN_PREFIX + parsed) : "";
|
||||
} catch (NumberFormatException e) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean canUseUserInternalReference(String key) {
|
||||
return WiredInternalVariableSupport.canUseUserReference(key);
|
||||
}
|
||||
|
||||
private static boolean canUseFurniInternalReference(String key) {
|
||||
return WiredInternalVariableSupport.canUseFurniReference(key);
|
||||
}
|
||||
|
||||
private static boolean canUseRoomInternalReference(String key) {
|
||||
return WiredInternalVariableSupport.canUseRoomReference(key);
|
||||
}
|
||||
|
||||
private static boolean canUseContextInternalReference(String key) {
|
||||
return WiredInternalVariableSupport.canUseContextReference(key);
|
||||
}
|
||||
|
||||
private static int param(int[] params, int index, int fallback) {
|
||||
return (params != null && params.length > index) ? params[index] : fallback;
|
||||
}
|
||||
|
||||
private static String[] parseStringData(String value) {
|
||||
return (value == null || value.isEmpty()) ? new String[0] : value.split("\\t", -1);
|
||||
}
|
||||
|
||||
private static int parseInteger(String value) {
|
||||
try {
|
||||
return (value == null || value.trim().isEmpty()) ? 0 : Integer.parseInt(value.trim());
|
||||
} catch (NumberFormatException e) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
protected static class JsonData {
|
||||
boolean selectByValue;
|
||||
int comparison;
|
||||
int referenceMode;
|
||||
int referenceConstantValue;
|
||||
int referenceTargetType;
|
||||
int referenceUserSource;
|
||||
int referenceFurniSource;
|
||||
boolean filterExisting;
|
||||
boolean invert;
|
||||
String variableToken;
|
||||
int variableItemId;
|
||||
String referenceVariableToken;
|
||||
int referenceVariableItemId;
|
||||
List<Integer> selectedItemIds;
|
||||
int delay;
|
||||
|
||||
JsonData(boolean selectByValue, int comparison, int referenceMode, int referenceConstantValue, int referenceTargetType, int referenceUserSource, int referenceFurniSource, boolean filterExisting, boolean invert, String variableToken, int variableItemId, String referenceVariableToken, int referenceVariableItemId, List<Integer> selectedItemIds, int delay) {
|
||||
this.selectByValue = selectByValue;
|
||||
this.comparison = comparison;
|
||||
this.referenceMode = referenceMode;
|
||||
this.referenceConstantValue = referenceConstantValue;
|
||||
this.referenceTargetType = referenceTargetType;
|
||||
this.referenceUserSource = referenceUserSource;
|
||||
this.referenceFurniSource = referenceFurniSource;
|
||||
this.filterExisting = filterExisting;
|
||||
this.invert = invert;
|
||||
this.variableToken = variableToken;
|
||||
this.variableItemId = variableItemId;
|
||||
this.referenceVariableToken = referenceVariableToken;
|
||||
this.referenceVariableItemId = referenceVariableItemId;
|
||||
this.selectedItemIds = selectedItemIds;
|
||||
this.delay = delay;
|
||||
}
|
||||
}
|
||||
|
||||
private static class ReferenceSnapshot {
|
||||
final int targetType;
|
||||
final LinkedHashMap<Integer, Integer> values = new LinkedHashMap<>();
|
||||
|
||||
ReferenceSnapshot(int targetType) {
|
||||
this.targetType = targetType;
|
||||
}
|
||||
|
||||
void add(int entityId, int value) {
|
||||
this.values.put(entityId, value);
|
||||
}
|
||||
|
||||
boolean isEmpty() {
|
||||
return this.values.isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
private static class TeamEffectData {
|
||||
final int colorId;
|
||||
final int typeId;
|
||||
|
||||
TeamEffectData(int colorId, int typeId) {
|
||||
this.colorId = colorId;
|
||||
this.typeId = typeId;
|
||||
}
|
||||
}
|
||||
}
|
||||
+12
@@ -141,6 +141,18 @@ public class WiredTriggerHabboSaysKeyword extends InteractionWiredTrigger {
|
||||
return this.hideMessage;
|
||||
}
|
||||
|
||||
public boolean isOwnerOnly() {
|
||||
return this.ownerOnly;
|
||||
}
|
||||
|
||||
public String getKey() {
|
||||
return this.key;
|
||||
}
|
||||
|
||||
public int getMatchMode() {
|
||||
return this.matchMode;
|
||||
}
|
||||
|
||||
private boolean matchesText(String text) {
|
||||
String normalizedText = text.toLowerCase().trim();
|
||||
String normalizedKey = this.key.toLowerCase().trim();
|
||||
|
||||
+47
-1
@@ -31,7 +31,7 @@ public class WiredTriggerReceiveSignal extends InteractionWiredTrigger {
|
||||
|
||||
private static final long ACTIVATION_PULSE_MS = 300L;
|
||||
private static final String ANTENNA_INTERACTION = "antenna";
|
||||
private static final String REQUIRE_ANTENNA_ERROR = "Puoi selezionare solo furni antenna.";
|
||||
private static final String REQUIRE_ANTENNA_ERROR = "You can only select antenna furni.";
|
||||
|
||||
private int channel = 0; // signal channel (0-based)
|
||||
private THashSet<HabboItem> items;
|
||||
@@ -68,6 +68,52 @@ public class WiredTriggerReceiveSignal extends InteractionWiredTrigger {
|
||||
return channel;
|
||||
}
|
||||
|
||||
public boolean unlinkAntenna(int antennaItemId) {
|
||||
if (antennaItemId <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean changed = false;
|
||||
|
||||
if (!this.items.isEmpty()) {
|
||||
THashSet<HabboItem> itemsToRemove = new THashSet<>();
|
||||
|
||||
for (HabboItem item : this.items) {
|
||||
if (item == null || item.getId() == antennaItemId) {
|
||||
itemsToRemove.add(item);
|
||||
}
|
||||
}
|
||||
|
||||
if (!itemsToRemove.isEmpty()) {
|
||||
this.items.removeAll(itemsToRemove);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.furniSource == WiredSourceUtil.SOURCE_SELECTED) {
|
||||
int nextChannel = 0;
|
||||
|
||||
if (!this.items.isEmpty()) {
|
||||
HabboItem firstItem = this.items.iterator().next();
|
||||
nextChannel = (firstItem != null) ? firstItem.getId() : 0;
|
||||
}
|
||||
|
||||
if (this.channel != nextChannel) {
|
||||
this.channel = nextChannel;
|
||||
changed = true;
|
||||
}
|
||||
} else if (this.channel == antennaItemId) {
|
||||
this.channel = 0;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
this.needsUpdate(true);
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTriggeredByRoomUnit() {
|
||||
return false;
|
||||
|
||||
+302
@@ -0,0 +1,302 @@
|
||||
package com.eu.habbo.habbohotel.items.interactions.wired.triggers;
|
||||
|
||||
import com.eu.habbo.Emulator;
|
||||
import com.eu.habbo.habbohotel.gameclients.GameClient;
|
||||
import com.eu.habbo.habbohotel.items.Item;
|
||||
import com.eu.habbo.habbohotel.items.interactions.InteractionWiredTrigger;
|
||||
import com.eu.habbo.habbohotel.items.interactions.wired.WiredSettings;
|
||||
import com.eu.habbo.habbohotel.rooms.Room;
|
||||
import com.eu.habbo.habbohotel.rooms.RoomUnit;
|
||||
import com.eu.habbo.habbohotel.rooms.WiredVariableDefinitionInfo;
|
||||
import com.eu.habbo.habbohotel.users.HabboItem;
|
||||
import com.eu.habbo.habbohotel.wired.WiredTriggerType;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredEvent;
|
||||
import com.eu.habbo.habbohotel.wired.core.WiredManager;
|
||||
import com.eu.habbo.messages.ServerMessage;
|
||||
import com.eu.habbo.messages.incoming.wired.WiredTriggerSaveException;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
public class WiredTriggerVariableChanged extends InteractionWiredTrigger {
|
||||
public static final WiredTriggerType type = WiredTriggerType.VARIABLE_CHANGED;
|
||||
|
||||
public static final int TARGET_USER = 0;
|
||||
public static final int TARGET_FURNI = 1;
|
||||
public static final int TARGET_ROOM = 3;
|
||||
|
||||
private static final String CUSTOM_TOKEN_PREFIX = "custom:";
|
||||
|
||||
private String variableToken = "";
|
||||
private int variableItemId = 0;
|
||||
private int targetType = TARGET_USER;
|
||||
private boolean createdEnabled = true;
|
||||
private boolean valueChangedEnabled = true;
|
||||
private boolean increasedEnabled = true;
|
||||
private boolean decreasedEnabled = true;
|
||||
private boolean unchangedEnabled = true;
|
||||
private boolean deletedEnabled = true;
|
||||
|
||||
public WiredTriggerVariableChanged(ResultSet set, Item baseItem) throws SQLException {
|
||||
super(set, baseItem);
|
||||
}
|
||||
|
||||
public WiredTriggerVariableChanged(int id, int userId, Item item, String extradata, int limitedStack, int limitedSells) {
|
||||
super(id, userId, item, extradata, limitedStack, limitedSells);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(HabboItem triggerItem, WiredEvent event) {
|
||||
if (event == null || event.getType() != WiredEvent.Type.VARIABLE_CHANGED) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (event.getVariableTargetType() != this.targetType || event.getVariableDefinitionItemId() != this.variableItemId) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.createdEnabled && event.isVariableCreated()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (this.deletedEnabled && event.isVariableDeleted()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!this.valueChangedEnabled) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return switch (event.getVariableChangeKind()) {
|
||||
case INCREASED -> this.increasedEnabled;
|
||||
case DECREASED -> this.decreasedEnabled;
|
||||
case UNCHANGED -> this.unchangedEnabled;
|
||||
default -> false;
|
||||
};
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
@Override
|
||||
public boolean execute(RoomUnit roomUnit, Room room, Object[] stuff) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WiredTriggerType getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serializeWiredData(ServerMessage message, Room room) {
|
||||
message.appendBoolean(false);
|
||||
message.appendInt(0);
|
||||
message.appendInt(0);
|
||||
message.appendInt(this.getBaseItem().getSpriteId());
|
||||
message.appendInt(this.getId());
|
||||
message.appendString(this.variableToken == null ? "" : this.variableToken);
|
||||
message.appendInt(7);
|
||||
message.appendInt(this.targetType);
|
||||
message.appendInt(this.createdEnabled ? 1 : 0);
|
||||
message.appendInt(this.valueChangedEnabled ? 1 : 0);
|
||||
message.appendInt(this.increasedEnabled ? 1 : 0);
|
||||
message.appendInt(this.decreasedEnabled ? 1 : 0);
|
||||
message.appendInt(this.unchangedEnabled ? 1 : 0);
|
||||
message.appendInt(this.deletedEnabled ? 1 : 0);
|
||||
message.appendInt(0);
|
||||
message.appendInt(this.getType().code);
|
||||
message.appendInt(0);
|
||||
message.appendInt(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean saveData(WiredSettings settings) {
|
||||
return this.saveData(settings, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean saveData(WiredSettings settings, GameClient gameClient) {
|
||||
Room room = Emulator.getGameEnvironment().getRoomManager().getRoom(this.getRoomId());
|
||||
int[] params = settings.getIntParams();
|
||||
|
||||
this.targetType = normalizeTargetType((params.length > 0) ? params[0] : TARGET_USER);
|
||||
this.createdEnabled = (params.length <= 1) || (params[1] == 1);
|
||||
this.valueChangedEnabled = (params.length <= 2) || (params[2] == 1);
|
||||
this.increasedEnabled = (params.length <= 3) || (params[3] == 1);
|
||||
this.decreasedEnabled = (params.length <= 4) || (params[4] == 1);
|
||||
this.unchangedEnabled = (params.length <= 5) || (params[5] == 1);
|
||||
this.deletedEnabled = (params.length <= 6) || (params[6] == 1);
|
||||
this.setVariableToken(normalizeVariableToken(settings.getStringParam()));
|
||||
this.normalizeOptions();
|
||||
|
||||
if (this.variableItemId <= 0) {
|
||||
throw new WiredTriggerSaveException("wiredfurni.params.variables.validation.missing_variable");
|
||||
}
|
||||
|
||||
if (!this.hasAnyEnabledOption()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (room == null || !this.isValidDefinition(room)) {
|
||||
throw new WiredTriggerSaveException("wiredfurni.params.variables.validation.invalid_variable");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getWiredData() {
|
||||
return WiredManager.getGson().toJson(new JsonData(
|
||||
this.variableToken,
|
||||
this.variableItemId,
|
||||
this.targetType,
|
||||
this.createdEnabled,
|
||||
this.valueChangedEnabled,
|
||||
this.increasedEnabled,
|
||||
this.decreasedEnabled,
|
||||
this.unchangedEnabled,
|
||||
this.deletedEnabled
|
||||
));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadWiredData(ResultSet set, Room room) throws SQLException {
|
||||
this.onPickUp();
|
||||
|
||||
String wiredData = set.getString("wired_data");
|
||||
if (wiredData == null || wiredData.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!wiredData.startsWith("{")) {
|
||||
this.setVariableToken(normalizeVariableToken(wiredData));
|
||||
return;
|
||||
}
|
||||
|
||||
JsonData data = WiredManager.getGson().fromJson(wiredData, JsonData.class);
|
||||
if (data == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.targetType = normalizeTargetType(data.targetType);
|
||||
this.createdEnabled = data.createdEnabled;
|
||||
this.valueChangedEnabled = data.valueChangedEnabled;
|
||||
this.increasedEnabled = data.increasedEnabled;
|
||||
this.decreasedEnabled = data.decreasedEnabled;
|
||||
this.unchangedEnabled = data.unchangedEnabled;
|
||||
this.deletedEnabled = data.deletedEnabled;
|
||||
this.setVariableToken(normalizeVariableToken((data.variableToken != null) ? data.variableToken : ((data.variableItemId > 0) ? String.valueOf(data.variableItemId) : "")));
|
||||
this.normalizeOptions();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPickUp() {
|
||||
this.variableToken = "";
|
||||
this.variableItemId = 0;
|
||||
this.targetType = TARGET_USER;
|
||||
this.createdEnabled = true;
|
||||
this.valueChangedEnabled = true;
|
||||
this.increasedEnabled = true;
|
||||
this.decreasedEnabled = true;
|
||||
this.unchangedEnabled = true;
|
||||
this.deletedEnabled = true;
|
||||
}
|
||||
|
||||
private void setVariableToken(String token) {
|
||||
this.variableToken = normalizeVariableToken(token);
|
||||
this.variableItemId = getCustomItemId(this.variableToken);
|
||||
}
|
||||
|
||||
private void normalizeOptions() {
|
||||
if (!this.valueChangedEnabled) {
|
||||
this.increasedEnabled = false;
|
||||
this.decreasedEnabled = false;
|
||||
this.unchangedEnabled = false;
|
||||
}
|
||||
|
||||
if (this.targetType == TARGET_ROOM) {
|
||||
this.createdEnabled = false;
|
||||
this.deletedEnabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasAnyEnabledOption() {
|
||||
return this.createdEnabled
|
||||
|| this.deletedEnabled
|
||||
|| (this.valueChangedEnabled && (this.increasedEnabled || this.decreasedEnabled || this.unchangedEnabled));
|
||||
}
|
||||
|
||||
private boolean isValidDefinition(Room room) {
|
||||
WiredVariableDefinitionInfo definitionInfo = switch (this.targetType) {
|
||||
case TARGET_FURNI -> room.getFurniVariableManager().getDefinitionInfo(this.variableItemId);
|
||||
case TARGET_ROOM -> room.getRoomVariableManager().getDefinitionInfo(this.variableItemId);
|
||||
default -> room.getUserVariableManager().getDefinitionInfo(this.variableItemId);
|
||||
};
|
||||
|
||||
return definitionInfo != null;
|
||||
}
|
||||
|
||||
private static int normalizeTargetType(int value) {
|
||||
return switch (value) {
|
||||
case TARGET_FURNI, TARGET_ROOM -> value;
|
||||
default -> TARGET_USER;
|
||||
};
|
||||
}
|
||||
|
||||
private static String normalizeVariableToken(String token) {
|
||||
if (token == null) {
|
||||
return "";
|
||||
}
|
||||
|
||||
String normalized = token.trim();
|
||||
if (normalized.isEmpty()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
if (normalized.startsWith(CUSTOM_TOKEN_PREFIX)) {
|
||||
return normalized;
|
||||
}
|
||||
|
||||
try {
|
||||
int itemId = Integer.parseInt(normalized);
|
||||
return (itemId > 0) ? (CUSTOM_TOKEN_PREFIX + itemId) : "";
|
||||
} catch (NumberFormatException ignored) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
private static int getCustomItemId(String token) {
|
||||
if (token == null || !token.startsWith(CUSTOM_TOKEN_PREFIX)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
try {
|
||||
return Integer.parseInt(token.substring(CUSTOM_TOKEN_PREFIX.length()));
|
||||
} catch (NumberFormatException ignored) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static class JsonData {
|
||||
String variableToken;
|
||||
int variableItemId;
|
||||
int targetType;
|
||||
boolean createdEnabled;
|
||||
boolean valueChangedEnabled;
|
||||
boolean increasedEnabled;
|
||||
boolean decreasedEnabled;
|
||||
boolean unchangedEnabled;
|
||||
boolean deletedEnabled;
|
||||
|
||||
JsonData(String variableToken, int variableItemId, int targetType, boolean createdEnabled, boolean valueChangedEnabled, boolean increasedEnabled, boolean decreasedEnabled, boolean unchangedEnabled, boolean deletedEnabled) {
|
||||
this.variableToken = variableToken;
|
||||
this.variableItemId = variableItemId;
|
||||
this.targetType = targetType;
|
||||
this.createdEnabled = createdEnabled;
|
||||
this.valueChangedEnabled = valueChangedEnabled;
|
||||
this.increasedEnabled = increasedEnabled;
|
||||
this.decreasedEnabled = decreasedEnabled;
|
||||
this.unchangedEnabled = unchangedEnabled;
|
||||
this.deletedEnabled = deletedEnabled;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -54,11 +54,23 @@ public class ModToolManager {
|
||||
if (userId <= 0)
|
||||
return;
|
||||
|
||||
try (Connection connection = Emulator.getDatabase().getDataSource().getConnection(); PreparedStatement statement = connection.prepareStatement("SELECT users.*, users_settings.*, permissions.rank_name, permissions.acc_hide_mail AS hide_mail, permissions.id AS rank_id FROM users INNER JOIN users_settings ON users.id = users_settings.user_id INNER JOIN permissions ON permissions.id = users.rank WHERE users.id = ? LIMIT 1")) {
|
||||
String query = Emulator.getGameEnvironment().getPermissionsManager().isNormalizedSchemaEnabled()
|
||||
? "SELECT users.*, users_settings.*, permission_ranks.rank_name, permission_ranks.id AS rank_id " +
|
||||
"FROM users " +
|
||||
"INNER JOIN users_settings ON users.id = users_settings.user_id " +
|
||||
"INNER JOIN permission_ranks ON permission_ranks.id = users.rank " +
|
||||
"WHERE users.id = ? LIMIT 1"
|
||||
: "SELECT users.*, users_settings.*, permissions.rank_name, permissions.acc_hide_mail AS hide_mail, permissions.id AS rank_id FROM users INNER JOIN users_settings ON users.id = users_settings.user_id INNER JOIN permissions ON permissions.id = users.rank WHERE users.id = ? LIMIT 1";
|
||||
|
||||
try (Connection connection = Emulator.getDatabase().getDataSource().getConnection(); PreparedStatement statement = connection.prepareStatement(query)) {
|
||||
statement.setInt(1, userId);
|
||||
try (ResultSet set = statement.executeQuery()) {
|
||||
while (set.next()) {
|
||||
client.sendResponse(new ModToolUserInfoComposer(set));
|
||||
boolean hideMail = Emulator.getGameEnvironment().getPermissionsManager().isNormalizedSchemaEnabled()
|
||||
? Emulator.getGameEnvironment().getPermissionsManager().getRank(set.getInt("rank_id")).hasPermission("acc_hide_mail", false)
|
||||
: set.getBoolean("hide_mail");
|
||||
|
||||
client.sendResponse(new ModToolUserInfoComposer(set, hideMail));
|
||||
}
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
|
||||
+156
-8
@@ -11,6 +11,7 @@ import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.sql.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -20,6 +21,7 @@ public class PermissionsManager {
|
||||
private final TIntObjectHashMap<Rank> ranks;
|
||||
private final TIntIntHashMap enables;
|
||||
private final THashMap<String, List<Rank>> badges;
|
||||
private volatile boolean normalizedSchemaEnabled;
|
||||
|
||||
public PermissionsManager() {
|
||||
long millis = System.currentTimeMillis();
|
||||
@@ -40,7 +42,30 @@ public class PermissionsManager {
|
||||
private void loadPermissions() {
|
||||
this.badges.clear();
|
||||
|
||||
try (Connection connection = Emulator.getDatabase().getDataSource().getConnection(); Statement statement = connection.createStatement(); ResultSet set = statement.executeQuery("SELECT * FROM permissions ORDER BY id ASC")) {
|
||||
try (Connection connection = Emulator.getDatabase().getDataSource().getConnection()) {
|
||||
if (this.hasNormalizedPermissionsSchema(connection)) {
|
||||
try {
|
||||
if (this.loadPermissionsNormalized(connection)) {
|
||||
this.normalizedSchemaEnabled = true;
|
||||
LOGGER.info("Permissions Manager -> Using normalized permissions schema.");
|
||||
return;
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
LOGGER.warn("Permissions Manager -> Failed to load normalized permissions schema, falling back to legacy permissions table.", e);
|
||||
}
|
||||
}
|
||||
|
||||
this.normalizedSchemaEnabled = false;
|
||||
this.badges.clear();
|
||||
LOGGER.info("Permissions Manager -> Using legacy permissions schema.");
|
||||
this.loadPermissionsLegacy(connection);
|
||||
} catch (SQLException e) {
|
||||
LOGGER.error("Caught SQL exception", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void loadPermissionsLegacy(Connection connection) throws SQLException {
|
||||
try (Statement statement = connection.createStatement(); ResultSet set = statement.executeQuery("SELECT * FROM permissions ORDER BY id ASC")) {
|
||||
while (set.next()) {
|
||||
Rank rank = null;
|
||||
if (!this.ranks.containsKey(set.getInt("id"))) {
|
||||
@@ -51,16 +76,135 @@ public class PermissionsManager {
|
||||
rank.load(set);
|
||||
}
|
||||
|
||||
if (rank != null && !rank.getBadge().isEmpty()) {
|
||||
if (!this.badges.containsKey(rank.getBadge())) {
|
||||
this.badges.put(rank.getBadge(), new ArrayList<Rank>());
|
||||
}
|
||||
this.addBadgeMapping(rank);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.badges.get(rank.getBadge()).add(rank);
|
||||
private boolean loadPermissionsNormalized(Connection connection) throws SQLException {
|
||||
boolean hasRanks = false;
|
||||
List<Rank> loadedRanks = new ArrayList<>();
|
||||
|
||||
try (Statement statement = connection.createStatement(); ResultSet set = statement.executeQuery("SELECT * FROM permission_ranks ORDER BY id ASC")) {
|
||||
while (set.next()) {
|
||||
hasRanks = true;
|
||||
|
||||
Rank rank = this.ranks.get(set.getInt("id"));
|
||||
|
||||
if (rank == null) {
|
||||
rank = new Rank(set.getInt("id"));
|
||||
this.ranks.put(set.getInt("id"), rank);
|
||||
}
|
||||
|
||||
rank.loadNormalizedMetadata(set);
|
||||
this.addBadgeMapping(rank);
|
||||
loadedRanks.add(rank);
|
||||
}
|
||||
}
|
||||
|
||||
if (!hasRanks) {
|
||||
return false;
|
||||
}
|
||||
|
||||
this.ensureNormalizedRankColumns(connection, loadedRanks);
|
||||
|
||||
boolean hasDefinitions = false;
|
||||
|
||||
try (PreparedStatement statement = connection.prepareStatement("SELECT * FROM permission_definitions ORDER BY permission_key ASC");
|
||||
ResultSet set = statement.executeQuery()) {
|
||||
ResultSetMetaData meta = set.getMetaData();
|
||||
Set<String> availableColumns = new HashSet<>();
|
||||
|
||||
for (int i = 1; i <= meta.getColumnCount(); i++) {
|
||||
availableColumns.add(meta.getColumnName(i).toLowerCase());
|
||||
}
|
||||
|
||||
for (Rank rank : loadedRanks) {
|
||||
if (!availableColumns.contains(("rank_" + rank.getId()).toLowerCase())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
LOGGER.error("Caught SQL exception", e);
|
||||
|
||||
while (set.next()) {
|
||||
hasDefinitions = true;
|
||||
String permissionKey = set.getString("permission_key");
|
||||
|
||||
for (Rank rank : loadedRanks) {
|
||||
String rankColumn = "rank_" + rank.getId();
|
||||
|
||||
if (!availableColumns.contains(rankColumn.toLowerCase())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
rank.setPermission(permissionKey, PermissionSetting.fromString(Integer.toString(set.getInt(rankColumn))));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return hasDefinitions;
|
||||
}
|
||||
|
||||
private void ensureNormalizedRankColumns(Connection connection, List<Rank> loadedRanks) throws SQLException {
|
||||
Set<String> availableColumns = new HashSet<>();
|
||||
|
||||
try (PreparedStatement statement = connection.prepareStatement("SELECT column_name FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'permission_definitions'");
|
||||
ResultSet set = statement.executeQuery()) {
|
||||
while (set.next()) {
|
||||
availableColumns.add(set.getString("column_name").toLowerCase());
|
||||
}
|
||||
}
|
||||
|
||||
for (Rank rank : loadedRanks) {
|
||||
String rankColumn = "rank_" + rank.getId();
|
||||
|
||||
if (availableColumns.contains(rankColumn.toLowerCase())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try (Statement statement = connection.createStatement()) {
|
||||
statement.execute("ALTER TABLE permission_definitions ADD COLUMN `" + rankColumn + "` tinyint(3) unsigned NOT NULL DEFAULT 0");
|
||||
}
|
||||
|
||||
availableColumns.add(rankColumn.toLowerCase());
|
||||
LOGGER.info("Permissions Manager -> Added missing normalized permission column {}.", rankColumn);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasNormalizedPermissionsSchema(Connection connection) throws SQLException {
|
||||
if (!this.tableExists(connection, "permission_ranks") || !this.tableExists(connection, "permission_definitions")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!this.tableHasRows(connection, "permission_ranks")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return this.tableHasRows(connection, "permission_definitions");
|
||||
}
|
||||
|
||||
private boolean tableExists(Connection connection, String tableName) throws SQLException {
|
||||
try (PreparedStatement statement = connection.prepareStatement("SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name = ?")) {
|
||||
statement.setString(1, tableName);
|
||||
|
||||
try (ResultSet set = statement.executeQuery()) {
|
||||
return set.next() && set.getInt(1) > 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean tableHasRows(Connection connection, String tableName) throws SQLException {
|
||||
try (Statement statement = connection.createStatement(); ResultSet set = statement.executeQuery("SELECT COUNT(*) FROM " + tableName)) {
|
||||
return set.next() && set.getInt(1) > 0;
|
||||
}
|
||||
}
|
||||
|
||||
private void addBadgeMapping(Rank rank) {
|
||||
if (rank != null && !rank.getBadge().isEmpty()) {
|
||||
if (!this.badges.containsKey(rank.getBadge())) {
|
||||
this.badges.put(rank.getBadge(), new ArrayList<Rank>());
|
||||
}
|
||||
|
||||
this.badges.get(rank.getBadge()).add(rank);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -139,4 +283,8 @@ public class PermissionsManager {
|
||||
public List<Rank> getAllRanks() {
|
||||
return new ArrayList<>(this.ranks.valueCollection());
|
||||
}
|
||||
|
||||
public boolean isNormalizedSchemaEnabled() {
|
||||
return this.normalizedSchemaEnabled;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,32 +35,29 @@ public class Rank {
|
||||
private int gotwTimerAmount;
|
||||
|
||||
public Rank(ResultSet set) throws SQLException {
|
||||
this(set.getInt("id"));
|
||||
this.load(set);
|
||||
}
|
||||
|
||||
public Rank(int id) {
|
||||
this.permissions = new THashMap<>();
|
||||
this.variables = new THashMap<>();
|
||||
this.id = set.getInt("id");
|
||||
this.level = set.getInt("level");
|
||||
this.id = id;
|
||||
this.level = 1;
|
||||
this.diamondsTimerAmount = 1;
|
||||
this.creditsTimerAmount = 1;
|
||||
this.pixelsTimerAmount = 1;
|
||||
this.gotwTimerAmount = 1;
|
||||
|
||||
this.load(set);
|
||||
}
|
||||
|
||||
public void load(ResultSet set) throws SQLException {
|
||||
this.permissions.clear();
|
||||
this.variables.clear();
|
||||
|
||||
this.loadMetadata(set);
|
||||
|
||||
ResultSetMetaData meta = set.getMetaData();
|
||||
this.name = set.getString("rank_name");
|
||||
this.badge = set.getString("badge");
|
||||
this.roomEffect = set.getInt("room_effect");
|
||||
this.logCommands = set.getString("log_commands").equals("1");
|
||||
this.prefix = set.getString("prefix");
|
||||
this.prefixColor = set.getString("prefix_color");
|
||||
this.level = set.getInt("level");
|
||||
this.diamondsTimerAmount = set.getInt("auto_points_amount");
|
||||
this.creditsTimerAmount = set.getInt("auto_credits_amount");
|
||||
this.pixelsTimerAmount = set.getInt("auto_pixels_amount");
|
||||
this.gotwTimerAmount = set.getInt("auto_gotw_amount");
|
||||
this.hasPrefix = !this.prefix.isEmpty();
|
||||
|
||||
for (int i = 1; i < meta.getColumnCount() + 1; i++) {
|
||||
String columnName = meta.getColumnName(i);
|
||||
if (columnName.startsWith("cmd_") || columnName.startsWith("acc_")) {
|
||||
@@ -71,6 +68,51 @@ public class Rank {
|
||||
}
|
||||
}
|
||||
|
||||
public void loadNormalizedMetadata(ResultSet set) throws SQLException {
|
||||
this.permissions.clear();
|
||||
this.variables.clear();
|
||||
this.loadMetadata(set);
|
||||
this.storeMetadataVariables();
|
||||
}
|
||||
|
||||
public void setPermission(String key, PermissionSetting setting) {
|
||||
this.permissions.put(key, new Permission(key, setting));
|
||||
}
|
||||
|
||||
private void loadMetadata(ResultSet set) throws SQLException {
|
||||
this.name = this.safeString(set.getString("rank_name"));
|
||||
this.badge = this.safeString(set.getString("badge"));
|
||||
this.roomEffect = set.getInt("room_effect");
|
||||
this.logCommands = "1".equals(this.safeString(set.getString("log_commands")));
|
||||
this.prefix = this.safeString(set.getString("prefix"));
|
||||
this.prefixColor = this.safeString(set.getString("prefix_color"));
|
||||
this.level = set.getInt("level");
|
||||
this.diamondsTimerAmount = set.getInt("auto_points_amount");
|
||||
this.creditsTimerAmount = set.getInt("auto_credits_amount");
|
||||
this.pixelsTimerAmount = set.getInt("auto_pixels_amount");
|
||||
this.gotwTimerAmount = set.getInt("auto_gotw_amount");
|
||||
this.hasPrefix = !this.prefix.isEmpty();
|
||||
}
|
||||
|
||||
private void storeMetadataVariables() {
|
||||
this.variables.put("id", Integer.toString(this.id));
|
||||
this.variables.put("rank_name", this.name);
|
||||
this.variables.put("badge", this.badge);
|
||||
this.variables.put("room_effect", Integer.toString(this.roomEffect));
|
||||
this.variables.put("log_commands", this.logCommands ? "1" : "0");
|
||||
this.variables.put("prefix", this.prefix);
|
||||
this.variables.put("prefix_color", this.prefixColor);
|
||||
this.variables.put("level", Integer.toString(this.level));
|
||||
this.variables.put("auto_points_amount", Integer.toString(this.diamondsTimerAmount));
|
||||
this.variables.put("auto_credits_amount", Integer.toString(this.creditsTimerAmount));
|
||||
this.variables.put("auto_pixels_amount", Integer.toString(this.pixelsTimerAmount));
|
||||
this.variables.put("auto_gotw_amount", Integer.toString(this.gotwTimerAmount));
|
||||
}
|
||||
|
||||
private String safeString(String value) {
|
||||
return value == null ? "" : value;
|
||||
}
|
||||
|
||||
public boolean hasPermission(String key, boolean isRoomOwner) {
|
||||
if (this.permissions.containsKey(key)) {
|
||||
Permission permission = this.permissions.get(key);
|
||||
|
||||
@@ -0,0 +1,574 @@
|
||||
package com.eu.habbo.habbohotel.rooms;
|
||||
|
||||
import com.eu.habbo.Emulator;
|
||||
import com.eu.habbo.habbohotel.guilds.Guild;
|
||||
import com.eu.habbo.habbohotel.guilds.GuildMember;
|
||||
import com.eu.habbo.habbohotel.guilds.GuildRank;
|
||||
import com.eu.habbo.habbohotel.permissions.Permission;
|
||||
import com.eu.habbo.habbohotel.users.Habbo;
|
||||
import com.eu.habbo.habbohotel.users.HabboInfo;
|
||||
import com.eu.habbo.habbohotel.users.subscriptions.Subscription;
|
||||
import com.eu.habbo.messages.outgoing.catalog.BuildersClubFurniCountComposer;
|
||||
import com.eu.habbo.messages.outgoing.catalog.BuildersClubSubscriptionStatusComposer;
|
||||
import com.eu.habbo.messages.outgoing.generic.alerts.BubbleAlertComposer;
|
||||
import com.eu.habbo.messages.outgoing.generic.alerts.BubbleAlertKeys;
|
||||
import com.eu.habbo.messages.outgoing.generic.alerts.SimpleAlertComposer;
|
||||
import gnu.trove.map.hash.THashMap;
|
||||
import gnu.trove.set.hash.THashSet;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
public class BuildersClubRoomSupport {
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(BuildersClubRoomSupport.class);
|
||||
|
||||
public static final int DEFAULT_TRIAL_FURNI_LIMIT = 50;
|
||||
// Runtime-only owner marker used to display Builders Club furni as virtual/non-user-owned in-room.
|
||||
// The actual DB owner for persistence/FK purposes is tracked separately on the item instance.
|
||||
public static final int VIRTUAL_OWNER_ID = 1;
|
||||
public static final String DISPLAY_OWNER_NAME = "Builders Club";
|
||||
|
||||
public enum SyncResult {
|
||||
UNCHANGED,
|
||||
LOCKED,
|
||||
UNLOCKED
|
||||
}
|
||||
|
||||
private BuildersClubRoomSupport() {
|
||||
}
|
||||
|
||||
public static int getFurniLimit(Habbo habbo) {
|
||||
if (habbo == null) {
|
||||
return DEFAULT_TRIAL_FURNI_LIMIT;
|
||||
}
|
||||
|
||||
return DEFAULT_TRIAL_FURNI_LIMIT + Math.max(0, habbo.getHabboStats().getBuildersClubBonusFurni());
|
||||
}
|
||||
|
||||
public static int getFurniLimit(int userId) {
|
||||
HabboInfo habboInfo = Emulator.getGameEnvironment().getHabboManager().getHabboInfo(userId);
|
||||
|
||||
if (habboInfo == null || habboInfo.getHabboStats() == null) {
|
||||
return DEFAULT_TRIAL_FURNI_LIMIT;
|
||||
}
|
||||
|
||||
return DEFAULT_TRIAL_FURNI_LIMIT + Math.max(0, habboInfo.getHabboStats().getBuildersClubBonusFurni());
|
||||
}
|
||||
|
||||
public static int getMembershipSecondsLeft(int userId) {
|
||||
HabboInfo habboInfo = Emulator.getGameEnvironment().getHabboManager().getHabboInfo(userId);
|
||||
|
||||
if (habboInfo == null || habboInfo.getHabboStats() == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
Subscription subscription = habboInfo.getHabboStats().getSubscription(Subscription.BUILDERS_CLUB);
|
||||
|
||||
if (subscription == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return Math.max(0, subscription.getRemaining());
|
||||
}
|
||||
|
||||
public static boolean hasActiveMembership(int userId) {
|
||||
HabboInfo habboInfo = Emulator.getGameEnvironment().getHabboManager().getHabboInfo(userId);
|
||||
|
||||
return habboInfo != null
|
||||
&& habboInfo.getHabboStats() != null
|
||||
&& habboInfo.getHabboStats().hasSubscription(Subscription.BUILDERS_CLUB);
|
||||
}
|
||||
|
||||
public static int getTrackedFurniCount(int userId) {
|
||||
try (Connection connection = Emulator.getDatabase().getDataSource().getConnection();
|
||||
PreparedStatement statement = connection.prepareStatement("SELECT COUNT(*) FROM builders_club_items WHERE user_id = ? AND room_id > 0")) {
|
||||
statement.setInt(1, userId);
|
||||
|
||||
try (ResultSet set = statement.executeQuery()) {
|
||||
if (set.next()) {
|
||||
return set.getInt(1);
|
||||
}
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
LOGGER.error("Caught SQL exception counting Builders Club furni", e);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static boolean hasTrackedItemsInOwnedRooms(int ownerId) {
|
||||
try (Connection connection = Emulator.getDatabase().getDataSource().getConnection();
|
||||
PreparedStatement statement = connection.prepareStatement("SELECT 1 FROM builders_club_items bci INNER JOIN rooms r ON r.id = bci.room_id WHERE r.owner_id = ? AND bci.room_id > 0 LIMIT 1")) {
|
||||
statement.setInt(1, ownerId);
|
||||
|
||||
try (ResultSet set = statement.executeQuery()) {
|
||||
return set.next();
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
LOGGER.error("Caught SQL exception checking Builders Club room ownership", e);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean roomHasTrackedItems(int roomId) {
|
||||
try (Connection connection = Emulator.getDatabase().getDataSource().getConnection();
|
||||
PreparedStatement statement = connection.prepareStatement("SELECT 1 FROM builders_club_items WHERE room_id = ? LIMIT 1")) {
|
||||
statement.setInt(1, roomId);
|
||||
|
||||
try (ResultSet set = statement.executeQuery()) {
|
||||
return set.next();
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
LOGGER.error("Caught SQL exception checking Builders Club room items", e);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean isTrackedItem(int itemId) {
|
||||
try (Connection connection = Emulator.getDatabase().getDataSource().getConnection();
|
||||
PreparedStatement statement = connection.prepareStatement("SELECT 1 FROM builders_club_items WHERE item_id = ? LIMIT 1")) {
|
||||
statement.setInt(1, itemId);
|
||||
|
||||
try (ResultSet set = statement.executeQuery()) {
|
||||
return set.next();
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
LOGGER.error("Caught SQL exception checking Builders Club tracked item", e);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static int getTrackedUserId(int itemId) {
|
||||
try (Connection connection = Emulator.getDatabase().getDataSource().getConnection();
|
||||
PreparedStatement statement = connection.prepareStatement("SELECT user_id FROM builders_club_items WHERE item_id = ? LIMIT 1")) {
|
||||
statement.setInt(1, itemId);
|
||||
|
||||
try (ResultSet set = statement.executeQuery()) {
|
||||
if (set.next()) {
|
||||
return set.getInt("user_id");
|
||||
}
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
LOGGER.error("Caught SQL exception getting Builders Club tracked user", e);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static boolean hasPlacementVisitors(Room room, Habbo owner) {
|
||||
if (room == null || owner == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (Habbo habbo : room.getHabbos()) {
|
||||
if (habbo == null || habbo.getHabboInfo() == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (habbo.getHabboInfo().getId() == owner.getHabboInfo().getId()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (habbo.hasPermission(Permission.ACC_ENTERANYROOM) || habbo.hasPermission(Permission.ACC_ANYROOMOWNER)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean isPlacementBlockedByVisitors(Habbo habbo) {
|
||||
if (habbo == null || habbo.getHabboInfo() == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (hasActiveMembership(habbo.getHabboInfo().getId())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Room currentRoom = habbo.getHabboInfo().getCurrentRoom();
|
||||
|
||||
if (currentRoom == null || currentRoom.getOwnerId() != habbo.getHabboInfo().getId()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return hasPlacementVisitors(currentRoom, habbo);
|
||||
}
|
||||
|
||||
public static boolean canPlaceInCurrentRoom(Habbo habbo) {
|
||||
if (habbo == null || habbo.getHabboInfo() == null || habbo.getHabboInfo().getCurrentRoom() == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return canPlaceInRoom(habbo, habbo.getHabboInfo().getCurrentRoom());
|
||||
}
|
||||
|
||||
public static boolean canPlaceInRoom(Habbo habbo, Room room) {
|
||||
if (habbo == null || habbo.getHabboInfo() == null || room == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (room.getOwnerId() == habbo.getHabboInfo().getId()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
Room currentRoom = habbo.getHabboInfo().getCurrentRoom();
|
||||
|
||||
if (currentRoom == null || currentRoom.getId() != room.getId()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return canUseGuildPlacementPool(habbo, room);
|
||||
}
|
||||
|
||||
public static int getPlacementPoolUserId(Habbo habbo) {
|
||||
if (habbo == null || habbo.getHabboInfo() == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
Room currentRoom = habbo.getHabboInfo().getCurrentRoom();
|
||||
|
||||
if (currentRoom == null) {
|
||||
return habbo.getHabboInfo().getId();
|
||||
}
|
||||
|
||||
if (currentRoom.getOwnerId() == habbo.getHabboInfo().getId()) {
|
||||
return habbo.getHabboInfo().getId();
|
||||
}
|
||||
|
||||
if (canUseGuildPlacementPool(habbo, currentRoom)) {
|
||||
Guild guild = Emulator.getGameEnvironment().getGuildManager().getGuild(currentRoom.getGuildId());
|
||||
|
||||
if (guild != null && guild.getOwnerId() > 0) {
|
||||
return guild.getOwnerId();
|
||||
}
|
||||
}
|
||||
|
||||
return habbo.getHabboInfo().getId();
|
||||
}
|
||||
|
||||
public static int getPlacementPoolFurniCount(Habbo habbo) {
|
||||
int userId = getPlacementPoolUserId(habbo);
|
||||
|
||||
if (userId <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return getTrackedFurniCount(userId);
|
||||
}
|
||||
|
||||
public static int getPlacementPoolFurniLimit(Habbo habbo) {
|
||||
int userId = getPlacementPoolUserId(habbo);
|
||||
|
||||
if (userId <= 0) {
|
||||
return DEFAULT_TRIAL_FURNI_LIMIT;
|
||||
}
|
||||
|
||||
return getFurniLimit(userId);
|
||||
}
|
||||
|
||||
public static void sendPlacementStatus(Habbo habbo) {
|
||||
if (habbo == null || habbo.getClient() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
habbo.getClient().sendResponse(new BuildersClubFurniCountComposer(getTrackedFurniCount(habbo.getHabboInfo().getId())));
|
||||
habbo.getClient().sendResponse(new BuildersClubSubscriptionStatusComposer(habbo));
|
||||
}
|
||||
|
||||
public static void sendPlacementStatusForPool(Room room, int placementUserId) {
|
||||
if (placementUserId <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
THashSet<Integer> updatedUsers = new THashSet<>();
|
||||
|
||||
if (room != null) {
|
||||
for (Habbo habbo : room.getHabbos()) {
|
||||
if (habbo == null || habbo.getHabboInfo() == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (getPlacementPoolUserId(habbo) != placementUserId) {
|
||||
continue;
|
||||
}
|
||||
|
||||
sendPlacementStatus(habbo);
|
||||
updatedUsers.add(habbo.getHabboInfo().getId());
|
||||
}
|
||||
}
|
||||
|
||||
Habbo placementPoolHabbo = Emulator.getGameEnvironment().getHabboManager().getHabbo(placementUserId);
|
||||
|
||||
if (placementPoolHabbo != null && placementPoolHabbo.getHabboInfo() != null && !updatedUsers.contains(placementPoolHabbo.getHabboInfo().getId())) {
|
||||
sendPlacementStatus(placementPoolHabbo);
|
||||
}
|
||||
}
|
||||
|
||||
public static void sendCurrentRoomPlacementStatus(Room room) {
|
||||
if (room == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Habbo owner = room.getHabbo(room.getOwnerId());
|
||||
|
||||
if (owner == null || owner.getClient() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
owner.getClient().sendResponse(new com.eu.habbo.messages.outgoing.catalog.BuildersClubSubscriptionStatusComposer(owner));
|
||||
}
|
||||
|
||||
private static boolean canUseGuildPlacementPool(Habbo habbo, Room room) {
|
||||
if (habbo == null || room == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Guild guild = resolvePlacementGuild(room);
|
||||
|
||||
if (guild == null || guild.getOwnerId() <= 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean isGuildAdmin = room.getGuildRightLevel(habbo).isEqualOrGreaterThan(RoomRightLevels.GUILD_ADMIN);
|
||||
|
||||
if (!isGuildAdmin) {
|
||||
GuildMember member = Emulator.getGameEnvironment().getGuildManager().getGuildMember(guild.getId(), habbo.getHabboInfo().getId());
|
||||
|
||||
isGuildAdmin = member != null && (member.getRank() == GuildRank.ADMIN || member.getRank() == GuildRank.OWNER);
|
||||
}
|
||||
|
||||
if (!isGuildAdmin) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return hasActiveMembership(habbo.getHabboInfo().getId()) && hasActiveMembership(guild.getOwnerId());
|
||||
}
|
||||
|
||||
private static Guild resolvePlacementGuild(Room room) {
|
||||
int guildId = resolveRoomGuildId(room);
|
||||
|
||||
if (guildId <= 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (room.getGuildId() != guildId) {
|
||||
room.setGuild(guildId);
|
||||
}
|
||||
|
||||
return Emulator.getGameEnvironment().getGuildManager().getGuild(guildId);
|
||||
}
|
||||
|
||||
private static int resolveRoomGuildId(Room room) {
|
||||
if (room == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (room.getGuildId() > 0) {
|
||||
return room.getGuildId();
|
||||
}
|
||||
|
||||
try (Connection connection = Emulator.getDatabase().getDataSource().getConnection();
|
||||
PreparedStatement statement = connection.prepareStatement("SELECT guild_id FROM rooms WHERE id = ? LIMIT 1")) {
|
||||
statement.setInt(1, room.getId());
|
||||
|
||||
try (ResultSet set = statement.executeQuery()) {
|
||||
if (set.next()) {
|
||||
return set.getInt("guild_id");
|
||||
}
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
LOGGER.error("Caught SQL exception resolving Builders Club room guild", e);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static void trackPlacedItem(int itemId, int userId, int roomId) {
|
||||
try (Connection connection = Emulator.getDatabase().getDataSource().getConnection();
|
||||
PreparedStatement statement = connection.prepareStatement("INSERT INTO builders_club_items (item_id, user_id, room_id) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE user_id = VALUES(user_id), room_id = VALUES(room_id)")) {
|
||||
statement.setInt(1, itemId);
|
||||
statement.setInt(2, userId);
|
||||
statement.setInt(3, roomId);
|
||||
statement.executeUpdate();
|
||||
} catch (SQLException e) {
|
||||
LOGGER.error("Caught SQL exception tracking Builders Club item placement", e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void clearTrackedItemRoom(int itemId) {
|
||||
try (Connection connection = Emulator.getDatabase().getDataSource().getConnection();
|
||||
PreparedStatement statement = connection.prepareStatement("UPDATE builders_club_items SET room_id = 0 WHERE item_id = ? LIMIT 1")) {
|
||||
statement.setInt(1, itemId);
|
||||
statement.executeUpdate();
|
||||
} catch (SQLException e) {
|
||||
LOGGER.error("Caught SQL exception clearing Builders Club room assignment", e);
|
||||
}
|
||||
}
|
||||
|
||||
public static void deleteTrackedItem(int itemId) {
|
||||
try (Connection connection = Emulator.getDatabase().getDataSource().getConnection();
|
||||
PreparedStatement statement = connection.prepareStatement("DELETE FROM builders_club_items WHERE item_id = ? LIMIT 1")) {
|
||||
statement.setInt(1, itemId);
|
||||
statement.executeUpdate();
|
||||
} catch (SQLException e) {
|
||||
LOGGER.error("Caught SQL exception deleting Builders Club tracked item", e);
|
||||
}
|
||||
}
|
||||
|
||||
public static SyncResult syncRoom(Room room) {
|
||||
if (room == null) {
|
||||
return SyncResult.UNCHANGED;
|
||||
}
|
||||
|
||||
boolean hasTrackedItems = roomHasTrackedItems(room.getId());
|
||||
boolean hasMembership = hasActiveMembership(room.getOwnerId());
|
||||
|
||||
if (hasTrackedItems && !hasMembership) {
|
||||
return lockRoom(room) ? SyncResult.LOCKED : SyncResult.UNCHANGED;
|
||||
}
|
||||
|
||||
if (room.isBuildersClubTrialLocked() && (!hasTrackedItems || hasMembership)) {
|
||||
return unlockRoom(room) ? SyncResult.UNLOCKED : SyncResult.UNCHANGED;
|
||||
}
|
||||
|
||||
return SyncResult.UNCHANGED;
|
||||
}
|
||||
|
||||
public static int syncOwnedRooms(int ownerId) {
|
||||
int changed = 0;
|
||||
|
||||
try (Connection connection = Emulator.getDatabase().getDataSource().getConnection();
|
||||
PreparedStatement statement = connection.prepareStatement("SELECT id FROM rooms WHERE owner_id = ?")) {
|
||||
statement.setInt(1, ownerId);
|
||||
|
||||
try (ResultSet set = statement.executeQuery()) {
|
||||
while (set.next()) {
|
||||
Room room = Emulator.getGameEnvironment().getRoomManager().loadRoom(set.getInt("id"), false);
|
||||
|
||||
if (syncRoom(room) != SyncResult.UNCHANGED) {
|
||||
changed++;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
LOGGER.error("Caught SQL exception syncing Builders Club rooms", e);
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
public static void sendRoomLockedBubble(int ownerId) {
|
||||
sendBubbleNotification(ownerId, BubbleAlertKeys.BUILDERS_CLUB_ROOM_LOCKED, null);
|
||||
}
|
||||
|
||||
public static void sendRoomUnlockedBubble(int ownerId) {
|
||||
sendBubbleNotification(ownerId, BubbleAlertKeys.BUILDERS_CLUB_ROOM_UNLOCKED, null);
|
||||
}
|
||||
|
||||
public static void sendMembershipMadeBubble(int userId) {
|
||||
sendBubbleNotification(userId, BubbleAlertKeys.BUILDERS_CLUB_MEMBERSHIP_MADE, null);
|
||||
}
|
||||
|
||||
public static void sendMembershipExtendedBubble(int userId) {
|
||||
sendBubbleNotification(userId, BubbleAlertKeys.BUILDERS_CLUB_MEMBERSHIP_EXTENDED, null);
|
||||
}
|
||||
|
||||
public static void sendVisitDeniedOwnerBubble(int ownerId, String username) {
|
||||
THashMap<String, String> keys = new THashMap<>();
|
||||
keys.put("USERNAME", username);
|
||||
|
||||
sendBubbleNotification(ownerId, BubbleAlertKeys.BUILDERS_CLUB_VISIT_DENIED_OWNER, keys);
|
||||
}
|
||||
|
||||
public static void sendVisitDeniedVisitorAlert(int userId) {
|
||||
sendSimpleAlert(userId, "notification.builders_club.visit_denied_for_visitor.message");
|
||||
}
|
||||
|
||||
public static void sendMembershipExpiringAlert(int userId) {
|
||||
sendSimpleAlert(userId, "expiring.bc.membership.description");
|
||||
}
|
||||
|
||||
public static void sendMembershipExpiredAlert(int userId, boolean hasTrackedRooms) {
|
||||
sendSimpleAlert(
|
||||
userId,
|
||||
hasTrackedRooms
|
||||
? "notification.builders_club.membership_expired.message"
|
||||
: "notification.builders_club.membership_expired.message_no_rooms"
|
||||
);
|
||||
}
|
||||
|
||||
private static void sendBubbleNotification(int userId, BubbleAlertKeys key, THashMap<String, String> keys) {
|
||||
Habbo habbo = Emulator.getGameEnvironment().getHabboManager().getHabbo(userId);
|
||||
|
||||
if (habbo == null || habbo.getClient() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (keys == null) {
|
||||
habbo.getClient().sendResponse(new BubbleAlertComposer(key.key));
|
||||
return;
|
||||
}
|
||||
|
||||
habbo.getClient().sendResponse(new BubbleAlertComposer(key.key, keys));
|
||||
}
|
||||
|
||||
private static void sendSimpleAlert(int userId, String messageKey) {
|
||||
Habbo habbo = Emulator.getGameEnvironment().getHabboManager().getHabbo(userId);
|
||||
|
||||
if (habbo == null || habbo.getClient() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
habbo.getClient().sendResponse(new SimpleAlertComposer(messageKey));
|
||||
}
|
||||
|
||||
private static boolean lockRoom(Room room) {
|
||||
if (room.isBuildersClubTrialLocked()) {
|
||||
if (room.getState() != RoomState.INVISIBLE) {
|
||||
room.setState(RoomState.INVISIBLE);
|
||||
room.setNeedsUpdate(true);
|
||||
room.save();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
room.setBuildersClubOriginalState(room.getState());
|
||||
room.setBuildersClubTrialLocked(true);
|
||||
room.setState(RoomState.INVISIBLE);
|
||||
room.setNeedsUpdate(true);
|
||||
room.save();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static boolean unlockRoom(Room room) {
|
||||
if (!room.isBuildersClubTrialLocked()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RoomState originalState = room.getBuildersClubOriginalState();
|
||||
|
||||
if (originalState == null) {
|
||||
originalState = RoomState.OPEN;
|
||||
}
|
||||
|
||||
room.setState(originalState);
|
||||
room.setBuildersClubTrialLocked(false);
|
||||
room.setBuildersClubOriginalState(originalState);
|
||||
room.setNeedsUpdate(true);
|
||||
room.save();
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import com.eu.habbo.habbohotel.bots.Bot;
|
||||
import com.eu.habbo.habbohotel.games.Game;
|
||||
import com.eu.habbo.habbohotel.guilds.Guild;
|
||||
import com.eu.habbo.habbohotel.guilds.GuildMember;
|
||||
import com.eu.habbo.habbohotel.guilds.GuildRank;
|
||||
import com.eu.habbo.habbohotel.items.FurnitureType;
|
||||
import com.eu.habbo.habbohotel.items.Item;
|
||||
import com.eu.habbo.habbohotel.items.interactions.*;
|
||||
@@ -30,6 +31,7 @@ import com.eu.habbo.messages.outgoing.rooms.UpdateStackHeightComposer;
|
||||
import com.eu.habbo.messages.outgoing.rooms.items.*;
|
||||
import com.eu.habbo.messages.outgoing.rooms.users.RoomUserIgnoredComposer;
|
||||
import com.eu.habbo.messages.outgoing.rooms.users.RoomUserStatusComposer;
|
||||
import com.eu.habbo.messages.outgoing.wired.WiredRoomSettingsDataComposer;
|
||||
import com.eu.habbo.plugin.Event;
|
||||
import com.eu.habbo.plugin.events.furniture.FurniturePickedUpEvent;
|
||||
import com.eu.habbo.plugin.events.rooms.RoomLoadedEvent;
|
||||
@@ -75,6 +77,9 @@ public class Room implements Comparable<Room>, ISerialize, Runnable {
|
||||
private RoomRollerManager rollerManager;
|
||||
private RoomMessagingManager messagingManager;
|
||||
private RoomCycleManager cycleManager;
|
||||
private RoomUserVariableManager userVariableManager;
|
||||
private RoomFurniVariableManager furniVariableManager;
|
||||
private RoomVariableManager roomVariableManager;
|
||||
|
||||
public static final Comparator<Room> SORT_SCORE = (o1, o2) -> o2.getScore() - o1.getScore();
|
||||
public static final Comparator<Room> SORT_ID = (o1, o2) -> o2.getId() - o1.getId();
|
||||
@@ -92,6 +97,14 @@ public class Room implements Comparable<Room>, ISerialize, Runnable {
|
||||
public static int ROLLERS_MAXIMUM_ROLL_AVATARS = 1;
|
||||
public static boolean MUTEAREA_CAN_WHISPER = false;
|
||||
public static double MAXIMUM_FURNI_HEIGHT = 40d;
|
||||
public static final int WIRED_ACCESS_EVERYONE = 1;
|
||||
public static final int WIRED_ACCESS_USERS_WITH_RIGHTS = 2;
|
||||
public static final int WIRED_ACCESS_GROUP_MEMBERS = 4;
|
||||
public static final int WIRED_ACCESS_GROUP_ADMINS = 8;
|
||||
public static final int WIRED_ACCESS_ALLOWED_INSPECT_MASK = WIRED_ACCESS_EVERYONE | WIRED_ACCESS_USERS_WITH_RIGHTS | WIRED_ACCESS_GROUP_MEMBERS | WIRED_ACCESS_GROUP_ADMINS;
|
||||
public static final int WIRED_ACCESS_ALLOWED_MODIFY_MASK = WIRED_ACCESS_USERS_WITH_RIGHTS | WIRED_ACCESS_GROUP_MEMBERS | WIRED_ACCESS_GROUP_ADMINS;
|
||||
public static final int WIRED_ACCESS_DEFAULT_INSPECT_MASK = 0;
|
||||
public static final int WIRED_ACCESS_DEFAULT_MODIFY_MASK = 0;
|
||||
|
||||
static {
|
||||
for (int i = 1; i <= 3; i++) {
|
||||
@@ -164,6 +177,8 @@ public class Room implements Comparable<Room>, ISerialize, Runnable {
|
||||
private boolean allowUnderpass;
|
||||
private boolean jukeboxActive;
|
||||
private boolean hideWired;
|
||||
private boolean buildersClubTrialLocked;
|
||||
private RoomState buildersClubOriginalState;
|
||||
private RoomPromotion promotion;
|
||||
private volatile boolean needsUpdate;
|
||||
private volatile boolean loaded;
|
||||
@@ -175,9 +190,10 @@ public class Room implements Comparable<Room>, ISerialize, Runnable {
|
||||
private volatile boolean muted;
|
||||
private RoomSpecialTypes roomSpecialTypes;
|
||||
private TraxManager traxManager;
|
||||
|
||||
// YouTube room broadcast state: tracks the current video being broadcast
|
||||
// by the room owner, the owner's playlist, and which users have the player open.
|
||||
private final Object wiredSettingsLock = new Object();
|
||||
private volatile boolean wiredSettingsLoaded;
|
||||
private int wiredInspectMask = WIRED_ACCESS_DEFAULT_INSPECT_MASK;
|
||||
private int wiredModifyMask = WIRED_ACCESS_DEFAULT_MODIFY_MASK;
|
||||
private boolean youtubeEnabled = false;
|
||||
private String youtubeCurrentVideo = "";
|
||||
private String youtubeSenderName = "";
|
||||
@@ -248,6 +264,19 @@ public class Room implements Comparable<Room>, ISerialize, Runnable {
|
||||
this.promoted = set.getString("promoted").equals("1");
|
||||
this.jukeboxActive = set.getString("jukebox_active").equals("1");
|
||||
this.hideWired = set.getString("hidewired").equals("1");
|
||||
this.buildersClubTrialLocked = set.getBoolean("builders_club_trial_locked");
|
||||
|
||||
String buildersClubOriginalState = set.getString("builders_club_original_state");
|
||||
|
||||
if (buildersClubOriginalState != null && !buildersClubOriginalState.isEmpty()) {
|
||||
try {
|
||||
this.buildersClubOriginalState = RoomState.valueOf(buildersClubOriginalState.toUpperCase());
|
||||
} catch (IllegalArgumentException e) {
|
||||
this.buildersClubOriginalState = RoomState.OPEN;
|
||||
}
|
||||
} else {
|
||||
this.buildersClubOriginalState = RoomState.OPEN;
|
||||
}
|
||||
|
||||
this.bannedHabbos = new TIntObjectHashMap<>();
|
||||
|
||||
@@ -298,6 +327,9 @@ public class Room implements Comparable<Room>, ISerialize, Runnable {
|
||||
this.rollerManager = new RoomRollerManager(this);
|
||||
this.messagingManager = new RoomMessagingManager(this);
|
||||
this.cycleManager = new RoomCycleManager(this);
|
||||
this.userVariableManager = new RoomUserVariableManager(this);
|
||||
this.furniVariableManager = new RoomFurniVariableManager(this);
|
||||
this.roomVariableManager = new RoomVariableManager(this);
|
||||
}
|
||||
|
||||
// ==================== MANAGER GETTERS ====================
|
||||
@@ -379,6 +411,18 @@ public class Room implements Comparable<Room>, ISerialize, Runnable {
|
||||
return this.cycleManager;
|
||||
}
|
||||
|
||||
public RoomUserVariableManager getUserVariableManager() {
|
||||
return this.userVariableManager;
|
||||
}
|
||||
|
||||
public RoomFurniVariableManager getFurniVariableManager() {
|
||||
return this.furniVariableManager;
|
||||
}
|
||||
|
||||
public RoomVariableManager getRoomVariableManager() {
|
||||
return this.roomVariableManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the roller manager for this room.
|
||||
*/
|
||||
@@ -778,6 +822,8 @@ public class Room implements Comparable<Room>, ISerialize, Runnable {
|
||||
return;
|
||||
}
|
||||
|
||||
boolean trackedBuildersClubItem = BuildersClubRoomSupport.isTrackedItem(item.getId());
|
||||
|
||||
if (Emulator.getPluginManager().isRegistered(FurniturePickedUpEvent.class, true)) {
|
||||
Event furniturePickedUpEvent = new FurniturePickedUpEvent(item, picker);
|
||||
Emulator.getPluginManager().fireEvent(furniturePickedUpEvent);
|
||||
@@ -820,9 +866,14 @@ public class Room implements Comparable<Room>, ISerialize, Runnable {
|
||||
this.sendComposer(new RemoveWallItemComposer(item).compose());
|
||||
}
|
||||
|
||||
if (trackedBuildersClubItem) {
|
||||
Emulator.getGameEnvironment().getItemManager().deleteItem(item);
|
||||
return;
|
||||
}
|
||||
|
||||
Habbo habbo = (picker != null && picker.getHabboInfo().getId() == item.getId() ? picker
|
||||
: Emulator.getGameServer().getGameClientManager().getHabbo(item.getUserId()));
|
||||
if (habbo != null) {
|
||||
if (!trackedBuildersClubItem && habbo != null) {
|
||||
habbo.getInventory().getItemsComponent().addItem(item);
|
||||
habbo.getClient().sendResponse(new AddHabboItemComposer(item));
|
||||
habbo.getClient().sendResponse(new InventoryRefreshComposer());
|
||||
@@ -953,13 +1004,13 @@ public class Room implements Comparable<Room>, ISerialize, Runnable {
|
||||
|
||||
this.itemManager.saveAllPendingItems();
|
||||
|
||||
// Unregister all wired tickables for this room from the tick service
|
||||
com.eu.habbo.habbohotel.wired.core.WiredManager.unregisterRoomTickables(this);
|
||||
|
||||
if (this.roomSpecialTypes != null) {
|
||||
this.roomSpecialTypes.dispose();
|
||||
}
|
||||
|
||||
// Unregister all wired tickables for this room from the tick service
|
||||
com.eu.habbo.habbohotel.wired.core.WiredManager.unregisterRoomTickables(this);
|
||||
|
||||
// Clear wired engine caches for this room
|
||||
if (com.eu.habbo.habbohotel.wired.core.WiredManager.getStackIndex() != null) {
|
||||
com.eu.habbo.habbohotel.wired.core.WiredManager.getStackIndex().invalidateAll(this);
|
||||
@@ -967,6 +1018,8 @@ public class Room implements Comparable<Room>, ISerialize, Runnable {
|
||||
if (com.eu.habbo.habbohotel.wired.core.WiredManager.getEngine() != null) {
|
||||
com.eu.habbo.habbohotel.wired.core.WiredManager.getEngine().clearRoomRecursionDepth(this.id);
|
||||
com.eu.habbo.habbohotel.wired.core.WiredManager.getEngine().clearRoomRateLimiters(this.id);
|
||||
com.eu.habbo.habbohotel.wired.core.WiredManager.getEngine().clearRoomBan(this.id);
|
||||
com.eu.habbo.habbohotel.wired.core.WiredManager.getEngine().clearRoomDiagnostics(this.id);
|
||||
}
|
||||
|
||||
this.itemManager.clear();
|
||||
@@ -1292,6 +1345,22 @@ public class Room implements Comparable<Room>, ISerialize, Runnable {
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
public boolean isBuildersClubTrialLocked() {
|
||||
return this.buildersClubTrialLocked;
|
||||
}
|
||||
|
||||
public void setBuildersClubTrialLocked(boolean buildersClubTrialLocked) {
|
||||
this.buildersClubTrialLocked = buildersClubTrialLocked;
|
||||
}
|
||||
|
||||
public RoomState getBuildersClubOriginalState() {
|
||||
return this.buildersClubOriginalState;
|
||||
}
|
||||
|
||||
public void setBuildersClubOriginalState(RoomState buildersClubOriginalState) {
|
||||
this.buildersClubOriginalState = buildersClubOriginalState;
|
||||
}
|
||||
|
||||
public int getUsersMax() {
|
||||
return this.usersMax;
|
||||
}
|
||||
@@ -1391,11 +1460,28 @@ public class Room implements Comparable<Room>, ISerialize, Runnable {
|
||||
}
|
||||
|
||||
public int getGuildId() {
|
||||
if (this.guild > 0) {
|
||||
return this.guild;
|
||||
}
|
||||
|
||||
try (Connection connection = Emulator.getDatabase().getDataSource().getConnection();
|
||||
PreparedStatement statement = connection.prepareStatement("SELECT guild_id FROM rooms WHERE id = ? LIMIT 1")) {
|
||||
statement.setInt(1, this.id);
|
||||
|
||||
try (ResultSet set = statement.executeQuery()) {
|
||||
if (set.next()) {
|
||||
this.guild = set.getInt("guild_id");
|
||||
}
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
LOGGER.error("Caught SQL exception resolving room guild", e);
|
||||
}
|
||||
|
||||
return this.guild;
|
||||
}
|
||||
|
||||
public boolean hasGuild() {
|
||||
return this.guild != 0;
|
||||
return this.getGuildId() != 0;
|
||||
}
|
||||
|
||||
public void setGuild(int guild) {
|
||||
@@ -2143,11 +2229,18 @@ public class Room implements Comparable<Room>, ISerialize, Runnable {
|
||||
}
|
||||
|
||||
public RoomRightLevels getGuildRightLevel(Habbo habbo) {
|
||||
if (this.guild > 0 && habbo.getHabboStats().hasGuild(this.guild)) {
|
||||
Guild guild = Emulator.getGameEnvironment().getGuildManager().getGuild(this.guild);
|
||||
int guildId = this.getGuildId();
|
||||
|
||||
if (Emulator.getGameEnvironment().getGuildManager().getOnlyAdmins(guild)
|
||||
.get(habbo.getHabboInfo().getId()) != null) {
|
||||
if (guildId > 0 && habbo != null && habbo.getHabboInfo() != null) {
|
||||
Guild guild = Emulator.getGameEnvironment().getGuildManager().getGuild(guildId);
|
||||
|
||||
if (guild == null) {
|
||||
return RoomRightLevels.NONE;
|
||||
}
|
||||
|
||||
GuildMember member = Emulator.getGameEnvironment().getGuildManager().getGuildMember(guild.getId(), habbo.getHabboInfo().getId());
|
||||
|
||||
if ((member != null) && (member.getRank() == GuildRank.ADMIN || member.getRank() == GuildRank.OWNER)) {
|
||||
return RoomRightLevels.GUILD_ADMIN;
|
||||
}
|
||||
|
||||
@@ -2175,20 +2268,108 @@ public class Room implements Comparable<Room>, ISerialize, Runnable {
|
||||
return this.rightsManager.hasRights(habbo);
|
||||
}
|
||||
|
||||
public boolean hasExplicitRights(Habbo habbo) {
|
||||
return habbo != null && this.rights.contains(habbo.getHabboInfo().getId());
|
||||
}
|
||||
|
||||
public int getWiredInspectMask() {
|
||||
this.ensureWiredSettingsLoaded();
|
||||
return this.wiredInspectMask;
|
||||
}
|
||||
|
||||
public int getWiredModifyMask() {
|
||||
this.ensureWiredSettingsLoaded();
|
||||
return this.wiredModifyMask;
|
||||
}
|
||||
|
||||
public boolean canInspectWired(Habbo habbo) {
|
||||
if (habbo == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.canManageWiredSettings(habbo)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
this.ensureWiredSettingsLoaded();
|
||||
return this.matchesWiredAccessMask(habbo, this.wiredInspectMask, true);
|
||||
}
|
||||
|
||||
public boolean canModifyWired(Habbo habbo) {
|
||||
if (habbo == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.canManageWiredSettings(habbo)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
this.ensureWiredSettingsLoaded();
|
||||
return this.matchesWiredAccessMask(habbo, this.wiredModifyMask, false);
|
||||
}
|
||||
|
||||
public boolean canManageWiredSettings(Habbo habbo) {
|
||||
return habbo != null && this.isOwner(habbo);
|
||||
}
|
||||
|
||||
public boolean saveWiredSettings(int inspectMask, int modifyMask) {
|
||||
int sanitizedInspectMask = sanitizeWiredInspectMask(inspectMask);
|
||||
int sanitizedModifyMask = sanitizeWiredModifyMask(modifyMask);
|
||||
sanitizedInspectMask |= sanitizedModifyMask;
|
||||
|
||||
synchronized (this.wiredSettingsLock) {
|
||||
int previousInspectMask = this.wiredInspectMask;
|
||||
int previousModifyMask = this.wiredModifyMask;
|
||||
this.wiredInspectMask = sanitizedInspectMask;
|
||||
this.wiredModifyMask = sanitizedModifyMask;
|
||||
this.wiredSettingsLoaded = true;
|
||||
|
||||
try (Connection connection = Emulator.getDatabase().getDataSource().getConnection();
|
||||
PreparedStatement statement = connection.prepareStatement(
|
||||
"INSERT INTO room_wired_settings (room_id, inspect_mask, modify_mask) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE inspect_mask = VALUES(inspect_mask), modify_mask = VALUES(modify_mask)")) {
|
||||
statement.setInt(1, this.id);
|
||||
statement.setInt(2, sanitizedInspectMask);
|
||||
statement.setInt(3, sanitizedModifyMask);
|
||||
statement.executeUpdate();
|
||||
this.pushWiredSettingsToCurrentHabbos();
|
||||
return true;
|
||||
} catch (SQLException e) {
|
||||
this.wiredInspectMask = previousInspectMask;
|
||||
this.wiredModifyMask = previousModifyMask;
|
||||
LOGGER.error("Caught SQL exception while saving wired room settings", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void giveRights(Habbo habbo) {
|
||||
this.rightsManager.giveRights(habbo);
|
||||
if (habbo == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.giveRights(habbo.getHabboInfo().getId());
|
||||
}
|
||||
|
||||
public void giveRights(int userId) {
|
||||
this.rightsManager.giveRights(userId);
|
||||
|
||||
if (!this.rights.contains(userId)) {
|
||||
this.rights.add(userId);
|
||||
}
|
||||
|
||||
this.pushWiredSettingsToCurrentHabbos();
|
||||
}
|
||||
|
||||
public void removeRights(int userId) {
|
||||
this.rightsManager.removeRights(userId);
|
||||
this.rights.remove(userId);
|
||||
this.pushWiredSettingsToCurrentHabbos();
|
||||
}
|
||||
|
||||
public void removeAllRights() {
|
||||
this.rightsManager.removeAllRights();
|
||||
this.rights.clear();
|
||||
this.pushWiredSettingsToCurrentHabbos();
|
||||
}
|
||||
|
||||
void refreshRightsInRoom() {
|
||||
@@ -2215,6 +2396,111 @@ public class Room implements Comparable<Room>, ISerialize, Runnable {
|
||||
return this.bannedHabbos;
|
||||
}
|
||||
|
||||
private void ensureWiredSettingsLoaded() {
|
||||
if (this.wiredSettingsLoaded) {
|
||||
return;
|
||||
}
|
||||
|
||||
synchronized (this.wiredSettingsLock) {
|
||||
if (this.wiredSettingsLoaded) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.wiredInspectMask = WIRED_ACCESS_DEFAULT_INSPECT_MASK;
|
||||
this.wiredModifyMask = WIRED_ACCESS_DEFAULT_MODIFY_MASK;
|
||||
|
||||
try (Connection connection = Emulator.getDatabase().getDataSource().getConnection();
|
||||
PreparedStatement statement = connection.prepareStatement(
|
||||
"SELECT inspect_mask, modify_mask FROM room_wired_settings WHERE room_id = ? LIMIT 1")) {
|
||||
statement.setInt(1, this.id);
|
||||
|
||||
try (ResultSet set = statement.executeQuery()) {
|
||||
if (set.next()) {
|
||||
this.wiredInspectMask = sanitizeWiredInspectMask(set.getInt("inspect_mask"));
|
||||
this.wiredModifyMask = sanitizeWiredModifyMask(set.getInt("modify_mask"));
|
||||
}
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
LOGGER.error("Caught SQL exception while loading wired room settings", e);
|
||||
}
|
||||
|
||||
this.wiredSettingsLoaded = true;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean matchesWiredAccessMask(Habbo habbo, int mask, boolean allowEveryone) {
|
||||
if (habbo == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (allowEveryone && hasWiredAccess(mask, WIRED_ACCESS_EVERYONE)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (hasWiredAccess(mask, WIRED_ACCESS_USERS_WITH_RIGHTS) && this.hasExplicitRights(habbo)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (hasWiredAccess(mask, WIRED_ACCESS_GROUP_ADMINS) && this.isRoomGroupAdmin(habbo)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return hasWiredAccess(mask, WIRED_ACCESS_GROUP_MEMBERS) && this.isRoomGroupMember(habbo);
|
||||
}
|
||||
|
||||
private boolean isRoomGroupMember(Habbo habbo) {
|
||||
return habbo != null && this.guild > 0 && habbo.getHabboStats().hasGuild(this.guild);
|
||||
}
|
||||
|
||||
private boolean isRoomGroupAdmin(Habbo habbo) {
|
||||
if (!this.isRoomGroupMember(habbo)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
GuildMember member = Emulator.getGameEnvironment().getGuildManager().getGuildMember(this.guild, habbo.getHabboInfo().getId());
|
||||
|
||||
if (member == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
GuildRank rank = member.getRank();
|
||||
return rank == GuildRank.OWNER || rank == GuildRank.ADMIN;
|
||||
}
|
||||
|
||||
private static boolean hasWiredAccess(int mask, int permissionMask) {
|
||||
return (mask & permissionMask) != 0;
|
||||
}
|
||||
|
||||
private static int sanitizeWiredInspectMask(int mask) {
|
||||
int sanitizedMask = mask & WIRED_ACCESS_ALLOWED_INSPECT_MASK;
|
||||
|
||||
if (hasWiredAccess(sanitizedMask, WIRED_ACCESS_GROUP_MEMBERS)) {
|
||||
sanitizedMask |= WIRED_ACCESS_GROUP_ADMINS;
|
||||
}
|
||||
|
||||
return sanitizedMask;
|
||||
}
|
||||
|
||||
private static int sanitizeWiredModifyMask(int mask) {
|
||||
int sanitizedMask = mask & WIRED_ACCESS_ALLOWED_MODIFY_MASK;
|
||||
|
||||
if (hasWiredAccess(sanitizedMask, WIRED_ACCESS_GROUP_MEMBERS)) {
|
||||
sanitizedMask |= WIRED_ACCESS_GROUP_ADMINS;
|
||||
}
|
||||
|
||||
return sanitizedMask;
|
||||
}
|
||||
|
||||
private void pushWiredSettingsToCurrentHabbos() {
|
||||
for (Habbo currentHabbo : this.getCurrentHabbos().values()) {
|
||||
if (currentHabbo == null || currentHabbo.getClient() == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
currentHabbo.getClient().sendResponse(new WiredRoomSettingsDataComposer(this, currentHabbo));
|
||||
}
|
||||
}
|
||||
|
||||
public void addRoomBan(RoomBan roomBan) {
|
||||
this.rightsManager.addRoomBan(roomBan);
|
||||
}
|
||||
@@ -2279,29 +2565,38 @@ public class Room implements Comparable<Room>, ISerialize, Runnable {
|
||||
}
|
||||
|
||||
public void updateItem(HabboItem item) {
|
||||
if (this.isLoaded()) {
|
||||
if (item != null && item.getRoomId() == this.id) {
|
||||
if (item.getBaseItem() != null) {
|
||||
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()));
|
||||
} else if (item.getBaseItem().getType() == FurnitureType.WALL) {
|
||||
this.sendComposer(new WallItemUpdateComposer(item).compose());
|
||||
if (this.isLoaded()) {
|
||||
if (item != null && item.getRoomId() == this.id) {
|
||||
if (item.getBaseItem() != null) {
|
||||
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()));
|
||||
|
||||
if (RoomAreaHideSupport.isControllerItem(item)) {
|
||||
RoomAreaHideSupport.sendState(this, item);
|
||||
}
|
||||
} else if (item.getBaseItem().getType() == FurnitureType.WALL) {
|
||||
this.sendComposer(new WallItemUpdateComposer(item).compose());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void updateItemState(HabboItem item) {
|
||||
if (!item.isLimited()) {
|
||||
this.sendComposer(new ItemStateComposer(item).compose());
|
||||
} else {
|
||||
this.sendComposer(new FloorItemUpdateComposer(item).compose());
|
||||
}
|
||||
if (item != null && RoomAreaHideSupport.isControllerItem(item)) {
|
||||
this.updateItem(item);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!item.isLimited()) {
|
||||
this.sendComposer(new ItemStateComposer(item).compose());
|
||||
} else {
|
||||
this.sendComposer(new FloorItemUpdateComposer(item).compose());
|
||||
}
|
||||
|
||||
if (item.getBaseItem().getType() == FurnitureType.FLOOR) {
|
||||
if (this.layout == null) {
|
||||
@@ -2316,6 +2611,16 @@ public class Room implements Comparable<Room>, ISerialize, Runnable {
|
||||
((InteractionMultiHeight) item).updateUnitsOnItem(this);
|
||||
}
|
||||
}
|
||||
|
||||
if (item.getBaseItem().getType() == FurnitureType.FLOOR
|
||||
&& (RoomConfInvisSupport.isControllerItem(item) || RoomConfInvisSupport.isTarget(item))) {
|
||||
RoomConfInvisSupport.sendState(this);
|
||||
}
|
||||
|
||||
if (item.getBaseItem().getType() == FurnitureType.FLOOR
|
||||
&& RoomHanditemBlockSupport.isControllerItem(item)) {
|
||||
RoomHanditemBlockSupport.sendState(this);
|
||||
}
|
||||
}
|
||||
|
||||
public int getUserFurniCount(int userId) {
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
package com.eu.habbo.habbohotel.rooms;
|
||||
|
||||
import com.eu.habbo.habbohotel.gameclients.GameClient;
|
||||
import com.eu.habbo.habbohotel.items.FurnitureType;
|
||||
import com.eu.habbo.habbohotel.items.interactions.InteractionAreaHideControl;
|
||||
import com.eu.habbo.habbohotel.users.HabboItem;
|
||||
import com.eu.habbo.messages.outgoing.rooms.items.AreaHideComposer;
|
||||
|
||||
public final class RoomAreaHideSupport {
|
||||
private RoomAreaHideSupport() {
|
||||
}
|
||||
|
||||
public static boolean isControllerItem(HabboItem item) {
|
||||
return item instanceof InteractionAreaHideControl
|
||||
|| hasInteractionName(item, "wf_conf_area_hide")
|
||||
|| hasInteractionName(item, "conf_area_hide");
|
||||
}
|
||||
|
||||
public static boolean isControllerActive(HabboItem item) {
|
||||
return isControllerItem(item) && getState(item) == 1;
|
||||
}
|
||||
|
||||
public static int getState(HabboItem item) {
|
||||
return Math.min(1, readIntValue(item, "state", 0));
|
||||
}
|
||||
|
||||
public static int getRootX(HabboItem item) {
|
||||
return readIntValue(item, "rootX", 0);
|
||||
}
|
||||
|
||||
public static int getRootY(HabboItem item) {
|
||||
return readIntValue(item, "rootY", 0);
|
||||
}
|
||||
|
||||
public static int getWidth(HabboItem item) {
|
||||
return readIntValue(item, "width", 0);
|
||||
}
|
||||
|
||||
public static int getLength(HabboItem item) {
|
||||
return readIntValue(item, "length", 0);
|
||||
}
|
||||
|
||||
public static boolean isInvisibilityEnabled(HabboItem item) {
|
||||
return readIntValue(item, "invisibility", 0) == 1;
|
||||
}
|
||||
|
||||
public static boolean includesWallItems(HabboItem item) {
|
||||
return readIntValue(item, "wallItems", 0) == 1;
|
||||
}
|
||||
|
||||
public static boolean isInverted(HabboItem item) {
|
||||
return readIntValue(item, "invert", 0) == 1;
|
||||
}
|
||||
|
||||
public static void sendState(Room room, HabboItem item) {
|
||||
if (room == null || item == null || !isControllerItem(item)) {
|
||||
return;
|
||||
}
|
||||
|
||||
room.sendComposer(new AreaHideComposer(item).compose());
|
||||
}
|
||||
|
||||
public static void sendState(Room room, GameClient client) {
|
||||
if (room == null || client == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (HabboItem item : room.getFloorItems()) {
|
||||
if (!isControllerActive(item)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
client.sendResponse(new AreaHideComposer(item).compose());
|
||||
}
|
||||
}
|
||||
|
||||
private static int readIntValue(HabboItem item, String key, int fallback) {
|
||||
if (!(item instanceof InteractionAreaHideControl) || key == null) {
|
||||
return fallback;
|
||||
}
|
||||
|
||||
InteractionAreaHideControl areaHide = (InteractionAreaHideControl) item;
|
||||
String value = areaHide.values.get(key);
|
||||
|
||||
try {
|
||||
return Math.max(0, Integer.parseInt(value));
|
||||
} catch (Exception ignored) {
|
||||
return fallback;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean hasInteractionName(HabboItem item, String interactionName) {
|
||||
return item != null
|
||||
&& item.getBaseItem() != null
|
||||
&& item.getBaseItem().getType() == FurnitureType.FLOOR
|
||||
&& item.getBaseItem().getInteractionType() != null
|
||||
&& item.getBaseItem().getInteractionType().getName() != null
|
||||
&& item.getBaseItem().getInteractionType().getName().equalsIgnoreCase(interactionName);
|
||||
}
|
||||
}
|
||||
@@ -328,7 +328,9 @@ public class RoomChatManager {
|
||||
suppressSaysOutput = WiredManager.shouldSuppressUserSaysOutput(
|
||||
habbo.getHabboInfo().getCurrentRoom(),
|
||||
habbo.getRoomUnit(),
|
||||
wiredSayMessage);
|
||||
wiredSayMessage,
|
||||
chatType.ordinal(),
|
||||
roomChatMessage.getBubble() != null ? roomChatMessage.getBubble().getType() : -1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -407,7 +409,12 @@ public class RoomChatManager {
|
||||
}
|
||||
|
||||
if (chatType != RoomChatType.WHISPER && !ignoreWired && !roomChatMessage.isCommand) {
|
||||
WiredManager.triggerUserSays(habbo.getHabboInfo().getCurrentRoom(), habbo.getRoomUnit(), wiredSayMessage);
|
||||
WiredManager.triggerUserSays(
|
||||
habbo.getHabboInfo().getCurrentRoom(),
|
||||
habbo.getRoomUnit(),
|
||||
wiredSayMessage,
|
||||
chatType.ordinal(),
|
||||
roomChatMessage.getBubble() != null ? roomChatMessage.getBubble().getType() : -1);
|
||||
}
|
||||
|
||||
// Notify bots and talking furniture
|
||||
|
||||
@@ -52,14 +52,14 @@ public class RoomChatMessageBubbles {
|
||||
public static final RoomChatMessageBubbles UNKNOWN_43 = new RoomChatMessageBubbles(43, "UNKNOWN_43", "", true, false);
|
||||
public static final RoomChatMessageBubbles UNKNOWN_44 = new RoomChatMessageBubbles(44, "UNKNOWN_44", "", true, false);
|
||||
public static final RoomChatMessageBubbles UNKNOWN_45 = new RoomChatMessageBubbles(45, "UNKNOWN_45", "", true, false);
|
||||
public static final RoomChatMessageBubbles UNKNOWN_46 = new RoomChatMessageBubbles(45, "UNKNOWN_46", "", true, false);
|
||||
public static final RoomChatMessageBubbles UNKNOWN_47 = new RoomChatMessageBubbles(45, "UNKNOWN_47", "", true, false);
|
||||
public static final RoomChatMessageBubbles UNKNOWN_48 = new RoomChatMessageBubbles(45, "UNKNOWN_48", "", true, false);
|
||||
public static final RoomChatMessageBubbles UNKNOWN_49 = new RoomChatMessageBubbles(45, "UNKNOWN_49", "", true, false);
|
||||
public static final RoomChatMessageBubbles UNKNOWN_50 = new RoomChatMessageBubbles(45, "UNKNOWN_50", "", true, false);
|
||||
public static final RoomChatMessageBubbles UNKNOWN_51 = new RoomChatMessageBubbles(45, "UNKNOWN_51", "", true, false);
|
||||
public static final RoomChatMessageBubbles UNKNOWN_52 = new RoomChatMessageBubbles(45, "UNKNOWN_52", "", true, false);
|
||||
public static final RoomChatMessageBubbles UNKNOWN_53 = new RoomChatMessageBubbles(45, "UNKNOWN_53", "", true, false);
|
||||
public static final RoomChatMessageBubbles UNKNOWN_46 = new RoomChatMessageBubbles(46, "UNKNOWN_46", "", true, false);
|
||||
public static final RoomChatMessageBubbles UNKNOWN_47 = new RoomChatMessageBubbles(47, "UNKNOWN_47", "", true, false);
|
||||
public static final RoomChatMessageBubbles UNKNOWN_48 = new RoomChatMessageBubbles(48, "UNKNOWN_48", "", true, false);
|
||||
public static final RoomChatMessageBubbles UNKNOWN_49 = new RoomChatMessageBubbles(49, "UNKNOWN_49", "", true, false);
|
||||
public static final RoomChatMessageBubbles UNKNOWN_50 = new RoomChatMessageBubbles(50, "UNKNOWN_50", "", true, false);
|
||||
public static final RoomChatMessageBubbles UNKNOWN_51 = new RoomChatMessageBubbles(51, "UNKNOWN_51", "", true, false);
|
||||
public static final RoomChatMessageBubbles UNKNOWN_52 = new RoomChatMessageBubbles(52, "UNKNOWN_52", "", true, false);
|
||||
public static final RoomChatMessageBubbles UNKNOWN_53 = new RoomChatMessageBubbles(53, "UNKNOWN_53", "", true, false);
|
||||
|
||||
|
||||
static {
|
||||
@@ -167,11 +167,11 @@ public class RoomChatMessageBubbles {
|
||||
|
||||
public static void removeDynamicBubbles() {
|
||||
synchronized (BUBBLES) {
|
||||
BUBBLES.entrySet().removeIf(entry -> entry.getKey() > 45);
|
||||
BUBBLES.entrySet().removeIf(entry -> entry.getKey() > 53);
|
||||
}
|
||||
}
|
||||
|
||||
public static RoomChatMessageBubbles[] values() {
|
||||
return BUBBLES.values().toArray(new RoomChatMessageBubbles[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
package com.eu.habbo.habbohotel.rooms;
|
||||
|
||||
import com.eu.habbo.habbohotel.gameclients.GameClient;
|
||||
import com.eu.habbo.habbohotel.items.FurnitureType;
|
||||
import com.eu.habbo.habbohotel.items.interactions.InteractionConfInvisControl;
|
||||
import com.eu.habbo.habbohotel.users.HabboItem;
|
||||
import com.eu.habbo.messages.outgoing.rooms.items.ConfInvisStateComposer;
|
||||
import gnu.trove.list.array.TIntArrayList;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public final class RoomConfInvisSupport {
|
||||
private RoomConfInvisSupport() {
|
||||
}
|
||||
|
||||
public static boolean isControllerItem(HabboItem item) {
|
||||
return item instanceof InteractionConfInvisControl
|
||||
|| hasInteractionName(item, "wf_conf_invis_control");
|
||||
}
|
||||
|
||||
public static boolean isControllerActive(HabboItem item) {
|
||||
return isControllerItem(item) && "1".equals(item.getExtradata());
|
||||
}
|
||||
|
||||
public static boolean isTarget(HabboItem item) {
|
||||
return item != null
|
||||
&& item.getBaseItem() != null
|
||||
&& item.getBaseItem().getType() == FurnitureType.FLOOR
|
||||
&& hasCustomParamToken(item.getBaseItem().getCustomParams(), "is_invisible");
|
||||
}
|
||||
|
||||
public static TIntArrayList collectHiddenFloorItemIds(Room room) {
|
||||
TIntArrayList hiddenItemIds = new TIntArrayList();
|
||||
|
||||
if (room == null) {
|
||||
return hiddenItemIds;
|
||||
}
|
||||
|
||||
if (!hasActiveController(room)) {
|
||||
return hiddenItemIds;
|
||||
}
|
||||
|
||||
for (HabboItem item : room.getFloorItems()) {
|
||||
if (isTarget(item)) {
|
||||
hiddenItemIds.add(item.getId());
|
||||
}
|
||||
}
|
||||
|
||||
return hiddenItemIds;
|
||||
}
|
||||
|
||||
public static boolean hasActiveController(Room room) {
|
||||
if (room == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (HabboItem item : room.getFloorItems()) {
|
||||
if (isControllerActive(item)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void sendState(Room room) {
|
||||
if (room == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
room.sendComposer(new ConfInvisStateComposer(room).compose());
|
||||
}
|
||||
|
||||
public static void sendState(Room room, GameClient client) {
|
||||
if (room == null || client == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
client.sendResponse(new ConfInvisStateComposer(room).compose());
|
||||
}
|
||||
|
||||
private static boolean hasCustomParamToken(String value, String token) {
|
||||
if (value == null || token == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String normalized = value.trim().toLowerCase();
|
||||
|
||||
if (normalized.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Pattern pattern = Pattern.compile("(^|[^a-z0-9_])" + Pattern.quote(token.toLowerCase()) + "($|[^a-z0-9_])");
|
||||
|
||||
return pattern.matcher(normalized).find();
|
||||
}
|
||||
|
||||
private static boolean hasInteractionName(HabboItem item, String interactionName) {
|
||||
if (item == null || item.getBaseItem() == null || item.getBaseItem().getInteractionType() == null || interactionName == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String currentInteractionName = item.getBaseItem().getInteractionType().getName();
|
||||
|
||||
return currentInteractionName != null && currentInteractionName.equalsIgnoreCase(interactionName);
|
||||
}
|
||||
}
|
||||
@@ -377,7 +377,8 @@ public class RoomCycleManager {
|
||||
* Processes roller cycle.
|
||||
*/
|
||||
private void processRollers(THashSet<RoomUnit> updatedUnit) {
|
||||
int rollerSpeed = this.room.getRollerSpeed();
|
||||
Integer controlledRollerSpeed = RoomQueueSpeedControlSupport.getEffectiveRollerSpeed(this.room);
|
||||
int rollerSpeed = (controlledRollerSpeed != null) ? controlledRollerSpeed : this.room.getRollerSpeed();
|
||||
if (rollerSpeed != -1 && this.rollerCycle >= rollerSpeed) {
|
||||
this.rollerCycle = 0;
|
||||
this.room.getRollerManager().processRollerCycle(updatedUnit, this.cycleTimestamp);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user