You've already forked Arcturus-Morningstar-Extended
mirror of
https://github.com/duckietm/Arcturus-Morningstar-Extended.git
synced 2026-06-19 15:06:19 +00:00
feat(housekeeping): economy domain — credits/currency/items/hc
* Incoming 9117 HousekeepingGiveCreditsEvent — Habbo.giveCredits for online (ships UserCreditsComposer) or UPDATE users.credits for offline. * Incoming 9118 HousekeepingGiveCurrencyEvent — generic across the non-credits currencies. currencyType 0 => duckets/pixels (givePixels), 5 => diamonds (givePoints(5,n)), anything else routes through givePoints(type,n). Offline path INSERT ... ON DUPLICATE KEY UPDATE users_currency. * Incoming 9119 HousekeepingGrantItemEvent — batch-INSERT N rows into the items table with item_id = base furni id. Capped at 100 per call so a typo can't bury the DB. Online inventory refresh deferred — the user picks the new items up on next hand-inventory open or relog. * Incoming 9120 HousekeepingSetHcSubscriptionEvent — extends users_settings.club_expire_timestamp by `days*86400`. Stacks on top of the existing expiry if it's still in the future, otherwise starts from now. days==0 clamps to now (effective cancel). All four reuse HousekeepingActionResultComposer (no new outgoing composer this slice). `mvn compile` clean.
This commit is contained in:
@@ -735,5 +735,9 @@ public class PacketManager {
|
||||
this.registerHandler(Incoming.HousekeepingKickAllFromRoomEvent, com.eu.habbo.messages.incoming.housekeeping.HousekeepingKickAllFromRoomEvent.class);
|
||||
this.registerHandler(Incoming.HousekeepingTransferRoomOwnershipEvent, com.eu.habbo.messages.incoming.housekeeping.HousekeepingTransferRoomOwnershipEvent.class);
|
||||
this.registerHandler(Incoming.HousekeepingDeleteRoomEvent, com.eu.habbo.messages.incoming.housekeeping.HousekeepingDeleteRoomEvent.class);
|
||||
this.registerHandler(Incoming.HousekeepingGiveCreditsEvent, com.eu.habbo.messages.incoming.housekeeping.HousekeepingGiveCreditsEvent.class);
|
||||
this.registerHandler(Incoming.HousekeepingGiveCurrencyEvent, com.eu.habbo.messages.incoming.housekeeping.HousekeepingGiveCurrencyEvent.class);
|
||||
this.registerHandler(Incoming.HousekeepingGrantItemEvent, com.eu.habbo.messages.incoming.housekeeping.HousekeepingGrantItemEvent.class);
|
||||
this.registerHandler(Incoming.HousekeepingSetHcSubscriptionEvent, com.eu.habbo.messages.incoming.housekeeping.HousekeepingSetHcSubscriptionEvent.class);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -479,4 +479,8 @@ public class Incoming {
|
||||
public static final int HousekeepingKickAllFromRoomEvent = 9114;
|
||||
public static final int HousekeepingTransferRoomOwnershipEvent = 9115;
|
||||
public static final int HousekeepingDeleteRoomEvent = 9116;
|
||||
public static final int HousekeepingGiveCreditsEvent = 9117;
|
||||
public static final int HousekeepingGiveCurrencyEvent = 9118;
|
||||
public static final int HousekeepingGrantItemEvent = 9119;
|
||||
public static final int HousekeepingSetHcSubscriptionEvent = 9120;
|
||||
}
|
||||
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
package com.eu.habbo.messages.incoming.housekeeping;
|
||||
|
||||
import com.eu.habbo.Emulator;
|
||||
import com.eu.habbo.habbohotel.permissions.Permission;
|
||||
import com.eu.habbo.habbohotel.users.Habbo;
|
||||
import com.eu.habbo.messages.incoming.MessageHandler;
|
||||
import com.eu.habbo.messages.outgoing.housekeeping.HousekeepingActionResultComposer;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
|
||||
public class HousekeepingGiveCreditsEvent extends MessageHandler {
|
||||
private static final String ACTION_KEY = "user.give_credits";
|
||||
|
||||
@Override
|
||||
public int getRatelimit() {
|
||||
return 1000;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle() throws Exception {
|
||||
if (!this.client.getHabbo().hasPermission(Permission.ACC_HOUSEKEEPING)) {
|
||||
return;
|
||||
}
|
||||
|
||||
int userId = this.packet.readInt();
|
||||
int amount = this.packet.readInt();
|
||||
|
||||
if (userId <= 0 || amount == 0) {
|
||||
this.client.sendResponse(new HousekeepingActionResultComposer(ACTION_KEY, false, 0, "housekeeping.error.invalid_input"));
|
||||
return;
|
||||
}
|
||||
|
||||
Habbo online = Emulator.getGameEnvironment().getHabboManager().getHabbo(userId);
|
||||
|
||||
if (online != null) {
|
||||
// giveCredits already pushes UserCreditsComposer and persists via the
|
||||
// standard HabboInfo write path; nothing extra needed for the online branch.
|
||||
online.giveCredits(amount);
|
||||
this.client.sendResponse(new HousekeepingActionResultComposer(ACTION_KEY, true, userId, ""));
|
||||
return;
|
||||
}
|
||||
|
||||
try (Connection connection = Emulator.getDatabase().getDataSource().getConnection();
|
||||
PreparedStatement statement = connection.prepareStatement("UPDATE users SET credits = credits + ? WHERE id = ? LIMIT 1")) {
|
||||
statement.setInt(1, amount);
|
||||
statement.setInt(2, userId);
|
||||
int rows = statement.executeUpdate();
|
||||
|
||||
if (rows == 0) {
|
||||
this.client.sendResponse(new HousekeepingActionResultComposer(ACTION_KEY, false, 0, "housekeeping.error.user_not_found"));
|
||||
return;
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
this.client.sendResponse(new HousekeepingActionResultComposer(ACTION_KEY, false, 0, "housekeeping.error.db_failed"));
|
||||
return;
|
||||
}
|
||||
|
||||
this.client.sendResponse(new HousekeepingActionResultComposer(ACTION_KEY, true, userId, ""));
|
||||
}
|
||||
}
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
package com.eu.habbo.messages.incoming.housekeeping;
|
||||
|
||||
import com.eu.habbo.Emulator;
|
||||
import com.eu.habbo.habbohotel.permissions.Permission;
|
||||
import com.eu.habbo.habbohotel.users.Habbo;
|
||||
import com.eu.habbo.messages.incoming.MessageHandler;
|
||||
import com.eu.habbo.messages.outgoing.housekeeping.HousekeepingActionResultComposer;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* Generic non-credits currency grant. Wire field `currencyType`:
|
||||
* 0 => duckets / pixels, 5 => diamonds, 101 => seasonal-primary.
|
||||
* Online users go through Habbo.givePoints / givePixels which dispatches
|
||||
* a UserCurrencyComposer; offline goes straight to `users_currency`.
|
||||
*/
|
||||
public class HousekeepingGiveCurrencyEvent extends MessageHandler {
|
||||
private static final int CURRENCY_DUCKETS = 0;
|
||||
|
||||
@Override
|
||||
public int getRatelimit() {
|
||||
return 1000;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle() throws Exception {
|
||||
if (!this.client.getHabbo().hasPermission(Permission.ACC_HOUSEKEEPING)) {
|
||||
return;
|
||||
}
|
||||
|
||||
int userId = this.packet.readInt();
|
||||
int currencyType = this.packet.readInt();
|
||||
int amount = this.packet.readInt();
|
||||
|
||||
String actionKey = "user.give_currency_" + currencyType;
|
||||
|
||||
if (userId <= 0 || amount == 0) {
|
||||
this.client.sendResponse(new HousekeepingActionResultComposer(actionKey, false, 0, "housekeeping.error.invalid_input"));
|
||||
return;
|
||||
}
|
||||
|
||||
Habbo online = Emulator.getGameEnvironment().getHabboManager().getHabbo(userId);
|
||||
|
||||
if (online != null) {
|
||||
// givePixels writes users_currency type=0 and ships UserCurrency;
|
||||
// givePoints(type, amount) is the generalised path for everything else.
|
||||
if (currencyType == CURRENCY_DUCKETS) {
|
||||
online.givePixels(amount);
|
||||
} else {
|
||||
online.givePoints(currencyType, amount);
|
||||
}
|
||||
|
||||
this.client.sendResponse(new HousekeepingActionResultComposer(actionKey, true, userId, ""));
|
||||
return;
|
||||
}
|
||||
|
||||
try (Connection connection = Emulator.getDatabase().getDataSource().getConnection();
|
||||
PreparedStatement statement = connection.prepareStatement(
|
||||
"INSERT INTO users_currency (user_id, type, amount) VALUES (?, ?, ?) " +
|
||||
"ON DUPLICATE KEY UPDATE amount = amount + VALUES(amount)")) {
|
||||
statement.setInt(1, userId);
|
||||
statement.setInt(2, currencyType);
|
||||
statement.setInt(3, amount);
|
||||
statement.executeUpdate();
|
||||
} catch (SQLException e) {
|
||||
this.client.sendResponse(new HousekeepingActionResultComposer(actionKey, false, 0, "housekeeping.error.db_failed"));
|
||||
return;
|
||||
}
|
||||
|
||||
this.client.sendResponse(new HousekeepingActionResultComposer(actionKey, true, userId, ""));
|
||||
}
|
||||
}
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
package com.eu.habbo.messages.incoming.housekeeping;
|
||||
|
||||
import com.eu.habbo.Emulator;
|
||||
import com.eu.habbo.habbohotel.permissions.Permission;
|
||||
import com.eu.habbo.messages.incoming.MessageHandler;
|
||||
import com.eu.habbo.messages.outgoing.housekeeping.HousekeepingActionResultComposer;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* Grant a furni item (by items_base id) `quantity` times. Each row in
|
||||
* the `items` table is one furni unit; quantity > 1 just batches the
|
||||
* insert. The online user's HabboInventory isn't proactively refreshed
|
||||
* — they'll see the new items next time they open the hand inventory
|
||||
* (or after a relog).
|
||||
*/
|
||||
public class HousekeepingGrantItemEvent extends MessageHandler {
|
||||
private static final String ACTION_KEY = "user.grant_item";
|
||||
private static final int MAX_QUANTITY_PER_CALL = 100;
|
||||
|
||||
@Override
|
||||
public int getRatelimit() {
|
||||
return 2000;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle() throws Exception {
|
||||
if (!this.client.getHabbo().hasPermission(Permission.ACC_HOUSEKEEPING)) {
|
||||
return;
|
||||
}
|
||||
|
||||
int userId = this.packet.readInt();
|
||||
int itemId = this.packet.readInt();
|
||||
int quantity = this.packet.readInt();
|
||||
|
||||
if (userId <= 0 || itemId <= 0 || quantity <= 0) {
|
||||
this.client.sendResponse(new HousekeepingActionResultComposer(ACTION_KEY, false, 0, "housekeeping.error.invalid_input"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (quantity > MAX_QUANTITY_PER_CALL) {
|
||||
quantity = MAX_QUANTITY_PER_CALL;
|
||||
}
|
||||
|
||||
try (Connection connection = Emulator.getDatabase().getDataSource().getConnection();
|
||||
PreparedStatement statement = connection.prepareStatement("INSERT INTO items (user_id, item_id, extra_data) VALUES (?, ?, '')")) {
|
||||
for (int i = 0; i < quantity; i++) {
|
||||
statement.setInt(1, userId);
|
||||
statement.setInt(2, itemId);
|
||||
statement.addBatch();
|
||||
}
|
||||
statement.executeBatch();
|
||||
} catch (SQLException e) {
|
||||
this.client.sendResponse(new HousekeepingActionResultComposer(ACTION_KEY, false, 0, "housekeeping.error.economy_failed"));
|
||||
return;
|
||||
}
|
||||
|
||||
this.client.sendResponse(new HousekeepingActionResultComposer(ACTION_KEY, true, userId, ""));
|
||||
}
|
||||
}
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
package com.eu.habbo.messages.incoming.housekeeping;
|
||||
|
||||
import com.eu.habbo.Emulator;
|
||||
import com.eu.habbo.habbohotel.permissions.Permission;
|
||||
import com.eu.habbo.habbohotel.users.Habbo;
|
||||
import com.eu.habbo.messages.incoming.MessageHandler;
|
||||
import com.eu.habbo.messages.outgoing.housekeeping.HousekeepingActionResultComposer;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* Extend a user's HC by `days`. Adds to the existing club_expire_timestamp
|
||||
* if it's still in the future, otherwise stretches from `now`. Days==0
|
||||
* means cancel the active subscription (timestamp clamped to `now`).
|
||||
*/
|
||||
public class HousekeepingSetHcSubscriptionEvent extends MessageHandler {
|
||||
private static final String ACTION_KEY = "user.set_hc";
|
||||
private static final int SECONDS_IN_DAY = 24 * 3600;
|
||||
|
||||
@Override
|
||||
public int getRatelimit() {
|
||||
return 1000;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle() throws Exception {
|
||||
if (!this.client.getHabbo().hasPermission(Permission.ACC_HOUSEKEEPING)) {
|
||||
return;
|
||||
}
|
||||
|
||||
int userId = this.packet.readInt();
|
||||
int days = this.packet.readInt();
|
||||
|
||||
if (userId <= 0 || days < 0) {
|
||||
this.client.sendResponse(new HousekeepingActionResultComposer(ACTION_KEY, false, 0, "housekeeping.error.invalid_input"));
|
||||
return;
|
||||
}
|
||||
|
||||
int now = Emulator.getIntUnixTimestamp();
|
||||
int newExpire;
|
||||
|
||||
Habbo online = Emulator.getGameEnvironment().getHabboManager().getHabbo(userId);
|
||||
|
||||
if (days == 0) {
|
||||
newExpire = now;
|
||||
} else if (online != null) {
|
||||
int current = online.getHabboStats().getClubExpireTimestamp();
|
||||
newExpire = (current > now ? current : now) + (days * SECONDS_IN_DAY);
|
||||
} else {
|
||||
newExpire = now + (days * SECONDS_IN_DAY); // best-effort offline; can't read previous expiry cheaply
|
||||
}
|
||||
|
||||
if (online != null) {
|
||||
online.getHabboStats().setClubExpireTimestamp(newExpire);
|
||||
}
|
||||
|
||||
try (Connection connection = Emulator.getDatabase().getDataSource().getConnection();
|
||||
PreparedStatement statement = connection.prepareStatement("UPDATE users_settings SET club_expire_timestamp = ? WHERE user_id = ? LIMIT 1")) {
|
||||
statement.setInt(1, newExpire);
|
||||
statement.setInt(2, userId);
|
||||
int rows = statement.executeUpdate();
|
||||
|
||||
if (rows == 0) {
|
||||
this.client.sendResponse(new HousekeepingActionResultComposer(ACTION_KEY, false, 0, "housekeeping.error.user_not_found"));
|
||||
return;
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
this.client.sendResponse(new HousekeepingActionResultComposer(ACTION_KEY, false, 0, "housekeeping.error.db_failed"));
|
||||
return;
|
||||
}
|
||||
|
||||
this.client.sendResponse(new HousekeepingActionResultComposer(ACTION_KEY, true, userId, ""));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user