diff --git a/Emulator/src/main/java/com/eu/habbo/habbohotel/items/FurnitureTextProvider.java b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/FurnitureTextProvider.java index abe061c0..ab2ae51f 100644 --- a/Emulator/src/main/java/com/eu/habbo/habbohotel/items/FurnitureTextProvider.java +++ b/Emulator/src/main/java/com/eu/habbo/habbohotel/items/FurnitureTextProvider.java @@ -167,5 +167,26 @@ public class FurnitureTextProvider { return sb.toString(); } + /** + * Returns all lowercased base classnames whose furnidata display name contains + * {@code query} (case-insensitive, substring). Results are capped at 200 to + * bound SQL IN-clause size. Returns an empty list when query is null/blank. + */ + public java.util.List findClassnamesByName(String query) { + java.util.List out = new java.util.ArrayList<>(); + if (query == null) return out; + String q = query.trim().toLowerCase(Locale.ROOT); + if (q.isEmpty()) return out; + Map idx = this.index; // local ref (volatile) + for (Map.Entry e : idx.entrySet()) { + FurniText t = e.getValue(); + if (t != null && t.name() != null && t.name().toLowerCase(Locale.ROOT).contains(q)) { + out.add(e.getKey()); // key is the lowercased base classname + if (out.size() >= 200) break; // bound IN-clause size + } + } + return out; + } + private record FurniText(int id, FurnitureType type, String name, String description) {} } diff --git a/Emulator/src/main/java/com/eu/habbo/messages/incoming/furnieditor/FurniEditorSearchEvent.java b/Emulator/src/main/java/com/eu/habbo/messages/incoming/furnieditor/FurniEditorSearchEvent.java index bfdc229c..769f41cd 100644 --- a/Emulator/src/main/java/com/eu/habbo/messages/incoming/furnieditor/FurniEditorSearchEvent.java +++ b/Emulator/src/main/java/com/eu/habbo/messages/incoming/furnieditor/FurniEditorSearchEvent.java @@ -64,6 +64,34 @@ public class FurniEditorSearchEvent extends MessageHandler { params.add(type); } + // Extend search with furnidata display-name matches (server-authoritative names in JSON). + // Appends: OR (LOWER(item_name) IN (?,?,...) [AND type=?]) + // Both branches carry their own type filter, so type scoping is preserved. + // Params: [existing LIKE params] [existing type?] [furniCns...] [type again?] + if (!query.isEmpty()) { + java.util.List furniCns = Emulator.getGameEnvironment() + .getFurnitureTextProvider() + .findClassnamesByName(query); + if (!furniCns.isEmpty()) { + // Build: OR (LOWER(item_name) IN (?,?,...) [AND type = ?]) + StringBuilder orBranch = new StringBuilder(" OR (LOWER(item_name) IN ("); + for (int i = 0; i < furniCns.size(); i++) { + if (i > 0) orBranch.append(", "); + orBranch.append('?'); + } + orBranch.append(')'); + if (type != null && !type.isEmpty()) { + orBranch.append(" AND type = ?"); + } + orBranch.append(')'); + whereClause.append(orBranch); + params.addAll(furniCns); + if (type != null && !type.isEmpty()) { + params.add(type); + } + } + } + // Count total int total = 0; String countSql = "SELECT COUNT(*) FROM items_base " + whereClause;