-- ============================================================ -- db/furniture.lua – Custom furniture CRUD + FiveManage -- ============================================================ local DEFAULT_OFFSET = { x = 0.0, y = 0.0, z = 0.0 } local INSERT_FURNITURE_SQL = [[ INSERT INTO qs_garage_furnitures (`creator`, `category_key`, `object`, `label`, `description`, `price`, `img`, `colorlabel`, `type`, `stash`, `offset`, `colors`) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ]] local UPDATE_FURNITURE_SQL = [[ UPDATE qs_garage_furnitures SET `category_key` = ?, `object` = ?, `label` = ?, `description` = ?, `price` = ?, `img` = ?, `colorlabel` = ?, `type` = ?, `stash` = ?, `offset` = ?, `colors` = ? WHERE id = ? ]] -- ────────────────────────────────────────────── -- getFurnitureItems -- ────────────────────────────────────────────── function db.getFurnitureItems() local rows = MySQL.query.await("SELECT * FROM qs_garage_furnitures ORDER BY category_key, label") return rows or {} end -- ────────────────────────────────────────────── -- getFurnitureItemsByCategory -- ────────────────────────────────────────────── function db.getFurnitureItemsByCategory(categoryKey) local rows = MySQL.query.await( "SELECT * FROM qs_garage_furnitures WHERE category_key = ? ORDER BY label", { categoryKey } ) return rows or {} end -- ────────────────────────────────────────────── -- createFurnitureItem -- ────────────────────────────────────────────── function db.createFurnitureItem(sourcePlayer, data) assert(data, "db.createFurnitureItem data must be provided") assert(data.category, "db.createFurnitureItem category is required") assert(data.item, "db.createFurnitureItem item is required") local identifier = GetPlayerIdentifier(sourcePlayer) assert(identifier, "db.createFurnitureItem identifier is nil") local item = data.item item.offset = item.offset or DEFAULT_OFFSET local stashEncoded = item.stash and json.encode(item.stash) or nil local colorsEncoded = item.colors and json.encode(item.colors) or "[]" local newId = MySQL.insert.await(INSERT_FURNITURE_SQL, { identifier, data.category, item.object, item.label, item.description or "", item.price or 0, item.img or "", item.colorlabel or "", item.type, stashEncoded, json.encode(item.offset), colorsEncoded, }) Debug("db.createFurnitureItem", "Inserted", newId, "Category", data.category, "Object", item.object) return newId end -- ────────────────────────────────────────────── -- updateFurnitureItem -- ────────────────────────────────────────────── function db.updateFurnitureItem(sourcePlayer, data) assert(data, "db.updateFurnitureItem data must be provided") assert(data.item, "db.updateFurnitureItem item is required") assert(data.item.id, "db.updateFurnitureItem item.id is required") local identifier = GetPlayerIdentifier(sourcePlayer) assert(identifier, "db.updateFurnitureItem identifier is nil") local item = data.item item.offset = item.offset or DEFAULT_OFFSET local stashEncoded = item.stash and json.encode(item.stash) or nil local colorsEncoded = item.colors and json.encode(item.colors) or "[]" local affected = MySQL.update.await(UPDATE_FURNITURE_SQL, { data.category, item.object, item.label, item.description or "", item.price or 0, item.img or "", item.colorlabel or "", item.type, stashEncoded, json.encode(item.offset), colorsEncoded, item.id, }) Debug("db.updateFurnitureItem", "Updated", affected, "ID", item.id, "Object", item.object) return affected > 0 end -- ────────────────────────────────────────────── -- removeFurnitureItem -- ────────────────────────────────────────────── function db.removeFurnitureItem(itemId, sourcePlayer) assert(itemId, "db.removeFurnitureItem id is nil") local identifier = GetPlayerIdentifier(sourcePlayer) assert(identifier, "db.removeFurnitureItem identifier is nil") local affected = MySQL.update.await( "DELETE FROM qs_garage_furnitures WHERE id = ? AND creator = ?", { itemId, identifier } ) Debug("db.removeFurnitureItem", "Deleted", affected, "ID", itemId) return affected > 0 end -- ────────────────────────────────────────────── -- getMergedFurnitureData -- Merges DB custom furniture items into -- Config.Furniture, overriding existing entries -- by object name or appending new ones. -- ────────────────────────────────────────────── function db.getMergedFurnitureData() local dbItems = db.getFurnitureItems() local merged = table.clone(Config.Furniture) or {} for _, dbRow in ipairs(dbItems) do local categoryKey = dbRow.category_key local category = merged[categoryKey] if not category then Error("db.getMergedFurnitureData", "Category not found", categoryKey) else -- Decode JSON columns dbRow.stash = dbRow.stash and json.decode(dbRow.stash) or nil dbRow.offset = dbRow.offset and json.decode(dbRow.offset) or nil dbRow.colors = dbRow.colors and json.decode(dbRow.colors) or nil local newEntry = { id = dbRow.id, object = dbRow.object, label = dbRow.label, description = dbRow.description, price = dbRow.price, img = dbRow.img, colorlabel = dbRow.colorlabel, type = dbRow.type, key = categoryKey, creator = true, stash = dbRow.stash, offset = dbRow.offset, colors = dbRow.colors, } -- Find existing item with same object name local existingIndex = nil for idx, existingItem in ipairs(category.items) do if existingItem.object == newEntry.object then existingIndex = idx break end end if existingIndex then category.items[existingIndex] = newEntry else table.insert(category.items, newEntry) end end end return merged end -- ────────────────────────────────────────────── -- getFiveManageToken callback -- ────────────────────────────────────────────── lib.callback.register("garages:getFiveManageToken", function(sourcePlayer) if Config.FiveManageToken == "" then Error("garages:getFiveManageToken", "FiveManage token is not set. Please set it in config/fivemanage.lua.") return nil end if not HasPermission(sourcePlayer) then Error("garages:getFiveManageToken", "Player does not have permission to get five manage token") return nil end return Config.FiveManageToken end)