Subscription revamp, Habbo club, HC Pay day, Clothing validation and Catalog purchase logs

This commit is contained in:
Beny 2020-10-04 00:25:55 +02:00
parent 683ff1dd1d
commit 64b0f499d0
43 changed files with 1967 additions and 84 deletions

View File

@ -0,0 +1,88 @@
CREATE TABLE `users_subscriptions` (
`id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`user_id` int(10) UNSIGNED NULL,
`subscription_type` varchar(255) NULL,
`timestamp_start` int(10) UNSIGNED NULL,
`duration` int(10) UNSIGNED NULL,
`active` tinyint(1) NULL DEFAULT 1,
PRIMARY KEY (`id`),
INDEX `user_id`(`user_id`),
INDEX `subscription_type`(`subscription_type`),
INDEX `timestamp_start`(`timestamp_start`),
INDEX `active`(`active`)
);
CREATE TABLE `logs_shop_purchases` (
`id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`timestamp` int(10) UNSIGNED NULL,
`user_id` int(10) UNSIGNED NULL,
`catalog_item_id` int(10) UNSIGNED NULL,
`item_ids` text DEFAULT NULL,
`catalog_name` varchar(255) NULL,
`cost_credits` int(10) NULL,
`cost_points` int(10) NULL,
`points_type` int(10) NULL,
`amount` int(10) NULL,
PRIMARY KEY (`id`),
INDEX `timestamp`(`timestamp`),
INDEX `user_id`(`user_id`)
);
CREATE TABLE `logs_hc_payday` (
`id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
`timestamp` int(10) UNSIGNED NULL,
`user_id` int(10) UNSIGNED NULL,
`hc_streak` int(10) UNSIGNED NULL,
`total_coins_spent` int(10) UNSIGNED NULL,
`reward_coins_spent` int(10) UNSIGNED NULL,
`reward_streak` int(10) UNSIGNED NULL,
`total_payout` int(10) UNSIGNED NULL,
`currency` varchar(255) NULL,
`claimed` tinyint(1) DEFAULT 0 NULL,
PRIMARY KEY (`id`),
INDEX `timestamp`(`timestamp`),
INDEX `user_id`(`user_id`)
);
ALTER TABLE `emulator_settings` MODIFY COLUMN `value` varchar(512) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL AFTER `key`;
INSERT INTO `emulator_settings`(`key`, `value`) VALUES ('subscriptions.hc.payday.enabled', '1');
INSERT INTO `emulator_settings`(`key`, `value`) VALUES ('subscriptions.hc.payday.next_date', '2020-10-15 00:00:00');
INSERT INTO `emulator_settings`(`key`, `value`) VALUES ('subscriptions.hc.payday.interval', '1 month');
INSERT INTO `emulator_settings`(`key`, `value`) VALUES ('subscriptions.hc.payday.query', 'SELECT SUM(cost_credits) AS `amount_spent` FROM `logs_shop_purchases` WHERE `user_id` = @user_id AND `timestamp` > @timestamp_start AND `timestamp` <= @timestamp_end AND `catalog_name` NOT LIKE \'CF_%\' AND `catalog_name` NOT LIKE \'CFC_%\';');
INSERT INTO `emulator_settings`(`key`, `value`) VALUES ('subscriptions.hc.payday.streak', '7=5;30=10;60=15;90=20;180=25;365=30');
INSERT INTO `emulator_settings`(`key`, `value`) VALUES ('subscriptions.hc.payday.currency', 'credits');
INSERT INTO `emulator_settings`(`key`, `value`) VALUES ('subscriptions.hc.payday.percentage', '10');
INSERT INTO `emulator_settings`(`key`, `value`) VALUES ('subscriptions.hc.payday.creditsspent_reset_on_expire', '1');
INSERT INTO `emulator_texts` (`key`, `value`) VALUES ('subscriptions.hc.payday.message', 'Woohoo HC Payday has arrived! You have received %amount% credits to your purse. Enjoy!')
INSERT INTO `emulator_settings`(`key`, `value`) VALUES ('subscriptions.scheduler.enabled', '1');
INSERT INTO `emulator_settings`(`key`, `value`) VALUES ('subscriptions.scheduler.interval', '10');
INSERT INTO `emulator_settings`(`key`, `value`) VALUES ('hotel.users.clothingvalidation.onhcexpired', '0');
INSERT INTO `emulator_settings`(`key`, `value`) VALUES ('hotel.users.clothingvalidation.onlogin', '0');
INSERT INTO `emulator_settings`(`key`, `value`) VALUES ('hotel.users.clothingvalidation.onchangelooks', '0');
INSERT INTO `emulator_settings`(`key`, `value`) VALUES ('hotel.users.clothingvalidation.onmimic', '0');
INSERT INTO `emulator_settings`(`key`, `value`) VALUES ('hotel.users.clothingvalidation.onmannequin', '0');
INSERT INTO `emulator_settings`(`key`, `value`) VALUES ('hotel.users.clothingvalidation.onfballgate', '0');
INSERT INTO `emulator_settings`(`key`, `value`) VALUES ('gamedata.figuredata.url', 'https://habbo.com/gamedata/figuredata/0');
INSERT INTO `emulator_settings`(`key`, `value`) VALUES ('hotel.users.max.friends', '300');
INSERT INTO `emulator_settings`(`key`, `value`) VALUES ('hotel.users.max.friends.hc', '1100');
INSERT INTO `emulator_settings`(`key`, `value`) VALUES ('hotel.users.max.rooms', '50');
INSERT INTO `emulator_settings`(`key`, `value`) VALUES ('hotel.users.max.rooms.hc', '75');
DELETE FROM `emulator_settings` WHERE `key` = 'hotel.max.rooms.per.user';
DELETE FROM `emulator_settings` WHERE `key` = 'hotel.max.rooms.user';
DELETE FROM `emulator_settings` WHERE `key` = 'hotel.max.rooms.vip';
DELETE FROM `emulator_settings` WHERE `key` = 'max.friends';
DELETE FROM `emulator_settings` WHERE `key` = 'max.friends';
ALTER TABLE `users_settings` ADD COLUMN `max_friends` int(10) NULL DEFAULT 300 AFTER `has_gotten_default_saved_searches`;
ALTER TABLE `users_settings` ADD COLUMN `max_rooms` int(10) NULL DEFAULT 50 AFTER `has_gotten_default_saved_searches`;
ALTER TABLE `users_settings` ADD COLUMN `last_hc_payday` int(10) NULL DEFAULT 0 AFTER `has_gotten_default_saved_searches`;
ALTER TABLE `permissions` ADD COLUMN `cmd_subscription` enum('0','1') NULL DEFAULT '0' AFTER `cmd_credits`;
INSERT INTO `emulator_texts` (`key`, `value`) VALUES ('commands.keys.cmd_subscription', 'subscription;sub');
INSERT INTO users_subscriptions SELECT NULL, user_id, 'HABBO_CLUB' as `subscription_type`, UNIX_TIMESTAMP() AS `timestamp_start`, (club_expire_timestamp - UNIX_TIMESTAMP()) AS `duration`, 1 AS `active` FROM users_settings WHERE club_expire_timestamp > UNIX_TIMESTAMP();

View File

@ -24,10 +24,10 @@ import java.io.*;
import java.security.MessageDigest;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.Random;
import java.util.*;
import java.util.concurrent.ThreadLocalRandom;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public final class Emulator {
@ -368,6 +368,65 @@ public final class Emulator {
System.exit(0);
}
public static int timeStringToSeconds(String timeString) {
int totalSeconds = 0;
Matcher m = Pattern.compile("(([0-9]*) (second|minute|hour|day|week|month|year))").matcher(timeString);
Map<String,Integer> map = new HashMap<String,Integer>() {
{
put("second", 1);
put("minute", 60);
put("hour", 3600);
put("day", 86400);
put("week", 604800);
put("month", 2628000);
put("year", 31536000);
}
};
while (m.find()) {
try {
int amount = Integer.parseInt(m.group(2));
String what = m.group(3);
totalSeconds += amount * map.get(what);
}
catch (Exception ignored) { }
}
return totalSeconds;
}
public static Date modifyDate(Date date, String timeString) {
int totalSeconds = 0;
Calendar c = Calendar.getInstance();
c.setTime(date);
Matcher m = Pattern.compile("(([0-9]*) (second|minute|hour|day|week|month|year))").matcher(timeString);
Map<String, Integer> map = new HashMap<String, Integer>() {
{
put("second", Calendar.SECOND);
put("minute", Calendar.MINUTE);
put("hour", Calendar.HOUR);
put("day", Calendar.DAY_OF_MONTH);
put("week", Calendar.WEEK_OF_MONTH);
put("month", Calendar.MONTH);
put("year", Calendar.YEAR);
}
};
while (m.find()) {
try {
int amount = Integer.parseInt(m.group(2));
String what = m.group(3);
c.add(map.get(what), amount);
}
catch (Exception ignored) { }
}
return c.getTime();
}
private static String dateToUnixTimestamp(Date date) {
String res = "";
Date aux = stringToDate("1970-01-01 00:00:00");
@ -378,7 +437,7 @@ public final class Emulator {
return res + seconds;
}
private static Date stringToDate(String date) {
public static Date stringToDate(String date) {
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date res = null;
try {

View File

@ -3,9 +3,18 @@ package com.eu.habbo.database;
import com.eu.habbo.Emulator;
import com.eu.habbo.core.ConfigurationManager;
import com.zaxxer.hikari.HikariDataSource;
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.SQLException;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Database {
private static final Logger LOGGER = LoggerFactory.getLogger(Database.class);
@ -53,4 +62,52 @@ public class Database {
public DatabasePool getDatabasePool() {
return this.databasePool;
}
public static PreparedStatement preparedStatementWithParams(Connection connection, String query, THashMap<String, Object> queryParams) throws SQLException {
THashMap<Integer, Object> params = new THashMap<Integer, Object>();
THashSet<String> quotedParams = new THashSet<>();
for(String key : queryParams.keySet()) {
quotedParams.add(Pattern.quote(key));
}
String regex = "(" + String.join("|", quotedParams) + ")";
Matcher m = Pattern.compile(regex).matcher(query);
int i = 1;
while (m.find()) {
try {
params.put(i, queryParams.get(m.group(1)));
i++;
}
catch (Exception ignored) { }
}
PreparedStatement statement = connection.prepareStatement(query.replaceAll(regex, "?"));
for(Map.Entry<Integer, Object> set : params.entrySet()) {
if(set.getValue().getClass() == String.class) {
statement.setString(set.getKey(), (String)set.getValue());
}
else if(set.getValue().getClass() == Integer.class) {
statement.setInt(set.getKey(), (Integer)set.getValue());
}
else if(set.getValue().getClass() == Double.class) {
statement.setDouble(set.getKey(), (Double)set.getValue());
}
else if(set.getValue().getClass() == Float.class) {
statement.setFloat(set.getKey(), (Float)set.getValue());
}
else if(set.getValue().getClass() == Long.class) {
statement.setLong(set.getKey(), (Long)set.getValue());
}
else {
statement.setObject(set.getKey(), set.getValue());
}
}
return statement;
}
}

View File

@ -20,6 +20,8 @@ import com.eu.habbo.habbohotel.pets.PetManager;
import com.eu.habbo.habbohotel.polls.PollManager;
import com.eu.habbo.habbohotel.rooms.RoomManager;
import com.eu.habbo.habbohotel.users.HabboManager;
import com.eu.habbo.habbohotel.users.subscriptions.SubscriptionManager;
import com.eu.habbo.habbohotel.users.subscriptions.SubscriptionScheduler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -31,6 +33,8 @@ public class GameEnvironment {
public PixelScheduler pixelScheduler;
public PointsScheduler pointsScheduler;
public GotwPointsScheduler gotwPointsScheduler;
public SubscriptionScheduler subscriptionScheduler;
private HabboManager habboManager;
private NavigatorManager navigatorManager;
private GuildManager guildManager;
@ -49,6 +53,7 @@ public class GameEnvironment {
private WordFilter wordFilter;
private CraftingManager craftingManager;
private PollManager pollManager;
private SubscriptionManager subscriptionManager;
public void load() throws Exception {
LOGGER.info("GameEnvironment -> Loading...");
@ -86,6 +91,11 @@ public class GameEnvironment {
this.gotwPointsScheduler = new GotwPointsScheduler();
Emulator.getThreading().run(this.gotwPointsScheduler);
this.subscriptionManager = new SubscriptionManager();
this.subscriptionManager.init();
this.subscriptionScheduler = new SubscriptionScheduler();
Emulator.getThreading().run(this.subscriptionScheduler);
LOGGER.info("GameEnvironment -> Loaded!");
}
@ -103,6 +113,7 @@ public class GameEnvironment {
this.roomManager.dispose();
this.itemManager.dispose();
this.hotelViewManager.dispose();
this.subscriptionManager.dispose();
LOGGER.info("GameEnvironment -> Disposed!");
}
@ -191,4 +202,8 @@ public class GameEnvironment {
public GotwPointsScheduler getGotwPointsScheduler() { return this.gotwPointsScheduler;
}
public SubscriptionManager getSubscriptionManager() {
return this.subscriptionManager;
}
}

View File

@ -1121,6 +1121,26 @@ public class CatalogManager {
habbo.getClient().sendResponse(new PurchaseOKComposer(purchasedEvent.catalogItem));
habbo.getClient().sendResponse(new InventoryRefreshComposer());
THashSet<String> itemIds = new THashSet<>();
for(HabboItem ix : purchasedEvent.itemsList) {
itemIds.add(ix.getId() + "");
}
if(!free) {
Emulator.getThreading().run(new CatalogPurchaseLogEntry(
Emulator.getIntUnixTimestamp(),
purchasedEvent.habbo.getHabboInfo().getId(),
purchasedEvent.catalogItem != null ? purchasedEvent.catalogItem.getId() : 0,
String.join(";", itemIds),
purchasedEvent.catalogItem != null ? purchasedEvent.catalogItem.getName() : "",
purchasedEvent.totalCredits,
purchasedEvent.totalPoints,
item != null ? item.getPointsType() : 0,
amount
));
}
} catch (Exception e) {
LOGGER.error("Exception caught", e);
habbo.getClient().sendResponse(new AlertPurchaseFailedComposer(AlertPurchaseFailedComposer.SERVER_ERROR));

View File

@ -0,0 +1,61 @@
package com.eu.habbo.habbohotel.catalog;
import com.eu.habbo.Emulator;
import com.eu.habbo.core.DatabaseLoggable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.sql.PreparedStatement;
import java.sql.SQLException;
public class CatalogPurchaseLogEntry implements Runnable, DatabaseLoggable {
private static final Logger LOGGER = LoggerFactory.getLogger(CatalogPurchaseLogEntry.class);
private static final String QUERY = "INSERT INTO `logs_shop_purchases` (timestamp, user_id, catalog_item_id, item_ids, catalog_name, cost_credits, cost_points, points_type, amount) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)";
private final int timestamp;
private final int userId;
private final int catalogItemId;
private final String itemIds;
private final String catalogName;
private final int costCredits;
private final int costPoints;
private final int pointsType;
private final int amount;
public CatalogPurchaseLogEntry(int timestamp, int userId, int catalogItemId, String itemIds, String catalogName, int costCredits, int costPoints, int pointsType, int amount) {
this.timestamp = timestamp;
this.userId = userId;
this.catalogItemId = catalogItemId;
this.itemIds = itemIds;
this.catalogName = catalogName;
this.costCredits = costCredits;
this.costPoints = costPoints;
this.pointsType = pointsType;
this.amount = amount;
}
@Override
public String getQuery() {
return QUERY;
}
@Override
public void log(PreparedStatement statement) throws SQLException {
statement.setInt(1, this.timestamp);
statement.setInt(2, this.userId);
statement.setInt(3, this.catalogItemId);
statement.setString(4, this.itemIds);
statement.setString(5, this.catalogName);
statement.setInt(6, this.costCredits);
statement.setInt(7, this.costPoints);
statement.setInt(8, this.pointsType);
statement.setInt(9, this.amount);
statement.addBatch();
}
@Override
public void run() {
Emulator.getDatabaseLogger().store(this);
}
}

View File

@ -285,6 +285,7 @@ public class CommandHandler {
addCommand(new UpdateYoutubePlaylistsCommand());
addCommand(new AddYoutubePlaylistCommand());
addCommand(new SoftKickCommand());
addCommand(new SubscriptionCommand());
addCommand(new TestCommand());
}

View File

@ -6,6 +6,7 @@ import com.eu.habbo.habbohotel.permissions.Permission;
import com.eu.habbo.habbohotel.rooms.RoomChatMessageBubbles;
import com.eu.habbo.habbohotel.users.Habbo;
import com.eu.habbo.habbohotel.users.HabboGender;
import com.eu.habbo.habbohotel.users.clothingvalidation.ClothingValidationManager;
import com.eu.habbo.messages.outgoing.rooms.users.RoomUserDataComposer;
import com.eu.habbo.messages.outgoing.users.UserDataComposer;
import com.eu.habbo.util.figure.FigureUtil;
@ -35,7 +36,7 @@ public class MimicCommand extends Command {
gameClient.getHabbo().whisper(Emulator.getTexts().getValue("commands.error.cmd_mimic.forbidden_clothing"), RoomChatMessageBubbles.ALERT);
return true;
} else {
gameClient.getHabbo().getHabboInfo().setLook(habbo.getHabboInfo().getLook());
gameClient.getHabbo().getHabboInfo().setLook(ClothingValidationManager.VALIDATE_ON_MIMIC ? ClothingValidationManager.validateLook(gameClient.getHabbo(), habbo.getHabboInfo().getLook(), habbo.getHabboInfo().getGender().name()) : habbo.getHabboInfo().getLook());
gameClient.getHabbo().getHabboInfo().setGender(habbo.getHabboInfo().getGender());
gameClient.sendResponse(new UserDataComposer(gameClient.getHabbo()));
gameClient.getHabbo().getHabboInfo().getCurrentRoom().sendComposer(new RoomUserDataComposer(gameClient.getHabbo()).compose());

View File

@ -0,0 +1,107 @@
package com.eu.habbo.habbohotel.commands;
import com.eu.habbo.Emulator;
import com.eu.habbo.habbohotel.gameclients.GameClient;
import com.eu.habbo.habbohotel.rooms.RoomChatMessageBubbles;
import com.eu.habbo.habbohotel.users.Habbo;
import com.eu.habbo.habbohotel.users.HabboInfo;
import com.eu.habbo.habbohotel.users.HabboManager;
import com.eu.habbo.habbohotel.users.subscriptions.Subscription;
/**
* @author Beny
*/
public class SubscriptionCommand extends Command {
public SubscriptionCommand() {
super("cmd_subscription", Emulator.getTexts().getValue("commands.keys.cmd_subscription").split(";"));
}
/**
* Allows you to give/extend/remove subscription on a given user.
*
* Parameters:
* [username] = Username of user to execute command on
* [type] = Subscription type (e.g. HABBO_CLUB)
* [add|remove] = Use add or remove to increase/decrease sub duration
* [time] = Time string e.g. "1 week", "18 days", "4 minutes". Can be complex e.g. "1 month 5 days 2 minutes"
*
* Examples:
* :sub Beny habbo_club add 1 month - adds 1 month of HABBO_CLUB subscription duration on the user Beny
* :sub Beny builders_club add 1 month - adds 1 month of BUILDERS_CLUB subscription duration on the user Beny
* :sub Beny habbo_club remove 3 days - removes 3 days of HABBO_CLUB subscription duration on the user Beny
* :sub Beny habbo_club remove - removes all remaining time from the HABBO_CLUB subscription (expires it) on the user Beny
*
* @param gameClient Client that executed the command
* @param params Command parameters
* @return Boolean indicating success
* @throws Exception Exception
*/
@Override
public boolean handle(GameClient gameClient, String[] params) throws Exception {
if (params.length >= 4) {
HabboInfo info = HabboManager.getOfflineHabboInfo(params[1]);
if (info != null) {
Habbo habbo = Emulator.getGameServer().getGameClientManager().getHabbo(params[1]);
String subscription = params[2].toUpperCase();
String action = params[3];
StringBuilder message = new StringBuilder();
if (params.length > 4) {
for (int i = 4; i < params.length; i++) {
message.append(params[i]).append(" ");
}
}
if(!Emulator.getGameEnvironment().getSubscriptionManager().types.containsKey(subscription)) {
gameClient.getHabbo().whisper(Emulator.getTexts().getValue("commands.error.cmd_subscription.type_not_found", "%subscription% is not a valid subscription type").replace("%subscription%", subscription), RoomChatMessageBubbles.ALERT);
return true;
}
if(action.equalsIgnoreCase("add") || action.equalsIgnoreCase("+") || action.equalsIgnoreCase("a")) {
int timeToAdd = Emulator.timeStringToSeconds(message.toString());
if(timeToAdd < 1) {
gameClient.getHabbo().whisper(Emulator.getTexts().getValue("commands.error.cmd_subscription.invalid_params", "Invalid time span, try: x minutes/days/weeks/months"), RoomChatMessageBubbles.ALERT);
return true;
}
habbo.getHabboStats().createSubscription(subscription, timeToAdd);
gameClient.getHabbo().whisper(Emulator.getTexts().getValue("commands.error.cmd_subscription.success_add_time", "Successfully added %time% seconds to %subscription% on %user%").replace("%time%", timeToAdd + "").replace("%user%", params[1]).replace("%subscription%", subscription), RoomChatMessageBubbles.ALERT);
}
else if(action.equalsIgnoreCase("remove") || action.equalsIgnoreCase("-") || action.equalsIgnoreCase("r")) {
Subscription s = habbo.getHabboStats().getSubscription(subscription);
if (s == null) {
gameClient.getHabbo().whisper(Emulator.getTexts().getValue("commands.error.cmd_subscription.user_not_have", "%user% does not have the %subscription% subscription").replace("%user%", params[1]).replace("%subscription%", subscription), RoomChatMessageBubbles.ALERT);
return true;
}
if(message.length() != 0) {
int timeToRemove = Emulator.timeStringToSeconds(message.toString());
if (timeToRemove < 1) {
gameClient.getHabbo().whisper(Emulator.getTexts().getValue("commands.error.cmd_subscription.invalid_params", "Invalid time span, try: x minutes/days/weeks/months"), RoomChatMessageBubbles.ALERT);
return true;
}
s.addDuration(timeToRemove);
gameClient.getHabbo().whisper(Emulator.getTexts().getValue("commands.error.cmd_subscription.success_remove_time", "Successfully removed %time% seconds from %subscription% on %user%").replace("%time%", timeToRemove + "").replace("%user%", params[1]).replace("%subscription%", subscription), RoomChatMessageBubbles.ALERT);
}
else {
s.addDuration(-s.getRemaining());
gameClient.getHabbo().whisper(Emulator.getTexts().getValue("commands.error.cmd_subscription.success_remove_sub", "Successfully removed %subscription% sub from %user%").replace("%user%", params[1]).replace("%subscription%", subscription), RoomChatMessageBubbles.ALERT);
}
}
} else {
gameClient.getHabbo().whisper(Emulator.getTexts().getValue("commands.error.cmd_subscription.user_not_found", "%user% was not found").replace("%user%", params[1]), RoomChatMessageBubbles.ALERT);
}
} else {
gameClient.getHabbo().whisper(Emulator.getTexts().getValue("commands.error.cmd_subscription.invalid_params", "Invalid command format"), RoomChatMessageBubbles.ALERT);
}
return true;
}
}

View File

@ -6,6 +6,7 @@ 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.habbohotel.users.clothingvalidation.ClothingValidationManager;
import com.eu.habbo.messages.ServerMessage;
import com.eu.habbo.messages.outgoing.rooms.users.RoomUserDataComposer;
import com.eu.habbo.messages.outgoing.users.UserDataComposer;
@ -60,7 +61,17 @@ public class InteractionMannequin extends HabboItem {
@Override
public void onClick(GameClient client, Room room, Object[] objects) throws Exception {
String lookCode = this.getExtradata().split(":")[1];
String[] data = this.getExtradata().split(":");
if(data.length < 2)
return;
String gender = data[0];
String figure = data[1];
if (gender.isEmpty() || figure.isEmpty() || (!gender.equalsIgnoreCase("m") && !gender.equalsIgnoreCase("f")) || !client.getHabbo().getHabboInfo().getGender().name().equalsIgnoreCase(gender))
return;
String newFigure = "";
for (String playerFigurePart : client.getHabbo().getHabboInfo().getLook().split("\\.")) {
@ -68,8 +79,7 @@ public class InteractionMannequin extends HabboItem {
newFigure += playerFigurePart + ".";
}
if (lookCode.isEmpty()) return;
String newFigureParts = lookCode;
String newFigureParts = figure;
for (String newFigurePart : newFigureParts.split("\\.")) {
if (newFigurePart.startsWith("hd"))
@ -78,12 +88,12 @@ public class InteractionMannequin extends HabboItem {
if (newFigureParts.equals("")) return;
final String figure = newFigure + newFigureParts;
String newLook = newFigure + newFigureParts;
if (figure.length() > 512)
if (newLook.length() > 512)
return;
client.getHabbo().getHabboInfo().setLook(figure);
client.getHabbo().getHabboInfo().setLook(ClothingValidationManager.VALIDATE_ON_MANNEQUIN ? ClothingValidationManager.validateLook(client.getHabbo(), newLook, client.getHabbo().getHabboInfo().getGender().name()) : newLook);
room.sendComposer(new RoomUserDataComposer(client.getHabbo()).compose());
client.sendResponse(new UserDataComposer(client.getHabbo()));
}

View File

@ -7,6 +7,7 @@ import com.eu.habbo.habbohotel.rooms.RoomUnit;
import com.eu.habbo.habbohotel.users.Habbo;
import com.eu.habbo.habbohotel.users.HabboGender;
import com.eu.habbo.habbohotel.users.HabboItem;
import com.eu.habbo.habbohotel.users.clothingvalidation.ClothingValidationManager;
import com.eu.habbo.messages.ServerMessage;
import com.eu.habbo.messages.outgoing.rooms.users.RoomUserDataComposer;
import com.eu.habbo.messages.outgoing.users.UpdateUserLookComposer;
@ -120,7 +121,7 @@ public class InteractionFootballGate extends HabboItem {
UserSavedLookEvent lookEvent = new UserSavedLookEvent(habbo, habbo.getHabboInfo().getGender(), oldlook);
Emulator.getPluginManager().fireEvent(lookEvent);
if (!lookEvent.isCancelled()) {
habbo.getHabboInfo().setLook(lookEvent.newLook);
habbo.getHabboInfo().setLook(ClothingValidationManager.VALIDATE_ON_FBALLGATE ? ClothingValidationManager.validateLook(habbo, lookEvent.newLook, lookEvent.gender.name()) : lookEvent.newLook);
Emulator.getThreading().run(habbo.getHabboInfo());
habbo.getClient().sendResponse(new UpdateUserLookComposer(habbo));
room.sendComposer(new RoomUserDataComposer(habbo).compose());
@ -134,7 +135,7 @@ public class InteractionFootballGate extends HabboItem {
Emulator.getPluginManager().fireEvent(lookEvent);
if (!lookEvent.isCancelled()) {
habbo.getHabboStats().cache.put(CACHE_KEY, habbo.getHabboInfo().getLook());
habbo.getHabboInfo().setLook(lookEvent.newLook);
habbo.getHabboInfo().setLook(ClothingValidationManager.VALIDATE_ON_FBALLGATE ? ClothingValidationManager.validateLook(habbo, lookEvent.newLook, lookEvent.gender.name()) : lookEvent.newLook);
Emulator.getThreading().run(habbo.getHabboInfo());
habbo.getClient().sendResponse(new UpdateUserLookComposer(habbo));
room.sendComposer(new RoomUserDataComposer(habbo).compose());

View File

@ -167,18 +167,6 @@ public class Messenger {
return map;
}
public static int friendLimit(Habbo habbo) {
if (habbo.hasPermission("acc_infinite_friends")) {
return Integer.MAX_VALUE;
}
if (habbo.getHabboStats().hasActiveClub()) {
return MAXIMUM_FRIENDS_HC;
}
return MAXIMUM_FRIENDS;
}
public static void checkFriendSizeProgress(Habbo habbo) {
int progress = habbo.getHabboStats().getAchievementProgress(Emulator.getGameEnvironment().getAchievementManager().getAchievement("FriendListSize"));

View File

@ -66,7 +66,7 @@ public class RoomManager {
private static final int page = 0;
//Configuration. Loaded from database & updated accordingly.
public static int MAXIMUM_ROOMS_USER = 25;
public static int MAXIMUM_ROOMS_VIP = 35;
public static int MAXIMUM_ROOMS_HC = 35;
public static int HOME_ROOM_ID = 0;
public static boolean SHOW_PUBLIC_IN_POPULAR_TAB = false;
private final THashMap<Integer, RoomCategory> roomCategories;

View File

@ -9,22 +9,22 @@ import com.eu.habbo.habbohotel.catalog.CatalogItem;
import com.eu.habbo.habbohotel.rooms.RoomChatMessageBubbles;
import com.eu.habbo.habbohotel.rooms.RoomTrade;
import com.eu.habbo.habbohotel.users.cache.HabboOfferPurchase;
import com.eu.habbo.habbohotel.users.subscriptions.Subscription;
import com.eu.habbo.habbohotel.users.subscriptions.SubscriptionManager;
import com.eu.habbo.plugin.events.users.subscriptions.UserSubscriptionCreatedEvent;
import com.eu.habbo.plugin.events.users.subscriptions.UserSubscriptionExtendedEvent;
import gnu.trove.list.array.TIntArrayList;
import gnu.trove.map.TIntObjectMap;
import gnu.trove.map.hash.THashMap;
import gnu.trove.map.hash.TIntObjectHashMap;
import gnu.trove.set.hash.THashSet;
import gnu.trove.stack.array.TIntArrayStack;
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.List;
import java.util.Map;
import java.lang.reflect.Constructor;
import java.sql.*;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
public class HabboStats implements Runnable {
@ -93,6 +93,11 @@ public class HabboStats implements Runnable {
private boolean allowTrade;
private int clubExpireTimestamp;
private int muteEndTime;
public int maxFriends;
public int maxRooms;
public int lastHCPayday;
public int hcMessageLastModified = Emulator.getIntUnixTimestamp();
public THashSet<Subscription> subscriptions;
private HabboStats(ResultSet set, HabboInfo habboInfo) throws SQLException {
this.cache = new THashMap<>(0);
@ -142,9 +147,14 @@ public class HabboStats implements Runnable {
this.forumPostsCount = set.getInt("forums_post_count");
this.uiFlags = set.getInt("ui_flags");
this.hasGottenDefaultSavedSearches = set.getInt("has_gotten_default_saved_searches") == 1;
this.maxFriends = set.getInt("max_friends");
this.maxRooms = set.getInt("max_rooms");
this.lastHCPayday = set.getInt("last_hc_payday");
this.nuxReward = this.nux;
this.subscriptions = Emulator.getGameEnvironment().getSubscriptionManager().getSubscriptionsForUser(this.habboInfo.getId());
try (PreparedStatement statement = set.getStatement().getConnection().prepareStatement("SELECT * FROM user_window_settings WHERE user_id = ? LIMIT 1")) {
statement.setInt(1, this.habboInfo.getId());
try (ResultSet nSet = statement.executeQuery()) {
@ -306,7 +316,7 @@ public class HabboStats implements Runnable {
int onlineTime = Emulator.getIntUnixTimestamp() - onlineTimeLast;
try (Connection connection = Emulator.getDatabase().getDataSource().getConnection()) {
try (PreparedStatement statement = connection.prepareStatement("UPDATE users_settings SET achievement_score = ?, respects_received = ?, respects_given = ?, daily_respect_points = ?, block_following = ?, block_friendrequests = ?, online_time = online_time + ?, guild_id = ?, daily_pet_respect_points = ?, club_expire_timestamp = ?, login_streak = ?, rent_space_id = ?, rent_space_endtime = ?, volume_system = ?, volume_furni = ?, volume_trax = ?, block_roominvites = ?, old_chat = ?, block_camera_follow = ?, chat_color = ?, hof_points = ?, block_alerts = ?, talent_track_citizenship_level = ?, talent_track_helpers_level = ?, ignore_bots = ?, ignore_pets = ?, nux = ?, mute_end_timestamp = ?, allow_name_change = ?, perk_trade = ?, can_trade = ?, `forums_post_count` = ?, ui_flags = ?, has_gotten_default_saved_searches = ? WHERE user_id = ? LIMIT 1")) {
try (PreparedStatement statement = connection.prepareStatement("UPDATE users_settings SET achievement_score = ?, respects_received = ?, respects_given = ?, daily_respect_points = ?, block_following = ?, block_friendrequests = ?, online_time = online_time + ?, guild_id = ?, daily_pet_respect_points = ?, club_expire_timestamp = ?, login_streak = ?, rent_space_id = ?, rent_space_endtime = ?, volume_system = ?, volume_furni = ?, volume_trax = ?, block_roominvites = ?, old_chat = ?, block_camera_follow = ?, chat_color = ?, hof_points = ?, block_alerts = ?, talent_track_citizenship_level = ?, talent_track_helpers_level = ?, ignore_bots = ?, ignore_pets = ?, nux = ?, mute_end_timestamp = ?, allow_name_change = ?, perk_trade = ?, can_trade = ?, `forums_post_count` = ?, ui_flags = ?, has_gotten_default_saved_searches = ?, max_friends = ?, max_rooms = ?, last_hc_payday = ? WHERE user_id = ? LIMIT 1")) {
statement.setInt(1, this.achievementScore);
statement.setInt(2, this.respectPointsReceived);
statement.setInt(3, this.respectPointsGiven);
@ -341,7 +351,10 @@ public class HabboStats implements Runnable {
statement.setInt(32, this.forumPostsCount);
statement.setInt(33, this.uiFlags);
statement.setInt(34, this.hasGottenDefaultSavedSearches ? 1 : 0);
statement.setInt(35, this.habboInfo.getId());
statement.setInt(35, this.maxFriends);
statement.setInt(36, this.maxRooms);
statement.setInt(37, this.lastHCPayday);
statement.setInt(38, this.habboInfo.getId());
statement.executeUpdate();
}
@ -441,16 +454,92 @@ public class HabboStats implements Runnable {
return this.rentedTimeEnd >= Emulator.getIntUnixTimestamp();
}
public Subscription getSubscription(String subscriptionType) {
for(Subscription subscription : subscriptions) {
if(subscription.getSubscriptionType().equalsIgnoreCase(subscriptionType) && subscription.isActive() && subscription.getRemaining() > 0) {
return subscription;
}
}
return null;
}
public boolean hasSubscription(String subscriptionType) {
Subscription subscription = getSubscription(subscriptionType);
return subscription != null;
}
public int getSubscriptionExpireTimestamp(String subscriptionType) {
Subscription subscription = getSubscription(subscriptionType);
if(subscription == null)
return 0;
return subscription.getTimestampEnd();
}
public Subscription createSubscription(String subscriptionType, int duration) {
Subscription subscription = getSubscription(subscriptionType);
if(subscription != null) {
if (!Emulator.getPluginManager().fireEvent(new UserSubscriptionExtendedEvent(this.habboInfo.getId(), subscription, duration)).isCancelled()) {
subscription.addDuration(duration);
subscription.onExtended(duration);
}
return subscription;
}
if (!Emulator.getPluginManager().fireEvent(new UserSubscriptionCreatedEvent(this.habboInfo.getId(), subscriptionType, duration)).isCancelled()) {
int startTimestamp = Emulator.getIntUnixTimestamp();
try (Connection connection = Emulator.getDatabase().getDataSource().getConnection(); PreparedStatement statement = connection.prepareStatement("INSERT INTO `users_subscriptions` (`user_id`, `subscription_type`, `timestamp_start`, `duration`, `active`) VALUES (?, ?, ?, ?, ?)", Statement.RETURN_GENERATED_KEYS)) {
statement.setInt(1, this.habboInfo.getId());
statement.setString(2, subscriptionType);
statement.setInt(3, startTimestamp);
statement.setInt(4, duration);
statement.setInt(5, 1);
statement.execute();
try (ResultSet set = statement.getGeneratedKeys()) {
if (set.next()) {
Class<? extends Subscription> subClazz = Emulator.getGameEnvironment().getSubscriptionManager().getSubscriptionClass(subscriptionType);
try {
Constructor<? extends Subscription> c = subClazz.getConstructor(Integer.class, Integer.class, String.class, Integer.class, Integer.class, Boolean.class);
c.setAccessible(true);
Subscription sub = c.newInstance(set.getInt(1), this.habboInfo.getId(), subscriptionType, startTimestamp, duration, true);
sub.onCreated();
this.subscriptions.add(sub);
return sub;
}
catch (Exception e) {
LOGGER.error("Caught exception", e);
}
}
}
} catch (SQLException e) {
LOGGER.error("Caught SQL exception", e);
}
}
return null;
}
public int getClubExpireTimestamp() {
return this.clubExpireTimestamp;
return getSubscriptionExpireTimestamp(Subscription.HABBO_CLUB);
}
public void setClubExpireTimestamp(int clubExpireTimestamp) {
this.clubExpireTimestamp = clubExpireTimestamp;
Subscription subscription = getSubscription(Subscription.HABBO_CLUB);
int duration = clubExpireTimestamp - Emulator.getIntUnixTimestamp();
if(subscription != null) {
duration = clubExpireTimestamp - subscription.getTimestampStart();
}
if(duration > 0) {
createSubscription(Subscription.HABBO_CLUB, duration);
}
}
public boolean hasActiveClub() {
return this.clubExpireTimestamp > Emulator.getIntUnixTimestamp();
return hasSubscription(Subscription.HABBO_CLUB);
}
public THashMap<Achievement, Integer> getAchievementProgress() {

View File

@ -0,0 +1,184 @@
package com.eu.habbo.habbohotel.users.clothingvalidation;
import com.eu.habbo.habbohotel.users.Habbo;
import gnu.trove.TIntCollection;
import gnu.trove.set.hash.TIntHashSet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.regex.Pattern;
public class ClothingValidationManager {
private static final Logger LOGGER = LoggerFactory.getLogger(ClothingValidationManager.class);
public static String FIGUREDATA_URL = "";
public static boolean VALIDATE_ON_HC_EXPIRE = false;
public static boolean VALIDATE_ON_LOGIN = false;
public static boolean VALIDATE_ON_CHANGE_LOOKS = false;
public static boolean VALIDATE_ON_MIMIC = false;
public static boolean VALIDATE_ON_MANNEQUIN = false;
public static boolean VALIDATE_ON_FBALLGATE = false;
private static final Figuredata FIGUREDATA = new Figuredata();
/**
* Parses the new figuredata.xml file
* @param newUrl URI of figuredata.xml file. Can be a file path or URL
*/
public static void reloadFiguredata(String newUrl) {
try {
FIGUREDATA.parseXML(newUrl);
} catch (Exception e) {
VALIDATE_ON_HC_EXPIRE = false;
VALIDATE_ON_LOGIN = false;
VALIDATE_ON_CHANGE_LOOKS = false;
VALIDATE_ON_MIMIC = false;
VALIDATE_ON_MANNEQUIN = false;
VALIDATE_ON_FBALLGATE = false;
LOGGER.error("Caught exception", e);
}
}
/**
* Validates a figure string on a given user
* @param habbo User to validate
* @return Cleaned figure string
*/
public static String validateLook(Habbo habbo) {
return validateLook(habbo.getHabboInfo().getLook(), habbo.getHabboInfo().getGender().name(), habbo.getHabboStats().hasActiveClub(), habbo.getInventory().getWardrobeComponent().getClothingSets());
}
/**
* Validates a given figure string and gender on a given user
* @param habbo User to validate
* @param look Figure string
* @param gender Gender (M/F)
* @return Cleaned figure string
*/
public static String validateLook(Habbo habbo, String look, String gender) {
return validateLook(look, gender, habbo.getHabboStats().hasActiveClub(), habbo.getInventory().getWardrobeComponent().getClothingSets());
}
/**
* Validates a given figure string against a given gender
* @param look Figure string
* @param gender Gender (M/F)
* @return Cleaned figure string
*/
public static String validateLook(String look, String gender) {
return validateLook(look, gender, false, new TIntHashSet());
}
/**
* Validates a given figure string against a given gender with club clothing option
* @param look Figure string
* @param gender Gender (M/F)
* @param isHC Boolean indicating if club clothing is permitted
* @return Cleaned figure string
*/
public static String validateLook(String look, String gender, boolean isHC) {
return validateLook(look, gender, isHC, new TIntHashSet());
}
/**
* Validates a figure string with all available options
* @param look Figure string
* @param gender Gender (M/F)
* @param isHC Boolean indicating if club clothing is permitted
* @param ownedClothing Array of owned clothing set IDs. If sellable and setId not in this array clothing will be removed
* @return Cleaned figure string
*/
public static String validateLook(String look, String gender, boolean isHC, TIntCollection ownedClothing) {
if(FIGUREDATA.palettes.size() == 0 || FIGUREDATA.settypes.size() == 0)
return look;
String[] newLookParts = look.split(Pattern.quote("."));
ArrayList<String> lookParts = new ArrayList<>();
for(String lookpart : newLookParts) {
if(lookpart.contains("-")) {
try {
String[] data = lookpart.split(Pattern.quote("-"));
if (data.length > 1) {
FiguredataSettype settype = FIGUREDATA.settypes.get(data[0]);
if (settype == null) {
throw new Exception("Set type " + data[0] + " does not exist");
}
FiguredataPalette palette = FIGUREDATA.palettes.get(settype.paletteId);
if (palette == null) {
throw new Exception("Palette " + settype.paletteId + " does not exist");
}
int setId;
FiguredataSettypeSet set;
setId = Integer.parseInt(data[1]);
set = settype.getSet(setId);
if (set == null)
throw new Exception("Set " + setId + " does not exist in SetType");
if ((set.club && !isHC) || !set.selectable || (set.sellable && !ownedClothing.contains(set.id))) {
if(gender.equalsIgnoreCase("M") && !isHC && !settype.mandatoryMale0)
continue;
if(gender.equalsIgnoreCase("F") && !isHC && !settype.mandatoryFemale0)
continue;
if(gender.equalsIgnoreCase("M") && isHC && !settype.mandatoryMale1)
continue;
if(gender.equalsIgnoreCase("F") && isHC && !settype.mandatoryFemale1)
continue;
set = settype.getFirstNonHCSetForGender(gender);
setId = set.id;
}
ArrayList<String> dataParts = new ArrayList<>();
int color1 = -1;
int color2 = -1;
if (data.length > 2 && set.colorable) {
color1 = Integer.parseInt(data[2]);
FiguredataPaletteColor color = palette.getColor(color1);
if (color == null || (color.club && !isHC)) {
color1 = palette.getFirstNonHCColor().id;
}
}
if (data.length > 3 && set.colorable) {
color2 = Integer.parseInt(data[3]);
FiguredataPaletteColor color = palette.getColor(color2);
if (color == null || (color.club && !isHC)) {
color2 = palette.getFirstNonHCColor().id;
}
}
dataParts.add(settype.type);
dataParts.add("" + setId);
if (color1 > -1) {
dataParts.add("" + color1);
}
if (color2 > -1) {
dataParts.add("" + color2);
}
lookParts.add(String.join("-", dataParts));
}
}
catch (Exception e) {
//habbo.alert(e.getMessage());
}
}
}
return String.join(".", lookParts);
}
}

View File

@ -0,0 +1,100 @@
package com.eu.habbo.habbohotel.users.clothingvalidation;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.util.Map;
import java.util.TreeMap;
public class Figuredata {
public Map<Integer, FiguredataPalette> palettes;
public Map<String, FiguredataSettype> settypes;
public Figuredata() {
palettes = new TreeMap<>();
settypes = new TreeMap<>();
}
/**
* Parses the figuredata.xml file
* @param uri URI to the figuredata.xml file
* @throws ParserConfigurationException
* @throws IOException
* @throws SAXException
*/
public void parseXML(String uri) throws ParserConfigurationException, IOException, SAXException {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setValidating(false);
factory.setIgnoringElementContentWhitespace(true);
DocumentBuilder builder = factory.newDocumentBuilder();
Document document = builder.parse(uri);
Element rootElement = document.getDocumentElement();
NodeList palettesList = document.getElementsByTagName("colors").item(0).getChildNodes();
NodeList settypesList = document.getElementsByTagName("sets").item(0).getChildNodes();
palettes.clear();
settypes.clear();
for(int i = 0; i < palettesList.getLength(); i++) {
Node nNode = palettesList.item(i);
Element element = (Element)nNode;
int paletteId = Integer.parseInt(element.getAttribute("id"));
FiguredataPalette palette = new FiguredataPalette(paletteId);
NodeList colorsList = nNode.getChildNodes();
for(int ii = 0; ii < colorsList.getLength(); ii++) {
Element colorElement = (Element)colorsList.item(ii);
FiguredataPaletteColor color = new FiguredataPaletteColor(
Integer.parseInt(colorElement.getAttribute("id")),
Integer.parseInt(colorElement.getAttribute("index")),
!colorElement.getAttribute("club").equals("0"),
colorElement.getAttribute("selectable").equals("1"),
colorElement.getTextContent()
);
palette.addColor(color);
}
palettes.put(palette.id, palette);
}
for(int i = 0; i < settypesList.getLength(); i++) {
Node nNode = settypesList.item(i);
Element element = (Element)nNode;
String type = element.getAttribute("type");
int paletteId = Integer.parseInt(element.getAttribute("paletteid"));
boolean mandM0 = element.getAttribute("mand_m_0").equals("1");
boolean mandF0 = element.getAttribute("mand_f_0").equals("1");
boolean mandM1 = element.getAttribute("mand_m_1").equals("1");
boolean mandF1 = element.getAttribute("mand_f_1").equals("1");
FiguredataSettype settype = new FiguredataSettype(type, paletteId, mandM0, mandF0, mandM1, mandF1);
NodeList setsList = nNode.getChildNodes();
for(int ii = 0; ii < setsList.getLength(); ii++) {
Element setElement = (Element)setsList.item(ii);
FiguredataSettypeSet set = new FiguredataSettypeSet(
Integer.parseInt(setElement.getAttribute("id")),
setElement.getAttribute("gender"),
!setElement.getAttribute("club").equals("0"),
setElement.getAttribute("colorable").equals("1"),
setElement.getAttribute("selectable").equals("1"),
setElement.getAttribute("preselectable").equals("1"),
setElement.getAttribute("sellable").equals("1")
);
settype.addSet(set);
}
settypes.put(settype.type, settype);
}
}
}

View File

@ -0,0 +1,35 @@
package com.eu.habbo.habbohotel.users.clothingvalidation;
import java.util.Map;
import java.util.TreeMap;
public class FiguredataPalette {
public int id;
public Map<Integer, FiguredataPaletteColor> colors;
public FiguredataPalette(int id) {
this.id = id;
this.colors = new TreeMap<>();
}
public void addColor(FiguredataPaletteColor color) {
this.colors.put(color.id, color);
}
public FiguredataPaletteColor getColor(int colorId) {
return this.colors.get(colorId);
}
/**
* @return First non-club and selectable color
*/
public FiguredataPaletteColor getFirstNonHCColor() {
for(FiguredataPaletteColor color : this.colors.values()) {
if(!color.club && color.selectable)
return color;
}
return this.colors.size() > 0 ? this.colors.entrySet().iterator().next().getValue() : null;
}
}

View File

@ -0,0 +1,17 @@
package com.eu.habbo.habbohotel.users.clothingvalidation;
public class FiguredataPaletteColor {
public int id;
public int index;
public boolean club;
public boolean selectable;
public String colorHex;
public FiguredataPaletteColor(int id, int index, boolean club, boolean selectable, String colorHex) {
this.id = id;
this.index = index;
this.club = club;
this.selectable = selectable;
this.colorHex = colorHex;
}
}

View File

@ -0,0 +1,60 @@
package com.eu.habbo.habbohotel.users.clothingvalidation;
import java.util.Map;
import java.util.TreeMap;
public class FiguredataSettype {
public String type;
public int paletteId;
public boolean mandatoryMale0;
public boolean mandatoryFemale0;
public boolean mandatoryMale1;
public boolean mandatoryFemale1;
public Map<Integer, FiguredataSettypeSet> sets;
public FiguredataSettype(String type, int paletteId, boolean mandatoryMale0, boolean mandatoryFemale0, boolean mandatoryMale1, boolean mandatoryFemale1) {
this.type = type;
this.paletteId = paletteId;
this.mandatoryMale0 = mandatoryMale0;
this.mandatoryFemale0 = mandatoryFemale0;
this.mandatoryMale1 = mandatoryMale1;
this.mandatoryFemale1 = mandatoryFemale1;
this.sets = new TreeMap<>();
}
public void addSet(FiguredataSettypeSet set) {
this.sets.put(set.id, set);
}
public FiguredataSettypeSet getSet(int id) {
return this.sets.get(id);
}
/**
* @param gender Gender (M/F)
* @return First non-sellable and selectable set for given gender
*/
public FiguredataSettypeSet getFirstSetForGender(String gender) {
for(FiguredataSettypeSet set : this.sets.values()) {
if(set.gender.equalsIgnoreCase(gender) && !set.sellable && set.selectable) {
return set;
}
}
return this.sets.size() > 0 ? this.sets.entrySet().iterator().next().getValue() : null;
}
/**
* @param gender Gender (M/F)
* @return First non-club, non-sellable and selectable set for given gender
*/
public FiguredataSettypeSet getFirstNonHCSetForGender(String gender) {
for(FiguredataSettypeSet set : this.sets.values()) {
if(set.gender.equalsIgnoreCase(gender) && !set.club && !set.sellable && set.selectable) {
return set;
}
}
return getFirstSetForGender(gender);
}
}

View File

@ -0,0 +1,21 @@
package com.eu.habbo.habbohotel.users.clothingvalidation;
public class FiguredataSettypeSet {
public int id;
public String gender;
public boolean club;
public boolean colorable;
public boolean selectable;
public boolean preselectable;
public boolean sellable;
public FiguredataSettypeSet(int id, String gender, boolean club, boolean colorable, boolean selectable, boolean preselectable, boolean sellable) {
this.id = id;
this.gender = gender;
this.club = club;
this.colorable = colorable;
this.selectable = selectable;
this.preselectable = preselectable;
this.sellable = sellable;
}
}

View File

@ -14,15 +14,18 @@ import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.regex.Pattern;
public class WardrobeComponent {
private static final Logger LOGGER = LoggerFactory.getLogger(WardrobeComponent.class);
private final THashMap<Integer, WardrobeItem> looks;
private final TIntSet clothing;
private final TIntSet clothingSets;
public WardrobeComponent(Habbo habbo) {
this.looks = new THashMap<>();
this.clothing = new TIntHashSet();
this.clothingSets = new TIntHashSet();
try (Connection connection = Emulator.getDatabase().getDataSource().getConnection()) {
try (PreparedStatement statement = connection.prepareStatement("SELECT * FROM users_wardrobe WHERE user_id = ?")) {
@ -34,13 +37,19 @@ public class WardrobeComponent {
}
}
try (PreparedStatement statement = connection.prepareStatement("SELECT * FROM users_clothing WHERE user_id = ?")) {
try (PreparedStatement statement = connection.prepareStatement("SELECT users_clothing.*, catalog_clothing.setid FROM users_clothing LEFT JOIN catalog_clothing ON catalog_clothing.id = users_clothing.clothing_id WHERE users_clothing.user_id = ?")) {
statement.setInt(1, habbo.getHabboInfo().getId());
try (ResultSet set = statement.executeQuery()) {
while (set.next()) {
int value = set.getInt("clothing_id");
this.clothing.add(value);
for(String x : set.getString("setid").split(Pattern.quote(","))) {
try {
this.clothingSets.add(Integer.parseInt(x));
}
catch (Exception e) { }
}
}
}
}
@ -61,6 +70,10 @@ public class WardrobeComponent {
return this.clothing;
}
public TIntCollection getClothingSets() {
return this.clothingSets;
}
public void dispose() {
this.looks.values().stream().filter(item -> item.needsInsert || item.needsUpdate).forEach(item -> {
Emulator.getThreading().run(item);

View File

@ -0,0 +1,64 @@
package com.eu.habbo.habbohotel.users.subscriptions;
import com.eu.habbo.Emulator;
import com.eu.habbo.core.DatabaseLoggable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.sql.PreparedStatement;
import java.sql.SQLException;
/**
* @author Beny
*/
public class HcPayDayLogEntry implements Runnable, DatabaseLoggable {
private static final Logger LOGGER = LoggerFactory.getLogger(HcPayDayLogEntry.class);
private static final String QUERY = "INSERT INTO `logs_hc_payday` (`timestamp`, `user_id`, `hc_streak`, `total_coins_spent`, `reward_coins_spent`, `reward_streak`, `total_payout`, `currency`, `claimed`) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)";
public final int timestamp;
public final int userId;
public final int hcStreak;
public final int totalCoinsSpent;
public final int rewardCoinsSpent;
public final int rewardStreak;
public final int totalPayout;
public final String currency;
public final boolean claimed;
public HcPayDayLogEntry(int timestamp, int userId, int hcStreak, int totalCoinsSpent, int rewardCoinsSpent, int rewardStreak, int totalPayout, String currency, boolean claimed) {
this.timestamp = timestamp;
this.userId = userId;
this.hcStreak = hcStreak;
this.totalCoinsSpent = totalCoinsSpent;
this.rewardCoinsSpent = rewardCoinsSpent;
this.rewardStreak = rewardStreak;
this.totalPayout = totalPayout;
this.currency = currency;
this.claimed = claimed;
}
@Override
public String getQuery() {
return QUERY;
}
@Override
public void log(PreparedStatement statement) throws SQLException {
statement.setInt(1, this.timestamp);
statement.setInt(2, this.userId);
statement.setInt(3, this.hcStreak);
statement.setInt(4, this.totalCoinsSpent);
statement.setInt(5, this.rewardCoinsSpent);
statement.setInt(6, this.rewardStreak);
statement.setInt(7, this.totalPayout);
statement.setString(8, this.currency);
statement.setInt(9, this.claimed ? 1 : 0);
statement.addBatch();
}
@Override
public void run() {
Emulator.getDatabaseLogger().store(this);
}
}

View File

@ -0,0 +1,147 @@
package com.eu.habbo.habbohotel.users.subscriptions;
import com.eu.habbo.Emulator;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
/**
* @author Beny
*/
public class Subscription {
public static final String HABBO_CLUB = "HABBO_CLUB";
private final int id;
private final int userId;
private final String subscriptionType;
private final int timestampStart;
private int duration;
private boolean active;
/**
* Subscription constructor
* @param id ID of the subscription
* @param userId ID of user who has the subscription
* @param subscriptionType Subscription type name (e.g. HABBO_CLUB)
* @param timestampStart Unix timestamp start of subscription
* @param duration Length of subscription in seconds
* @param active Boolean indicating if subscription is active
*/
public Subscription(Integer id, Integer userId, String subscriptionType, Integer timestampStart, Integer duration, Boolean active) {
this.id = id;
this.userId = userId;
this.subscriptionType = subscriptionType;
this.timestampStart = timestampStart;
this.duration = duration;
this.active = active;
}
/**
* @return ID of the subscription
*/
public int getSubscriptionId() {
return id;
}
/**
* @return ID of user who has the subscription
*/
public int getUserId() {
return userId;
}
/**
* @return Subscription type name (e.g. HABBO_CLUB)
*/
public String getSubscriptionType() {
return subscriptionType;
}
/**
* @return Length of subscription in seconds
*/
public int getDuration() {
return duration;
}
/**
* Updates the Subscription record with new duration
* @param amount Length of time to add in seconds
*/
public void addDuration(int amount) {
this.duration += amount;
try (Connection connection = Emulator.getDatabase().getDataSource().getConnection()) {
try (PreparedStatement statement = connection.prepareStatement("UPDATE `users_subscriptions` SET `duration` = ? WHERE `id` = ? LIMIT 1")) {
statement.setInt(1, this.duration);
statement.setInt(2, this.id);
statement.executeUpdate();
}
} catch (SQLException e) {
SubscriptionManager.LOGGER.error("Caught SQL exception", e);
}
}
/**
* Sets the subscription as active or inactive. If active and remaining time <= 0 the SubscriptionScheduler will inactivate the subscription and call onExpired()
* @param active Boolean indicating if the subscription is active
*/
public void setActive(boolean active) {
this.active = active;
try (Connection connection = Emulator.getDatabase().getDataSource().getConnection()) {
try (PreparedStatement statement = connection.prepareStatement("UPDATE `users_subscriptions` SET `active` = ? WHERE `id` = ? LIMIT 1")) {
statement.setInt(1, this.active ? 1 : 0);
statement.setInt(2, this.id);
statement.executeUpdate();
}
} catch (SQLException e) {
SubscriptionManager.LOGGER.error("Caught SQL exception", e);
}
}
/**
* @return Remaining duration of subscription in seconds
*/
public int getRemaining() {
return (this.timestampStart + this.duration) - Emulator.getIntUnixTimestamp();
}
/**
* @return Unix timestamp start of subscription
*/
public int getTimestampStart() {
return this.timestampStart;
}
/**
* @return Unix timestamp end of subscription
*/
public int getTimestampEnd() {
return (this.timestampStart + this.duration);
}
/**
* @return Boolean indicating if the subscription is active
*/
public boolean isActive() {
return active;
}
/**
* Called when the subscription is first created
*/
public void onCreated() { }
/**
* Called when the subscription is extended or bought again when already exists
* @param duration Extended duration time in seconds
*/
public void onExtended(int duration) { }
/**
* Called by SubscriptionScheduler when isActive() && getRemaining() < 0
*/
public void onExpired() { }
}

View File

@ -0,0 +1,371 @@
package com.eu.habbo.habbohotel.users.subscriptions;
import com.eu.habbo.Emulator;
import com.eu.habbo.database.Database;
import com.eu.habbo.habbohotel.messenger.Messenger;
import com.eu.habbo.habbohotel.rooms.RoomManager;
import com.eu.habbo.habbohotel.users.Habbo;
import com.eu.habbo.habbohotel.users.HabboInfo;
import com.eu.habbo.habbohotel.users.clothingvalidation.ClothingValidationManager;
import com.eu.habbo.messages.outgoing.catalog.ClubCenterDataComposer;
import com.eu.habbo.messages.outgoing.rooms.users.RoomUserDataComposer;
import com.eu.habbo.messages.outgoing.users.*;
import gnu.trove.map.hash.THashMap;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
import java.util.TreeMap;
/**
* @author Beny
*/
public class SubscriptionHabboClub extends Subscription {
public static boolean HC_PAYDAY_ENABLED = false;
public static int HC_PAYDAY_NEXT_DATE = Integer.MAX_VALUE; // yyyy-MM-dd HH:mm:ss
public static String HC_PAYDAY_INTERVAL = "";
public static String HC_PAYDAY_QUERY = "";
public static TreeMap<Integer, Integer> HC_PAYDAY_STREAK = new TreeMap<>();
public static String HC_PAYDAY_CURRENCY = "";
public static Double HC_PAYDAY_KICKBACK_PERCENTAGE = 0.1;
/**
* When true "coins spent" will be calculated from the timestamp the user joins HC instead of from the last HC pay day execution timestamp
*/
public static boolean HC_PAYDAY_COINSSPENT_RESET_ON_EXPIRE = false;
/**
* Boolean indicating if HC pay day currency executing. Prevents double execution
*/
public static boolean isExecuting = false;
public SubscriptionHabboClub(Integer id, Integer userId, String subscriptionType, Integer timestampStart, Integer duration, Boolean active) {
super(id, userId, subscriptionType, timestampStart, duration, active);
}
/**
* Called when the subscription is first created.
* Actions:
* - Set user's max_friends to MAXIMUM_FRIENDS_HC
* - Set user's max_rooms to MAXIMUM_ROOMS_HC
* - Reset the user's HC pay day timer (used in calculating the coins spent)
* - Send associated HC packets to client
*/
@Override
public void onCreated() {
super.onCreated();
Habbo habbo = Emulator.getGameEnvironment().getHabboManager().getHabbo(this.getUserId());
habbo.getHabboStats().maxFriends = Messenger.MAXIMUM_FRIENDS_HC;
habbo.getHabboStats().maxRooms = RoomManager.MAXIMUM_ROOMS_HC;
habbo.getHabboStats().lastHCPayday = HC_PAYDAY_COINSSPENT_RESET_ON_EXPIRE ? Emulator.getIntUnixTimestamp() : HC_PAYDAY_NEXT_DATE - Emulator.timeStringToSeconds(HC_PAYDAY_INTERVAL);
Emulator.getThreading().run(habbo.getHabboStats());
if(habbo.getClient() != null) {
if((Emulator.getIntUnixTimestamp() - habbo.getHabboStats().hcMessageLastModified) < 60) {
Emulator.getThreading().run(() -> { habbo.getClient().sendResponse(new UserClubComposer(habbo)); habbo.getClient().sendResponse(new UserPermissionsComposer(habbo)); }, (Emulator.getIntUnixTimestamp() - habbo.getHabboStats().hcMessageLastModified));
}
else {
habbo.getClient().sendResponse(new UserClubComposer(habbo));
habbo.getClient().sendResponse(new UserPermissionsComposer(habbo));
}
}
}
/**
* Called when the subscription is extended by manual action (by admin command or RCON)
* Actions:
* - Extend duration of the subscription
* - Send associated HC packets to client
*/
@Override
public void addDuration(int amount) {
super.addDuration(amount);
if(amount < 0) {
Habbo habbo = Emulator.getGameEnvironment().getHabboManager().getHabbo(this.getUserId());
if(habbo != null && habbo.getClient() != null) {
habbo.getClient().sendResponse(new UserClubComposer(habbo));
habbo.getClient().sendResponse(new UserPermissionsComposer(habbo));
}
}
}
/**
* Called when the subscription is extended or bought again when already exists
* Actions:
* - Extend duration of the subscription
* - Send associated HC packets to client
*/
@Override
public void onExtended(int duration) {
super.onExtended(duration);
Habbo habbo = Emulator.getGameEnvironment().getHabboManager().getHabbo(this.getUserId());
if(habbo.getClient() != null) {
habbo.getClient().sendResponse(new UserClubComposer(habbo));
habbo.getClient().sendResponse(new UserPermissionsComposer(habbo));
}
}
/**
* Called by SubscriptionScheduler when isActive() && getRemaining() < 0
* Actions:
* - Set user's max_friends to MAXIMUM_FRIENDS
* - Set user's max_rooms to MAXIMUM_ROOMS
* - Remove HC clothing
* - Send associated HC packets to client
*/
@Override
public void onExpired() {
super.onExpired();
Habbo habbo = Emulator.getGameEnvironment().getHabboManager().getHabbo(this.getUserId());
habbo.getHabboStats().maxFriends = Messenger.MAXIMUM_FRIENDS;
habbo.getHabboStats().maxRooms = RoomManager.MAXIMUM_ROOMS_USER;
Emulator.getThreading().run(habbo.getHabboStats());
if(ClothingValidationManager.VALIDATE_ON_HC_EXPIRE) {
habbo.getHabboInfo().setLook(ClothingValidationManager.validateLook(habbo, habbo.getHabboInfo().getLook(), habbo.getHabboInfo().getGender().name()));
Emulator.getThreading().run(habbo.getHabboInfo());
if(habbo.getClient() != null) {
habbo.getClient().sendResponse(new UpdateUserLookComposer(habbo));
}
if (habbo.getHabboInfo().getCurrentRoom() != null) {
habbo.getHabboInfo().getCurrentRoom().sendComposer(new RoomUserDataComposer(habbo).compose());
}
}
if(habbo.getClient() != null) {
habbo.getClient().sendResponse(new UserClubComposer(habbo));
habbo.getClient().sendResponse(new UserPermissionsComposer(habbo));
}
}
/**
* Calculate's a users upcoming HC Pay day rewards
* @param habbo User to calculate for
* @return ClubCenterDataComposer
*/
public static ClubCenterDataComposer calculatePayday(HabboInfo habbo) {
Subscription activeSub = null;
Subscription firstEverSub = null;
int currentHcStreak = 0;
int totalCreditsSpent = 0;
int creditRewardForStreakBonus = 0;
int creditRewardForMonthlySpent = 0;
int timeUntilPayday = 0;
for(Subscription sub : habbo.getHabboStats().subscriptions) {
if(sub.getSubscriptionType().equalsIgnoreCase(Subscription.HABBO_CLUB)) {
if(firstEverSub == null || sub.getTimestampStart() < firstEverSub.getTimestampStart()) {
firstEverSub = sub;
}
if(sub.isActive()) {
activeSub = sub;
}
}
}
if(HC_PAYDAY_ENABLED && activeSub != null) {
currentHcStreak = (int)Math.floor((Emulator.getIntUnixTimestamp() - activeSub.getTimestampStart()) / (60 * 60 * 24.0));
if(currentHcStreak < 1) {
currentHcStreak = 0;
}
for(Map.Entry<Integer, Integer> set : HC_PAYDAY_STREAK.entrySet()) {
if(currentHcStreak >= set.getKey() && set.getValue() > creditRewardForStreakBonus) {
creditRewardForStreakBonus = set.getValue();
}
}
THashMap<String, Object> queryParams = new THashMap();
queryParams.put("@user_id", habbo.getId());
queryParams.put("@timestamp_start", habbo.getHabboStats().lastHCPayday);
queryParams.put("@timestamp_end", HC_PAYDAY_NEXT_DATE);
try (Connection connection = Emulator.getDatabase().getDataSource().getConnection();
PreparedStatement statement = Database.preparedStatementWithParams(connection, HC_PAYDAY_QUERY, queryParams)) {
try (ResultSet set = statement.executeQuery()) {
while (set.next()) {
totalCreditsSpent = set.getInt("amount_spent");
}
}
} catch (SQLException e) {
SubscriptionManager.LOGGER.error("Caught SQL exception", e);
}
creditRewardForMonthlySpent = (int)Math.floor(totalCreditsSpent * HC_PAYDAY_KICKBACK_PERCENTAGE);
timeUntilPayday = (HC_PAYDAY_NEXT_DATE - Emulator.getIntUnixTimestamp()) / 60;
}
return new ClubCenterDataComposer(
currentHcStreak,
(firstEverSub != null ? new SimpleDateFormat("dd-MM-yyyy").format(new Date(firstEverSub.getTimestampStart() * 1000L)) : ""),
HC_PAYDAY_KICKBACK_PERCENTAGE,
0,
0,
totalCreditsSpent,
creditRewardForStreakBonus,
creditRewardForMonthlySpent,
timeUntilPayday
);
}
/**
* Executes the HC Pay day, calculating reward for all active HABBO_CLUB subscribers and issuing rewards.
*/
public static void executePayDay() {
isExecuting = true;
int timestampNow = Emulator.getIntUnixTimestamp();
try (Connection connection = Emulator.getDatabase().getDataSource().getConnection();
PreparedStatement statement = connection.prepareStatement("SELECT user_id FROM `users_subscriptions` WHERE subscription_type = '" + Subscription.HABBO_CLUB + "' AND `active` = 1 AND `timestamp_start` < ? AND (`timestamp_start` + `duration`) > ? GROUP BY user_id")) {
statement.setInt(1, timestampNow);
statement.setInt(2, timestampNow);
try (ResultSet set = statement.executeQuery()) {
while (set.next()) {
try {
int userId = set.getInt("user_id");
HabboInfo habboInfo = Emulator.getGameEnvironment().getHabboManager().getHabboInfo(userId);
ClubCenterDataComposer calculated = calculatePayday(habboInfo);
int totalReward = (calculated.creditRewardForMonthlySpent + calculated.creditRewardForStreakBonus);
if(totalReward > 0) {
boolean claimed = claimPayDay(Emulator.getGameEnvironment().getHabboManager().getHabbo(userId), totalReward, HC_PAYDAY_CURRENCY);
HcPayDayLogEntry le = new HcPayDayLogEntry(timestampNow, userId, calculated.currentHcStreak, calculated.totalCreditsSpent, calculated.creditRewardForMonthlySpent, calculated.creditRewardForStreakBonus, totalReward, HC_PAYDAY_CURRENCY, claimed);
Emulator.getThreading().run(le);
}
habboInfo.getHabboStats().lastHCPayday = timestampNow;
}
catch (Exception e) {
SubscriptionManager.LOGGER.error("Exception processing HC payday for user #" + set.getInt("user_id"), e);
}
}
}
Date date = new java.util.Date(HC_PAYDAY_NEXT_DATE * 1000L);
date = Emulator.modifyDate(date, HC_PAYDAY_INTERVAL);
HC_PAYDAY_NEXT_DATE = (int)(date.getTime() / 1000L);
try(PreparedStatement stm2 = connection.prepareStatement("UPDATE `emulator_settings` SET `value` = ? WHERE `key` = ?")) {
SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
stm2.setString(1, sdf.format(date));
stm2.setString(2, "subscriptions.hc.payday.next_date");
stm2.execute();
}
try(PreparedStatement stm2 = connection.prepareStatement("UPDATE users_settings SET last_hc_payday = ? WHERE user_id IN (SELECT user_id FROM `users_subscriptions` WHERE subscription_type = '" + Subscription.HABBO_CLUB + "' AND `active` = 1 AND `timestamp_start` < ? AND (`timestamp_start` + `duration`) > ? GROUP BY user_id)")) {
stm2.setInt(1, timestampNow);
stm2.setInt(2, timestampNow);
stm2.setInt(3, timestampNow);
stm2.execute();
}
}
catch (SQLException e) {
SubscriptionManager.LOGGER.error("Caught SQL exception", e);
}
isExecuting = false;
}
/**
* Called when a user logs in. Checks for any unclaimed HC Pay day rewards and issues rewards.
* @param habbo User to process
*/
public static void processUnclaimed(Habbo habbo) {
try (Connection connection = Emulator.getDatabase().getDataSource().getConnection();
PreparedStatement statement = connection.prepareStatement("SELECT * FROM `logs_hc_payday` WHERE user_id = ? AND claimed = 0")) {
statement.setInt(1, habbo.getHabboInfo().getId());
try (ResultSet set = statement.executeQuery()) {
while (set.next()) {
try {
int logId = set.getInt("id");
int userId = set.getInt("user_id");
int totalPayout = set.getInt("total_payout");
String currency = set.getString("currency");
if(claimPayDay(habbo, totalPayout, currency)) {
try(PreparedStatement stm2 = connection.prepareStatement("UPDATE logs_hc_payday SET claimed = 1 WHERE id = ?")) {
stm2.setInt(1, logId);
stm2.execute();
}
}
}
catch (Exception e) {
SubscriptionManager.LOGGER.error("Exception processing HC payday for user #" + set.getInt("user_id"), e);
}
}
}
}
catch (SQLException e) {
SubscriptionManager.LOGGER.error("Caught SQL exception", e);
}
}
/**
* Issues rewards to user.
* @param habbo User to reward to
* @param amount Amount of currency to reward
* @param currency Currency string (Can be one of: credits, diamonds, duckets, pixels or a currency ID e.g. 5)
* @return Boolean indicating success of the operation
*/
public static boolean claimPayDay(Habbo habbo, int amount, String currency) {
if(habbo == null)
return false;
int pointCurrency;
switch(currency.toLowerCase()) {
case "credits":
case "coins":
case "credit":
case "coin":
habbo.getClient().getHabbo().getHabboInfo().addCredits(amount);
habbo.getClient().sendResponse(new UserCreditsComposer(habbo.getClient().getHabbo()));
break;
case "diamonds":
case "diamond":
pointCurrency = 5;
habbo.getClient().getHabbo().getHabboInfo().addCurrencyAmount(pointCurrency, amount);
habbo.getClient().sendResponse(new UserPointsComposer(habbo.getClient().getHabbo().getHabboInfo().getCurrencyAmount(pointCurrency), amount, pointCurrency));
break;
case "duckets":
case "ducket":
case "pixels":
case "pixel":
pointCurrency = 0;
habbo.getClient().getHabbo().getHabboInfo().addCurrencyAmount(pointCurrency, amount);
habbo.getClient().sendResponse(new UserPointsComposer(habbo.getClient().getHabbo().getHabboInfo().getCurrencyAmount(pointCurrency), amount, pointCurrency));
break;
default:
pointCurrency = Integer.parseInt(currency);
habbo.getClient().getHabbo().getHabboInfo().addCurrencyAmount(pointCurrency, amount);
habbo.getClient().sendResponse(new UserPointsComposer(habbo.getClient().getHabbo().getHabboInfo().getCurrencyAmount(pointCurrency), amount, pointCurrency));
break;
}
habbo.alert(Emulator.getTexts().getValue("subscriptions.hc.payday.message", "Woohoo HC Payday has arrived! You have received %amount% credits to your purse. Enjoy!").replace("%amount%", "" + amount));
return true;
}
}

View File

@ -0,0 +1,89 @@
package com.eu.habbo.habbohotel.users.subscriptions;
import com.eu.habbo.Emulator;
import gnu.trove.map.hash.THashMap;
import gnu.trove.set.hash.THashSet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* @author Beny
*/
public class SubscriptionManager {
public static final Logger LOGGER = LoggerFactory.getLogger(SubscriptionManager.class);
public THashMap<String, Class<? extends Subscription>> types;
public SubscriptionManager() {
this.types = new THashMap<>();
}
public void init() {
this.types.put(Subscription.HABBO_CLUB, SubscriptionHabboClub.class);
}
public void addSubscriptionType(String type, Class<? extends Subscription> clazz) {
if(this.types.containsKey(type) || this.types.containsValue(clazz)) {
throw new RuntimeException("Subscription Type must be unique. An class with type: " + clazz.getName() + " was already added OR the key: " + type + " is already in use.");
}
this.types.put(type, clazz);
}
public void removeSubscriptionType(String type) {
this.types.remove(type);
}
public Class<? extends Subscription> getSubscriptionClass(String type) {
if(!this.types.containsKey(type)) {
LOGGER.debug("Can't find subscription class: {}", type);
return Subscription.class;
}
return this.types.get(type);
}
public void dispose() {
this.types.clear();
}
public THashSet<Subscription> getSubscriptionsForUser(int userId) {
THashSet<Subscription> subscriptions = new THashSet<>();
try (Connection connection = Emulator.getDatabase().getDataSource().getConnection();
PreparedStatement statement = connection.prepareStatement("SELECT * FROM users_subscriptions WHERE user_id = ?")) {
statement.setInt(1, userId);
try (ResultSet set = statement.executeQuery()) {
while (set.next()) {
Class<? extends Subscription> subClazz = Emulator.getGameEnvironment().getSubscriptionManager().getSubscriptionClass(set.getString("subscription_type"));
Constructor<? extends Subscription> c = subClazz.getConstructor(Integer.class, Integer.class, String.class, Integer.class, Integer.class, Boolean.class);
c.setAccessible(true);
Subscription subscription = c.newInstance(set.getInt("id"), set.getInt("user_id"), set.getString("subscription_type"), set.getInt("timestamp_start"), set.getInt("duration"), set.getInt("active") == 1);
subscriptions.add(subscription);
}
} catch (IllegalAccessException e) {
LOGGER.error("IllegalAccessException", e);
} catch (InstantiationException e) {
LOGGER.error("InstantiationException", e);
} catch (InvocationTargetException e) {
LOGGER.error("InvocationTargetException", e);
}
} catch (SQLException e) {
LOGGER.error("Caught SQL exception", e);
}
catch (NoSuchMethodException e) {
LOGGER.error("Caught NoSuchMethodException", e);
}
return subscriptions;
}
}

View File

@ -0,0 +1,74 @@
package com.eu.habbo.habbohotel.users.subscriptions;
import com.eu.habbo.Emulator;
import com.eu.habbo.core.Scheduler;
import com.eu.habbo.habbohotel.users.Habbo;
import com.eu.habbo.plugin.events.users.subscriptions.UserSubscriptionExpiredEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Map;
/**
* @author Beny
*/
public class SubscriptionScheduler extends Scheduler {
private static final Logger LOGGER = LoggerFactory.getLogger(SubscriptionScheduler.class);
public SubscriptionScheduler() {
super(Emulator.getConfig().getInt("subscriptions.scheduler.interval", 10));
this.reloadConfig();
}
/**
* Called when config is changed. Should end the scheduler if disabled.
*/
public void reloadConfig() {
if (Emulator.getConfig().getBoolean("subscriptions.scheduler.enabled", true)) {
if (this.disposed) {
this.disposed = false;
this.run();
}
} else {
this.disposed = true;
}
}
@Override
public void run() {
super.run();
Habbo habbo;
for (Map.Entry<Integer, Habbo> map : Emulator.getGameEnvironment().getHabboManager().getOnlineHabbos().entrySet()) {
habbo = map.getValue();
try {
if (habbo != null) {
for(Subscription subscription : habbo.getHabboStats().subscriptions) {
if(subscription.isActive() && subscription.getRemaining() < 0) {
if (!Emulator.getPluginManager().fireEvent(new UserSubscriptionExpiredEvent(habbo.getHabboInfo().getId(), subscription)).isCancelled()) {
subscription.onExpired();
subscription.setActive(false);
}
}
}
}
} catch (Exception e) {
LOGGER.error("Caught exception", e);
}
}
if(SubscriptionHabboClub.HC_PAYDAY_ENABLED && !SubscriptionHabboClub.isExecuting && SubscriptionHabboClub.HC_PAYDAY_NEXT_DATE < Emulator.getIntUnixTimestamp()) {
SubscriptionHabboClub.executePayDay();
}
}
public boolean isDisposed() {
return this.disposed;
}
public void setDisposed(boolean disposed) {
this.disposed = disposed;
}
}

View File

@ -12,6 +12,7 @@ import com.eu.habbo.habbohotel.permissions.Permission;
import com.eu.habbo.habbohotel.pets.PetManager;
import com.eu.habbo.habbohotel.users.HabboBadge;
import com.eu.habbo.habbohotel.users.HabboInventory;
import com.eu.habbo.habbohotel.users.subscriptions.Subscription;
import com.eu.habbo.messages.incoming.MessageHandler;
import com.eu.habbo.messages.outgoing.catalog.AlertPurchaseFailedComposer;
import com.eu.habbo.messages.outgoing.catalog.AlertPurchaseUnavailableComposer;
@ -176,12 +177,19 @@ public class CatalogBuyItemEvent extends MessageHandler {
if (!this.client.getHabbo().hasPermission(Permission.ACC_INFINITE_POINTS))
this.client.getHabbo().getHabboInfo().addCurrencyAmount(item.getPointsType(), -totalDuckets);
if (this.client.getHabbo().getHabboStats().getClubExpireTimestamp() <= Emulator.getIntUnixTimestamp())
if(this.client.getHabbo().getHabboStats().createSubscription(Subscription.HABBO_CLUB, (totalDays * 86400)) == null) {
this.client.sendResponse(new AlertPurchaseFailedComposer(AlertPurchaseFailedComposer.SERVER_ERROR).compose());
throw new Exception("Unable to create or extend subscription");
}
/*if (this.client.getHabbo().getHabboStats().getClubExpireTimestamp() <= Emulator.getIntUnixTimestamp())
this.client.getHabbo().getHabboStats().setClubExpireTimestamp(Emulator.getIntUnixTimestamp());
this.client.getHabbo().getHabboStats().setClubExpireTimestamp(this.client.getHabbo().getHabboStats().getClubExpireTimestamp() + (totalDays * 86400));
this.client.sendResponse(new UserPermissionsComposer(this.client.getHabbo()));
this.client.sendResponse(new UserClubComposer(this.client.getHabbo()));
this.client.sendResponse(new UserClubComposer(this.client.getHabbo()));*/
if (totalCredits > 0)
this.client.sendResponse(new UserCreditsComposer(this.client.getHabbo()));

View File

@ -1,11 +1,14 @@
package com.eu.habbo.messages.incoming.catalog;
import com.eu.habbo.habbohotel.users.subscriptions.SubscriptionHabboClub;
import com.eu.habbo.messages.incoming.MessageHandler;
import com.eu.habbo.messages.outgoing.catalog.ClubCenterDataComposer;
import com.eu.habbo.messages.outgoing.catalog.ClubDataComposer;
public class RequestClubDataEvent extends MessageHandler {
@Override
public void handle() throws Exception {
this.client.sendResponse(new ClubDataComposer(this.client.getHabbo(), this.packet.readInt()));
this.client.sendResponse(SubscriptionHabboClub.calculatePayday(this.client.getHabbo().getHabboInfo()));
}
}

View File

@ -4,6 +4,8 @@ import com.eu.habbo.Emulator;
import com.eu.habbo.habbohotel.messenger.Messenger;
import com.eu.habbo.habbohotel.users.Habbo;
import com.eu.habbo.messages.incoming.MessageHandler;
import com.eu.habbo.messages.outgoing.friends.FriendRequestErrorComposer;
import com.eu.habbo.plugin.PluginManager;
public class AcceptFriendRequestEvent extends MessageHandler {
@Override
@ -17,18 +19,33 @@ public class AcceptFriendRequestEvent extends MessageHandler {
if (userId == 0)
return;
if (this.client.getHabbo().getMessenger().getFriends().containsKey(userId))
if (this.client.getHabbo().getMessenger().getFriends().containsKey(userId)) {
this.client.getHabbo().getMessenger().deleteFriendRequests(userId, this.client.getHabbo().getHabboInfo().getId());
continue;
}
Habbo target = Emulator.getGameEnvironment().getHabboManager().getHabbo(userId);
if(target == null) {
this.client.sendResponse(new FriendRequestErrorComposer(FriendRequestErrorComposer.TARGET_NOT_FOUND));
this.client.getHabbo().getMessenger().deleteFriendRequests(userId, this.client.getHabbo().getHabboInfo().getId());
continue;
}
if(this.client.getHabbo().getMessenger().getFriends().size() >= this.client.getHabbo().getHabboStats().maxFriends && !this.client.getHabbo().hasPermission("acc_infinite_friends")) {
this.client.sendResponse(new FriendRequestErrorComposer(FriendRequestErrorComposer.FRIEND_LIST_OWN_FULL));
break;
}
if(target.getMessenger().getFriends().size() >= target.getHabboStats().maxFriends && !target.hasPermission("acc_infinite_friends")) {
this.client.sendResponse(new FriendRequestErrorComposer(FriendRequestErrorComposer.FRIEND_LIST_TARGET_FULL));
continue;
}
this.client.getHabbo().getMessenger().acceptFriendRequest(userId, this.client.getHabbo().getHabboInfo().getId());
Messenger.checkFriendSizeProgress(this.client.getHabbo());
Habbo target = Emulator.getGameEnvironment().getHabboManager().getHabbo(userId);
if (target != null) {
Messenger.checkFriendSizeProgress(target);
}
}
}
}

View File

@ -74,10 +74,16 @@ public class FriendRequestEvent extends MessageHandler {
return;
}
if (this.client.getHabbo().getMessenger().getFriends().values().size() >= Messenger.friendLimit(this.client.getHabbo()) && !this.client.getHabbo().hasPermission("acc_infinite_friends")) {
if (this.client.getHabbo().getMessenger().getFriends().values().size() >= this.client.getHabbo().getHabboStats().maxFriends && !this.client.getHabbo().hasPermission("acc_infinite_friends")) {
this.client.sendResponse(new FriendRequestErrorComposer(FriendRequestErrorComposer.FRIEND_LIST_OWN_FULL));
return;
}
if (habbo.getMessenger().getFriends().values().size() >= habbo.getHabboStats().maxFriends && !habbo.hasPermission("acc_infinite_friends")) {
this.client.sendResponse(new FriendRequestErrorComposer(FriendRequestErrorComposer.FRIEND_LIST_TARGET_FULL));
return;
}
Messenger.makeFriendRequest(this.client.getHabbo().getHabboInfo().getId(), id);
} else {
this.client.sendResponse(new FriendRequestErrorComposer(FriendRequestErrorComposer.TARGET_NOT_FOUND));

View File

@ -8,6 +8,8 @@ import com.eu.habbo.habbohotel.navigation.NavigatorSavedSearch;
import com.eu.habbo.habbohotel.permissions.Permission;
import com.eu.habbo.habbohotel.users.Habbo;
import com.eu.habbo.habbohotel.users.HabboManager;
import com.eu.habbo.habbohotel.users.clothingvalidation.ClothingValidationManager;
import com.eu.habbo.habbohotel.users.subscriptions.SubscriptionHabboClub;
import com.eu.habbo.messages.NoAuthMessage;
import com.eu.habbo.messages.ServerMessage;
import com.eu.habbo.messages.incoming.MessageHandler;
@ -105,6 +107,14 @@ public class SecureLoginEvent extends MessageHandler {
Emulator.getGameServer().getGameClientManager().disposeClient(this.client);
return;
}
if(ClothingValidationManager.VALIDATE_ON_LOGIN) {
String validated = ClothingValidationManager.validateLook(this.client.getHabbo());
if(!validated.equals(this.client.getHabbo().getHabboInfo().getLook())) {
this.client.getHabbo().getHabboInfo().setLook(validated);
}
}
ArrayList<ServerMessage> messages = new ArrayList<>();
messages.add(new SecureLoginOKComposer().compose());
@ -194,6 +204,10 @@ public class SecureLoginEvent extends MessageHandler {
}, Emulator.getConfig().getInt("hotel.welcome.alert.delay", 5000));
}
if(SubscriptionHabboClub.HC_PAYDAY_ENABLED) {
SubscriptionHabboClub.processUnclaimed(habbo);
}
Messenger.checkFriendSizeProgress(habbo);
if (!habbo.getHabboStats().hasGottenDefaultSavedSearches) {

View File

@ -9,7 +9,7 @@ public class RequestCanCreateRoomEvent extends MessageHandler {
@Override
public void handle() throws Exception {
int count = Emulator.getGameEnvironment().getRoomManager().getRoomsForHabbo(this.client.getHabbo()).size();
int max = this.client.getHabbo().getHabboStats().hasActiveClub() ? RoomManager.MAXIMUM_ROOMS_VIP : RoomManager.MAXIMUM_ROOMS_USER;
int max = this.client.getHabbo().getHabboStats().maxRooms;
this.client.sendResponse(new CanCreateRoomComposer(count, max));
}
}

View File

@ -48,7 +48,7 @@ public class RequestCreateRoomEvent extends MessageHandler {
return;
int count = Emulator.getGameEnvironment().getRoomManager().getRoomsForHabbo(this.client.getHabbo()).size();
int max = this.client.getHabbo().getHabboStats().hasActiveClub() ? RoomManager.MAXIMUM_ROOMS_VIP : RoomManager.MAXIMUM_ROOMS_USER;
int max = this.client.getHabbo().getHabboStats().maxRooms;
if (count >= max) {
this.client.sendResponse(new CanCreateRoomComposer(count, max));

View File

@ -53,6 +53,7 @@ public class RedeemClothingEvent extends MessageHandler {
}
this.client.getHabbo().getInventory().getWardrobeComponent().getClothing().add(clothing.id);
this.client.getHabbo().getInventory().getWardrobeComponent().getClothingSets().addAll(clothing.setId);
this.client.sendResponse(new UserClothesComposer(this.client.getHabbo()));
this.client.sendResponse(new BubbleAlertComposer(BubbleAlertKeys.FIGURESET_REDEEMED.key));

View File

@ -4,6 +4,7 @@ import com.eu.habbo.Emulator;
import com.eu.habbo.habbohotel.achievements.AchievementManager;
import com.eu.habbo.habbohotel.modtool.ScripterManager;
import com.eu.habbo.habbohotel.users.HabboGender;
import com.eu.habbo.habbohotel.users.clothingvalidation.ClothingValidationManager;
import com.eu.habbo.messages.incoming.MessageHandler;
import com.eu.habbo.messages.outgoing.rooms.users.RoomUserDataComposer;
import com.eu.habbo.messages.outgoing.users.UpdateUserLookComposer;
@ -35,7 +36,7 @@ public class UserSaveLookEvent extends MessageHandler {
if (lookEvent.isCancelled())
return;
this.client.getHabbo().getHabboInfo().setLook(lookEvent.newLook);
this.client.getHabbo().getHabboInfo().setLook(ClothingValidationManager.VALIDATE_ON_CHANGE_LOOKS ? ClothingValidationManager.validateLook(this.client.getHabbo(), lookEvent.newLook, lookEvent.gender.name()) : lookEvent.newLook);
this.client.getHabbo().getHabboInfo().setGender(lookEvent.gender);
Emulator.getThreading().run(this.client.getHabbo().getHabboInfo());
this.client.sendResponse(new UpdateUserLookComposer(this.client.getHabbo()));

View File

@ -1,40 +1,54 @@
package com.eu.habbo.messages.outgoing.catalog;
import com.eu.habbo.Emulator;
import com.eu.habbo.habbohotel.users.Habbo;
import com.eu.habbo.habbohotel.users.subscriptions.Subscription;
import com.eu.habbo.habbohotel.users.subscriptions.SubscriptionHabboClub;
import com.eu.habbo.messages.ServerMessage;
import com.eu.habbo.messages.outgoing.MessageComposer;
import com.eu.habbo.messages.outgoing.Outgoing;
public class ClubCenterDataComposer extends MessageComposer {
private final int streakDuration;
private final String joinDate;
private final double percentage;
private final int creditsSpend;
private final int creditsBonus;
private final int spendBonus;
private final int delay;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
public ClubCenterDataComposer(int streakDuration, String joinDate, double percentage, int creditsSpend, int creditsBonus, int spendBonus, int delay) {
this.streakDuration = streakDuration;
this.joinDate = joinDate;
this.percentage = percentage;
this.creditsSpend = creditsSpend;
this.creditsBonus = creditsBonus;
this.spendBonus = spendBonus;
this.delay = delay;
public class ClubCenterDataComposer extends MessageComposer {
public final int currentHcStreak;
public final String firstSubDate;
public final double kickbackPercentage;
public final int totalCreditsMissed;
public final int totalCreditsRewarded;
public final int totalCreditsSpent;
public final int creditRewardForStreakBonus;
public final int creditRewardForMonthlySpent;
public final int timeUntilPayday;
public ClubCenterDataComposer(int currentHcStreak, String firstSubDate, double kickbackPercentage, int totalCreditsMissed, int totalCreditsRewarded, int totalCreditsSpent, int creditRewardForStreakBonus, int creditRewardForMonthlySpent, int timeUntilPayday) {
this.currentHcStreak = currentHcStreak;
this.firstSubDate = firstSubDate;
this.kickbackPercentage = kickbackPercentage;
this.totalCreditsMissed = totalCreditsMissed;
this.totalCreditsRewarded = totalCreditsRewarded;
this.totalCreditsSpent = totalCreditsSpent;
this.creditRewardForStreakBonus = creditRewardForStreakBonus;
this.creditRewardForMonthlySpent = creditRewardForMonthlySpent;
this.timeUntilPayday = timeUntilPayday;
}
@Override
protected ServerMessage composeInternal() {
this.response.init(Outgoing.ClubCenterDataComposer);
this.response.appendInt(this.streakDuration); //streakduration in days
this.response.appendString(this.joinDate); //joindate
this.response.appendDouble(this.percentage); //percentage
this.response.appendInt(0); //Unused
this.response.appendInt(0); //unused
this.response.appendInt(this.creditsSpend); //Amount credits spend
this.response.appendInt(this.creditsBonus); //Credits bonus
this.response.appendInt(this.spendBonus); //Spend bonus
this.response.appendInt(this.delay); //next pay in minutes
this.response.appendInt(this.currentHcStreak); // currentHcStreak (days)
this.response.appendString(this.firstSubDate); // firstSubscriptionDate (dd-mm-yyyy)
this.response.appendDouble(this.kickbackPercentage); // kickbackPercentage (e.g. 0.1 for 10%)
this.response.appendInt(this.totalCreditsMissed); // (not used)
this.response.appendInt(this.totalCreditsRewarded); // (not used)
this.response.appendInt(this.totalCreditsSpent);
this.response.appendInt(this.creditRewardForStreakBonus);
this.response.appendInt(this.creditRewardForMonthlySpent);
this.response.appendInt(this.timeUntilPayday); // timeUntilPayday (minutes)
return this.response;
}
}

View File

@ -6,6 +6,7 @@ import com.eu.habbo.messages.outgoing.Outgoing;
public class FriendRequestErrorComposer extends MessageComposer {
public static final int FRIEND_LIST_OWN_FULL = 1;
public static final int FRIEND_LIST_TARGET_FULL = 2;
public static final int TARGET_NOT_ACCEPTING_REQUESTS = 3;
public static final int TARGET_NOT_FOUND = 4;

View File

@ -30,7 +30,7 @@ public class FriendsComposer extends MessageComposer {
//this.response.appendInt(300);
//this.response.appendInt(3); //Club level
this.response.appendInt(this.habbo.hasPermission("acc_infinite_friends") ? Integer.MAX_VALUE : Messenger.MAXIMUM_FRIENDS);
this.response.appendInt(this.habbo.hasPermission("acc_infinite_friends") ? Integer.MAX_VALUE : Messenger.MAXIMUM_FRIENDS);
this.response.appendInt(this.habbo.hasPermission("acc_infinite_friends") ? Integer.MAX_VALUE : Messenger.MAXIMUM_FRIENDS_HC);
this.response.appendInt(this.habbo.getMessenger().getFriends().size()/* + (this.habbo.hasPermission("acc_staff_chat") ? 1 : 0)*/);
for (Map.Entry<Integer, MessengerBuddy> row : this.habbo.getMessenger().getFriends().entrySet()) {

View File

@ -2,10 +2,15 @@ package com.eu.habbo.messages.outgoing.users;
import com.eu.habbo.Emulator;
import com.eu.habbo.habbohotel.users.Habbo;
import com.eu.habbo.habbohotel.users.subscriptions.Subscription;
import com.eu.habbo.messages.ServerMessage;
import com.eu.habbo.messages.outgoing.MessageComposer;
import com.eu.habbo.messages.outgoing.Outgoing;
import java.time.Period;
import java.util.Date;
import java.util.concurrent.TimeUnit;
public class UserClubComposer extends MessageComposer {
private final Habbo habbo;
@ -19,6 +24,47 @@ public class UserClubComposer extends MessageComposer {
this.response.appendString("club_habbo");
Subscription subscription = this.habbo.getHabboStats().getSubscription(Subscription.HABBO_CLUB);
int days = 0;
int minutes = 0;
int timeRemaining = 0;
if(subscription != null) {
timeRemaining = subscription.getRemaining();
days = (int) Math.floor(timeRemaining / 86400.0);
minutes = (int) Math.ceil(timeRemaining / 60.0);
if(days < 1 && minutes > 0) {
days = 1;
}
}
this.response.appendInt(days); // daysToPeriodEnd
this.response.appendInt(0); // memberPeriods
this.response.appendInt(0); // periodsSubscribedAhead
this.response.appendInt(0); // responseType
this.response.appendBoolean(true); // hasEverBeenMember
this.response.appendBoolean(true); // isVIP
this.response.appendInt(0); // pastClubDays
this.response.appendInt(0); // pastVIPdays
this.response.appendInt(minutes); // minutesTillExpiration
this.response.appendInt((Emulator.getIntUnixTimestamp() - this.habbo.getHabboStats().hcMessageLastModified) / 60); // minutesSinceLastModified
this.habbo.getHabboStats().hcMessageLastModified = Emulator.getIntUnixTimestamp();
// int - daysToPeriodEnd
// int - memberPeriods
// int - periodsSubscribedAhead
// int - responseType
// bool - hasEverBeenMember
// bool - isVIP
// int - pastClubDays
// int - pastVIPdays
// int - minutesTillExpiration
// (optional) int - minutesSinceLastModified
/*
int endTimestamp = this.habbo.getHabboStats().getClubExpireTimestamp();
int now = Emulator.getIntUnixTimestamp();
@ -48,6 +94,7 @@ public class UserClubComposer extends MessageComposer {
this.response.appendInt(0);
this.response.appendInt(1);
}
this.response.appendBoolean(true);
this.response.appendBoolean(true);
this.response.appendInt(0);
@ -60,6 +107,7 @@ public class UserClubComposer extends MessageComposer {
} else {
this.response.appendInt((int) remaining);
}
*/
return this.response;
}

View File

@ -21,8 +21,11 @@ import com.eu.habbo.habbohotel.navigation.EventCategory;
import com.eu.habbo.habbohotel.navigation.NavigatorManager;
import com.eu.habbo.habbohotel.pets.PetManager;
import com.eu.habbo.habbohotel.rooms.*;
import com.eu.habbo.habbohotel.users.clothingvalidation.ClothingValidationManager;
import com.eu.habbo.habbohotel.users.HabboInventory;
import com.eu.habbo.habbohotel.users.HabboManager;
import com.eu.habbo.habbohotel.users.subscriptions.SubscriptionHabboClub;
import com.eu.habbo.habbohotel.users.subscriptions.SubscriptionManager;
import com.eu.habbo.habbohotel.wired.WiredHandler;
import com.eu.habbo.habbohotel.wired.highscores.WiredHighscoreManager;
import com.eu.habbo.messages.PacketManager;
@ -59,6 +62,7 @@ import java.net.URLClassLoader;
import java.util.Arrays;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
public class PluginManager {
@ -97,8 +101,8 @@ public class PluginManager {
Bot.PLACEMENT_MESSAGES = Emulator.getConfig().getValue("hotel.bot.placement.messages", "Yo!;Hello I'm a real party animal!;Hello!").split(";");
HabboInventory.MAXIMUM_ITEMS = Emulator.getConfig().getInt("hotel.inventory.max.items");
Messenger.MAXIMUM_FRIENDS = Emulator.getConfig().getInt("hotel.max.friends");
Messenger.MAXIMUM_FRIENDS_HC = Emulator.getConfig().getInt("hotel.max.friends.hc");
Messenger.MAXIMUM_FRIENDS = Emulator.getConfig().getInt("hotel.users.max.friends", 300);
Messenger.MAXIMUM_FRIENDS_HC = Emulator.getConfig().getInt("hotel.users.max.friends.hc", 1100);
Room.MAXIMUM_BOTS = Emulator.getConfig().getInt("hotel.max.bots.room");
Room.MAXIMUM_PETS = Emulator.getConfig().getInt("hotel.pets.max.room");
Room.MAXIMUM_FURNI = Emulator.getConfig().getInt("hotel.room.furni.max", 2500);
@ -107,8 +111,8 @@ public class PluginManager {
Room.IDLE_CYCLES = Emulator.getConfig().getInt("hotel.roomuser.idle.cycles", 240);
Room.IDLE_CYCLES_KICK = Emulator.getConfig().getInt("hotel.roomuser.idle.cycles.kick", 480);
Room.ROLLERS_MAXIMUM_ROLL_AVATARS = Emulator.getConfig().getInt("hotel.room.rollers.roll_avatars.max", 1);
RoomManager.MAXIMUM_ROOMS_VIP = Emulator.getConfig().getInt("hotel.max.rooms.vip");
RoomManager.MAXIMUM_ROOMS_USER = Emulator.getConfig().getInt("hotel.max.rooms.user");
RoomManager.MAXIMUM_ROOMS_USER = Emulator.getConfig().getInt("hotel.users.max.rooms", 50);
RoomManager.MAXIMUM_ROOMS_HC = Emulator.getConfig().getInt("hotel.users.max.rooms.hc", 75);
RoomManager.HOME_ROOM_ID = Emulator.getConfig().getInt("hotel.home.room");
WiredHandler.MAXIMUM_FURNI_SELECTION = Emulator.getConfig().getInt("hotel.wired.furni.selection.count");
WiredHandler.TELEPORT_DELAY = Emulator.getConfig().getInt("wired.effect.teleport.delay", 500);
@ -162,6 +166,49 @@ public class PluginManager {
PetManager.MAXIMUM_PET_INVENTORY_SIZE = Emulator.getConfig().getInt("hotel.pets.max.inventory");
SubscriptionHabboClub.HC_PAYDAY_ENABLED = Emulator.getConfig().getBoolean("subscriptions.hc.payday.enabled", false);
try {
SubscriptionHabboClub.HC_PAYDAY_NEXT_DATE = (int) (Emulator.stringToDate(Emulator.getConfig().getValue("subscriptions.hc.payday.next_date")).getTime() / 1000);
}
catch(Exception e) { SubscriptionHabboClub.HC_PAYDAY_NEXT_DATE = Integer.MAX_VALUE; }
SubscriptionHabboClub.HC_PAYDAY_INTERVAL = Emulator.getConfig().getValue("subscriptions.hc.payday.interval");
SubscriptionHabboClub.HC_PAYDAY_QUERY = Emulator.getConfig().getValue("subscriptions.hc.payday.query");
SubscriptionHabboClub.HC_PAYDAY_CURRENCY = Emulator.getConfig().getValue("subscriptions.hc.payday.currency");
SubscriptionHabboClub.HC_PAYDAY_KICKBACK_PERCENTAGE = Emulator.getConfig().getInt("subscriptions.hc.payday.percentage", 10) / 100.0;
SubscriptionHabboClub.HC_PAYDAY_COINSSPENT_RESET_ON_EXPIRE = Emulator.getConfig().getBoolean("subscriptions.hc.payday.creditsspent_reset_on_expire", false);
SubscriptionHabboClub.HC_PAYDAY_STREAK.clear();
for (String streak : Emulator.getConfig().getValue("subscriptions.hc.payday.streak", "7=5;30=10;60=15;90=20;180=25;365=30").split(Pattern.quote(";"))) {
if(streak.contains("=")) {
SubscriptionHabboClub.HC_PAYDAY_STREAK.put(Integer.parseInt(streak.split(Pattern.quote("="))[0]), Integer.parseInt(streak.split(Pattern.quote("="))[1]));
}
}
ClothingValidationManager.VALIDATE_ON_HC_EXPIRE = Emulator.getConfig().getBoolean("hotel.users.clothingvalidation.onhcexpired", false);
ClothingValidationManager.VALIDATE_ON_LOGIN = Emulator.getConfig().getBoolean("hotel.users.clothingvalidation.onlogin", false);
ClothingValidationManager.VALIDATE_ON_CHANGE_LOOKS = Emulator.getConfig().getBoolean("hotel.users.clothingvalidation.onchangelooks", false);
ClothingValidationManager.VALIDATE_ON_MIMIC = Emulator.getConfig().getBoolean("hotel.users.clothingvalidation.onmimic", false);
ClothingValidationManager.VALIDATE_ON_MANNEQUIN = Emulator.getConfig().getBoolean("hotel.users.clothingvalidation.onmannequin", false);
ClothingValidationManager.VALIDATE_ON_FBALLGATE = Emulator.getConfig().getBoolean("hotel.users.clothingvalidation.onfballgate", false);
String newUrl = Emulator.getConfig().getValue("gamedata.figuredata.url");
if(!ClothingValidationManager.FIGUREDATA_URL.equals(newUrl)) {
ClothingValidationManager.FIGUREDATA_URL = newUrl;
ClothingValidationManager.reloadFiguredata(newUrl);
}
if(newUrl.isEmpty()) {
ClothingValidationManager.VALIDATE_ON_HC_EXPIRE = false;
ClothingValidationManager.VALIDATE_ON_LOGIN = false;
ClothingValidationManager.VALIDATE_ON_CHANGE_LOOKS = false;
ClothingValidationManager.VALIDATE_ON_MIMIC = false;
ClothingValidationManager.VALIDATE_ON_MANNEQUIN = false;
ClothingValidationManager.VALIDATE_ON_FBALLGATE = false;
}
NewNavigatorEventCategoriesComposer.CATEGORIES.clear();
for (String category : Emulator.getConfig().getValue("navigator.eventcategories", "").split(";")) {
try {
@ -179,6 +226,7 @@ public class PluginManager {
Emulator.getGameEnvironment().getPointsScheduler().reloadConfig();
Emulator.getGameEnvironment().getPixelScheduler().reloadConfig();
Emulator.getGameEnvironment().getGotwPointsScheduler().reloadConfig();
Emulator.getGameEnvironment().subscriptionScheduler.reloadConfig();
}
}

View File

@ -0,0 +1,17 @@
package com.eu.habbo.plugin.events.users.subscriptions;
import com.eu.habbo.plugin.Event;
public class UserSubscriptionCreatedEvent extends Event {
public final int userId;
public final String subscriptionType;
public final int duration;
public UserSubscriptionCreatedEvent(int userId, String subscriptionType, int duration) {
super();
this.userId = userId;
this.subscriptionType = subscriptionType;
this.duration = duration;
}
}

View File

@ -0,0 +1,16 @@
package com.eu.habbo.plugin.events.users.subscriptions;
import com.eu.habbo.habbohotel.users.subscriptions.Subscription;
import com.eu.habbo.plugin.Event;
public class UserSubscriptionExpiredEvent extends Event {
public final int userId;
public final Subscription subscription;
public UserSubscriptionExpiredEvent(int userId, Subscription subscription) {
super();
this.userId = userId;
this.subscription = subscription;
}
}

View File

@ -0,0 +1,17 @@
package com.eu.habbo.plugin.events.users.subscriptions;
import com.eu.habbo.habbohotel.users.subscriptions.Subscription;
import com.eu.habbo.plugin.Event;
public class UserSubscriptionExtendedEvent extends Event {
public final int userId;
public final Subscription subscription;
public final int duration;
public UserSubscriptionExtendedEvent(int userId, Subscription subscription, int duration) {
super();
this.userId = userId;
this.subscription = subscription;
this.duration = duration;
}
}