feat(furnieditor): FurniEditorRevertFurnidataEvent — restore last furnidata backup + rebroadcast

This commit is contained in:
simoleo89
2026-06-06 02:21:21 +02:00
parent 392d24b9c5
commit 1416cd7464
2 changed files with 119 additions and 0 deletions
@@ -286,6 +286,7 @@ public class PacketManager {
this.registerHandler(Incoming.FurniEditorUpdateEvent, FurniEditorUpdateEvent.class);
this.registerHandler(Incoming.FurniEditorDeleteEvent, FurniEditorDeleteEvent.class);
this.registerHandler(Incoming.FurniEditorUpdateFurnidataEvent, FurniEditorUpdateFurnidataEvent.class);
this.registerHandler(Incoming.FurniEditorRevertFurnidataEvent, FurniEditorRevertFurnidataEvent.class);
// Catalog Admin
this.registerHandler(Incoming.CatalogAdminSavePageEvent, CatalogAdminSavePageEvent.class);
@@ -0,0 +1,118 @@
package com.eu.habbo.messages.incoming.furnieditor;
import com.eu.habbo.Emulator;
import com.eu.habbo.habbohotel.items.FurnidataEntry;
import com.eu.habbo.habbohotel.items.FurnidataLock;
import com.eu.habbo.habbohotel.items.FurnidataWriter;
import com.eu.habbo.habbohotel.items.FurnitureTextProvider;
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.furniture.FurnitureDataReloadComposer;
import com.eu.habbo.messages.outgoing.furnieditor.FurniEditorResultComposer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
/**
* Incoming handler 10048 — admin reverts a furni's furnidata to the last rotating backup.
*
* Flow: permission check → read item_id → resolve classname → under FurnidataLock:
* FurnidataWriter.revertLastBackup → FurnitureTextProvider.reindexFromSource →
* broadcast FurnitureDataReloadComposer (10047) → audit log → respond.
*/
public class FurniEditorRevertFurnidataEvent extends MessageHandler {
private static final Logger LOGGER = LoggerFactory.getLogger(FurniEditorRevertFurnidataEvent.class);
@Override
public void handle() throws Exception {
Habbo habbo = this.client.getHabbo();
// 1. Permission check
if (!habbo.hasPermission(Permission.ACC_CATALOGFURNI)) {
this.client.sendResponse(new FurniEditorResultComposer(false, "No permission"));
return;
}
// 2. Read packet
int itemId = this.packet.readInt();
if (itemId <= 0) {
this.client.sendResponse(new FurniEditorResultComposer(false, "Invalid item ID"));
return;
}
// 3. Resolve classname from item_id (reuse static helper from update handler)
String classname = FurniEditorUpdateFurnidataEvent.classnameForItem(itemId);
String classnameForLog = (classname != null) ? classname : "?";
// 4. Verify provider is configured
FurnitureTextProvider provider =
Emulator.getGameEnvironment().getFurnitureTextProvider();
if (provider == null || provider.getSource() == null) {
this.client.sendResponse(new FurniEditorResultComposer(false, "Furnidata source not configured"));
return;
}
int adminId = habbo.getHabboInfo().getId();
// 5. Revert + reindex + broadcast under the shared lock
boolean reverted;
List<FurnidataEntry> delta;
FurnidataLock.LOCK.lock();
try {
FurnidataWriter writer = new FurnidataWriter(
provider.getSource(),
provider.isSourceDirectory(),
provider.getMaxBytes(),
3 /* backupKeep */
);
reverted = writer.revertLastBackup();
if (!reverted) {
this.client.sendResponse(new FurniEditorResultComposer(false, "No backup found to revert"));
return;
}
delta = provider.reindexFromSource();
if (!delta.isEmpty()) {
int deltaCap = Integer.parseInt(
Emulator.getConfig().getValue("items.furnidata.delta.cap", "500"));
FurnitureDataReloadComposer composer = (delta.size() > deltaCap)
? new FurnitureDataReloadComposer(FurnitureDataReloadComposer.MODE_RELOAD_HINT, List.of())
: new FurnitureDataReloadComposer(FurnitureDataReloadComposer.MODE_DELTA, delta);
broadcastToAll(composer);
}
} finally {
FurnidataLock.LOCK.unlock();
}
// 6. Audit log (outside lock — DB write, not latency-sensitive)
FurnidataAuditLog.record(
adminId,
classnameForLog,
"REVERT_FURNIDATA",
"", // previous state unknown at this point
"",
"",
""
);
// 7. Respond success
this.client.sendResponse(new FurniEditorResultComposer(true, "Furnidata reverted", itemId));
LOGGER.info("FurniEditorRevertFurnidataEvent: admin {} reverted furnidata for classname '{}' (item {})",
adminId, classnameForLog, itemId);
}
private static void broadcastToAll(FurnitureDataReloadComposer composer) {
for (Habbo habbo : Emulator.getGameEnvironment().getHabboManager().getOnlineHabbos().values()) {
if (habbo.getClient() != null) {
habbo.getClient().sendResponse(composer);
}
}
}
}