diff --git a/sqlupdates/2_1_1_TO_2_2_0-RC-1.sql b/sqlupdates/2_1_1_TO_2_2_0-RC-1.sql index 7d4b4451..408a2bf6 100644 --- a/sqlupdates/2_1_1_TO_2_2_0-RC-1.sql +++ b/sqlupdates/2_1_1_TO_2_2_0-RC-1.sql @@ -19,4 +19,16 @@ CREATE TABLE `items_highscore_data` ( `is_win` tinyint(1) NULL DEFAULT 0, `timestamp` int(11) NOT NULL, PRIMARY KEY (`id`) -); \ No newline at end of file +); + +CREATE TABLE `voucher_history` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `voucher_id` int(11) NOT NULL, + `user_id` int(11) NOT NULL, + `timestamp` int(11) NOT NULL, + PRIMARY KEY (`id`) +); + +ALTER TABLE `vouchers` +ADD COLUMN `amount` int(11) NOT NULL DEFAULT 1, +ADD COLUMN `limit` int(11) NOT NULL DEFAULT -1; diff --git a/src/main/java/com/eu/habbo/habbohotel/catalog/CatalogManager.java b/src/main/java/com/eu/habbo/habbohotel/catalog/CatalogManager.java index f5dc975e..68db8eea 100644 --- a/src/main/java/com/eu/habbo/habbohotel/catalog/CatalogManager.java +++ b/src/main/java/com/eu/habbo/habbohotel/catalog/CatalogManager.java @@ -24,6 +24,7 @@ import com.eu.habbo.messages.outgoing.inventory.AddBotComposer; import com.eu.habbo.messages.outgoing.inventory.AddHabboItemComposer; import com.eu.habbo.messages.outgoing.inventory.AddPetComposer; import com.eu.habbo.messages.outgoing.inventory.InventoryRefreshComposer; +import com.eu.habbo.messages.outgoing.modtool.ModToolIssueHandledComposer; import com.eu.habbo.messages.outgoing.users.AddUserBadgeComposer; import com.eu.habbo.messages.outgoing.users.UserCreditsComposer; import com.eu.habbo.messages.outgoing.users.UserPointsComposer; @@ -31,7 +32,6 @@ import com.eu.habbo.plugin.events.emulator.EmulatorLoadCatalogManagerEvent; import com.eu.habbo.plugin.events.users.catalog.UserCatalogFurnitureBoughtEvent; import com.eu.habbo.plugin.events.users.catalog.UserCatalogItemPurchasedEvent; import gnu.trove.TCollections; -import gnu.trove.iterator.TIntIterator; import gnu.trove.iterator.TIntObjectIterator; import gnu.trove.map.TIntObjectMap; import gnu.trove.map.hash.THashMap; @@ -534,35 +534,52 @@ public class CatalogManager { public void redeemVoucher(GameClient client, String voucherCode) { Voucher voucher = Emulator.getGameEnvironment().getCatalogManager().getVoucher(voucherCode); - if (voucher != null) { - if (Emulator.getGameEnvironment().getCatalogManager().deleteVoucher(voucher)) { - client.getHabbo().getHabboInfo().addCredits(voucher.credits); + if (voucher == null) { + client.sendResponse(new RedeemVoucherErrorComposer(RedeemVoucherErrorComposer.INVALID_CODE)); + return; + } - if (voucher.points > 0) { - client.getHabbo().getHabboInfo().addCurrencyAmount(voucher.pointsType, voucher.points); - client.sendResponse(new UserPointsComposer(client.getHabbo().getHabboInfo().getCurrencyAmount(voucher.pointsType), voucher.points, voucher.pointsType)); - } + Habbo habbo = client.getHabbo(); + if (habbo == null) return; - if (voucher.credits > 0) { - client.getHabbo().getHabboInfo().addCredits(voucher.credits); - client.sendResponse(new UserCreditsComposer(client.getHabbo())); - } - - if (voucher.catalogItemId > 0) { - CatalogItem item = this.getCatalogItem(voucher.catalogItemId); - - if (item != null) { - this.purchaseItem(null, item, client.getHabbo(), 1, "", true); - } - } - - client.sendResponse(new RedeemVoucherOKComposer()); - - return; + if (voucher.isExhausted()) { + if (!Emulator.getGameEnvironment().getCatalogManager().deleteVoucher(voucher)) { + client.sendResponse(new RedeemVoucherErrorComposer(RedeemVoucherErrorComposer.TECHNICAL_ERROR)); } } - client.sendResponse(new RedeemVoucherErrorComposer(RedeemVoucherErrorComposer.INVALID_CODE)); + if (voucher.hasUserExhausted(habbo.getHabboInfo().getId())) { + client.sendResponse(new ModToolIssueHandledComposer("You have exceeded the limit for redeeming this voucher.")); + return; + } + + voucher.addHistoryEntry(habbo.getHabboInfo().getId()); + + if (voucher.isExhausted()) { + if (!Emulator.getGameEnvironment().getCatalogManager().deleteVoucher(voucher)) { + client.sendResponse(new RedeemVoucherErrorComposer(RedeemVoucherErrorComposer.TECHNICAL_ERROR)); + } + } + + if (voucher.points > 0) { + client.getHabbo().getHabboInfo().addCurrencyAmount(voucher.pointsType, voucher.points); + client.sendResponse(new UserPointsComposer(client.getHabbo().getHabboInfo().getCurrencyAmount(voucher.pointsType), voucher.points, voucher.pointsType)); + } + + if (voucher.credits > 0) { + client.getHabbo().getHabboInfo().addCredits(voucher.credits); + client.sendResponse(new UserCreditsComposer(client.getHabbo())); + } + + if (voucher.catalogItemId > 0) { + CatalogItem item = this.getCatalogItem(voucher.catalogItemId); + + if (item != null) { + this.purchaseItem(null, item, client.getHabbo(), 1, "", true); + } + } + + client.sendResponse(new RedeemVoucherOKComposer()); } diff --git a/src/main/java/com/eu/habbo/habbohotel/catalog/Voucher.java b/src/main/java/com/eu/habbo/habbohotel/catalog/Voucher.java index 643a3d1d..7291e193 100644 --- a/src/main/java/com/eu/habbo/habbohotel/catalog/Voucher.java +++ b/src/main/java/com/eu/habbo/habbohotel/catalog/Voucher.java @@ -1,27 +1,24 @@ package com.eu.habbo.habbohotel.catalog; +import com.eu.habbo.Emulator; + +import java.sql.Connection; +import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; public class Voucher { - public final int id; - - public final String code; - - public final int credits; - - public final int points; - - public final int pointsType; - - public final int catalogItemId; - + public final int amount; + public final int limit; + private final List history = new ArrayList<>(); public Voucher(ResultSet set) throws SQLException { this.id = set.getInt("id"); @@ -30,5 +27,44 @@ public class Voucher { this.points = set.getInt("points"); this.pointsType = set.getInt("points_type"); this.catalogItemId = set.getInt("catalog_item_id"); + this.amount = set.getInt("amount"); + this.limit = set.getInt("limit"); + + this.loadHistory(); + } + + private void loadHistory() { + try (Connection connection = Emulator.getDatabase().getDataSource().getConnection(); PreparedStatement statement = connection.prepareStatement("SELECT * FROM voucher_history")) { + try (ResultSet set = statement.executeQuery()) { + while (set.next()) { + this.history.add(new VoucherHistoryEntry(set)); + } + } + } catch (SQLException e) { + Emulator.getLogging().logSQLException(e); + } + } + + public boolean hasUserExhausted(int userId) { + return this.limit > 0 && Math.toIntExact(this.history.stream().filter(h -> h.getUserId() == userId).count()) >= this.limit; + } + + public boolean isExhausted() { + return this.amount > 0 && this.history.size() >= this.amount; + } + + public void addHistoryEntry(int userId) { + int timestamp = Emulator.getIntUnixTimestamp(); + this.history.add(new VoucherHistoryEntry(this.id, userId, timestamp)); + + try (Connection connection = Emulator.getDatabase().getDataSource().getConnection(); PreparedStatement statement = connection.prepareStatement("INSERT INTO voucher_history (`voucher_id`, `user_id`, `timestamp`) VALUES (?, ?, ?)")) { + statement.setInt(1, this.id); + statement.setInt(2, userId); + statement.setInt(3, timestamp); + + statement.execute(); + } catch (SQLException e) { + Emulator.getLogging().logSQLException(e); + } } } diff --git a/src/main/java/com/eu/habbo/habbohotel/catalog/VoucherHistoryEntry.java b/src/main/java/com/eu/habbo/habbohotel/catalog/VoucherHistoryEntry.java new file mode 100644 index 00000000..300c7c8f --- /dev/null +++ b/src/main/java/com/eu/habbo/habbohotel/catalog/VoucherHistoryEntry.java @@ -0,0 +1,34 @@ +package com.eu.habbo.habbohotel.catalog; + +import java.sql.ResultSet; +import java.sql.SQLException; + +public class VoucherHistoryEntry { + private final int voucherId; + private final int userId; + private final int timestamp; + + public VoucherHistoryEntry(ResultSet set) throws SQLException { + this.voucherId = set.getInt("voucher_id"); + this.userId = set.getInt("user_id"); + this.timestamp = set.getInt("timestamp"); + } + + public VoucherHistoryEntry(int voucherId, int userId, int timestamp) { + this.voucherId = voucherId; + this.userId = userId; + this.timestamp = timestamp; + } + + public int getVoucherId() { + return voucherId; + } + + public int getUserId() { + return userId; + } + + public int getTimestamp() { + return timestamp; + } +}