From ed017ab51ac88dd6d478c127ad6cbe183231adab Mon Sep 17 00:00:00 2001 From: gasaichandesu Date: Fri, 7 Aug 2026 06:21:22 +0400 Subject: [PATCH 1/2] feat(transmog): add transmog module --- import-custom-sql.sh | 22 + .../Transmogrification/transmogrification.lua | 838 ++++++++++++++++++ sql/Transmogrification/auth.sql | 35 + sql/Transmogrification/char.sql | 33 + 4 files changed, 928 insertions(+) create mode 100644 lua_scripts/Transmogrification/transmogrification.lua create mode 100644 sql/Transmogrification/auth.sql create mode 100644 sql/Transmogrification/char.sql diff --git a/import-custom-sql.sh b/import-custom-sql.sh index b10592fbf..4965ca9a0 100644 --- a/import-custom-sql.sh +++ b/import-custom-sql.sh @@ -279,6 +279,27 @@ import_playerbots_ru_sql() { import_sql_file "acore_characters" "$names_sql_file" } +import_transmog_sql() { + local account_transmog_sql="$ROOT_DIR/sql/Transmogrification/auth.sql" + local character_transmog_sql="$ROOT_DIR/sql/Transmogrification/char.sql" + + if table_exists "acore_world" "account_transmog"; then + log "account_transmog table already exists, skipping" + else + import_sql_file "acore_world" "$account_transmog_sql" + + log "account_transmog table was successfully imported" + fi + + if table_exists "acore_world" "character_transmog"; then + log "character_transmog table already exists, skipping" + else + import_sql_file "acore_world" "$character_transmog_sql" + + log "account_character table was successfully imported" + fi +} + configure_server_motd() { log "configuring MoonWell login message" mysql_exec "acore_auth" " @@ -362,6 +383,7 @@ import_aoe_loot_sql import_playerbots_ru_sql import_encounter_journal_sql import_store_sql +import_transmog_sql configure_server_motd log "custom SQL bootstrap completed" diff --git a/lua_scripts/Transmogrification/transmogrification.lua b/lua_scripts/Transmogrification/transmogrification.lua new file mode 100644 index 000000000..2c4941785 --- /dev/null +++ b/lua_scripts/Transmogrification/transmogrification.lua @@ -0,0 +1,838 @@ +-- ╔════════════════════════════════════════════════════════════════════════╗ +-- ║ Transmog System Eluna Script by DanielTheDeveloper ║ +-- ╚════════════════════════════════════════════════════════════════════════╝ +-- +-- ╔══════════════════════════╗ +-- ╔══════════════════════║ Transmog System Settings ║══════════════════════╗ +-- ║ ╚══════════════════════════╝ ║ +-- ║ Automatically adds transmog appearances to the players account-wide ║ +-- ║ transmog collection when they equip an item for the first time. ║ +-- ║ ║ +-- ║ It is recommended to leave this option enabled. ║ +-- ╟────────────────────────────────────────────────────────────────────────╢ + local ADD_NEWLY_EQUIPPED_ITEMS_TO_THE_TRANSMOG_LIST = true --║ +-- ╟────────────────────────────────────────────────────────────────────────╢ +-- ║ ║ +-- ║ Automatically adds transmog appearances to the players account-wide ║ +-- ║ transmog collection when they loot an item for the first time. ║ +-- ║ ║ +-- ║ It is recommended to leave this option disabled as it creates the ║ +-- ║ potential for a more healthy transmog economy to exist inside the ║ +-- ║ auction house. ║ +-- ╟────────────────────────────────────────────────────────────────────────╢ + local ADD_NEWLY_LOOTED_ITEMS_TO_THE_TRANSMOG_LIST = false --║ +-- ╟────────────────────────────────────────────────────────────────────────╢ +-- ║ ║ +-- ║ Automatically adds all applicable quest reward items as transmog ║ +-- ║ appearances to the players account-wide transmog collection when ║ +-- ║ completing a quest, regardless of which quest reward the player ║ +-- ║ actually decided to select. ║ +-- ║ ║ +-- ║ It is recommended to leave this option enabled as it eliminates the ║ +-- ║ dilemma of deciding between a potential transmog appearance or gear ║ +-- ║ that is useful for the character. ║ +-- ╟────────────────────────────────────────────────────────────────────────╢ + local ADD_QUEST_REWARD_ITEMS_TO_THE_TRANSMOG_LIST = true --║ +-- ╟────────────────────────────────────────────────────────────────────────╢ +-- ║ ║ +-- ║ Restricts armor transmog appearances to items made up of the same ║ +-- ║ material. As an example, with this option enabled, cloth chest pieces ║ +-- ║ can only be transmogrified to appear as other cloth chest pieces. ║ +-- ║ When this option is disabled, cloth chest pieces can be ║ +-- ║ transmogrified to appear as a cloth, leather, mail, or plate chest ║ +-- ║ piece. ║ +-- ║ ║ +-- ║ It is recommended to leave this option enabled as it leaves the ║ +-- ║ class fantasy intact. ║ +-- ╟────────────────────────────────────────────────────────────────────────╢ + local RESTRICT_ARMOR_TRANSMOG_TO_SIMILAR_MATERIALS = true --║ +-- ╟────────────────────────────────────────────────────────────────────────╢ +-- ║ ║ +-- ║ Restricts weapon transmog appearances to the same weapon. As an ║ +-- ║ example, with this option enabled, two-handed swords can only be ║ +-- ║ transmogrified to appear as other two-handed swords. When this option ║ +-- ║ is disabled, two-handed swords can be transmogrified to appear as a ║ +-- ║ one-handed sword, staff, polearm, fishing pole, etc. ║ +-- ║ ║ +-- ║ It is recommended to leave this option enabled as it leaves the ║ +-- ║ class fantasy intact. ║ +-- ╟────────────────────────────────────────────────────────────────────────╢ + local RESTRICT_WEAPON_TRANSMOG_TO_SIMILAR_WEAPONS = true --║ +-- ╚════════════════════════════════════════════════════════════════════════╝ + +local AIO = AIO or require("AIO") +local TransmogrificationHandler = AIO.AddHandlers("TransmogrificationServer", {}) + +local SLOTS = 6 +local CALC = 281 +local PLAYER_VISIBLE_ITEM_1_ENTRYID = 283 -- Head +local PLAYER_VISIBLE_ITEM_3_ENTRYID = 287 -- Shoulder +local PLAYER_VISIBLE_ITEM_4_ENTRYID = 289 -- Shirt +local PLAYER_VISIBLE_ITEM_5_ENTRYID = 291 -- Chest +local PLAYER_VISIBLE_ITEM_6_ENTRYID = 293 -- Waist +local PLAYER_VISIBLE_ITEM_7_ENTRYID = 295 -- Legs +local PLAYER_VISIBLE_ITEM_8_ENTRYID = 297 -- Feet +local PLAYER_VISIBLE_ITEM_9_ENTRYID = 299 -- Wrist +local PLAYER_VISIBLE_ITEM_10_ENTRYID = 301 -- Hands +local PLAYER_VISIBLE_ITEM_15_ENTRYID = 311 -- Back +local PLAYER_VISIBLE_ITEM_16_ENTRYID = 313 -- Main +local PLAYER_VISIBLE_ITEM_17_ENTRYID = 315 -- Off +local PLAYER_VISIBLE_ITEM_18_ENTRYID = 317 -- Ranged +local PLAYER_VISIBLE_ITEM_19_ENTRYID = 319 -- Tabard +local UNUSABLE_INVENTORY_TYPES = {[2] = true, [11] = true, [12] = true, [18] = true, [24] = true, [27] = true, [28] = true} + +-- TODO: Add further language support. +local localeMessages = { + LOOT_ITEM_LOCALE = { + [0] = " has been added to your appearance collection.", -- enUS/enGB + [3] = " wurde deiner Transmog-Sammlung hinzugefügt.", -- deDE + } +} + +local function GetLocalizedMessage(messageID, locale, ...) + local message = localeMessages[messageID][locale] or localeMessages[messageID][0] + if select("#", ...) > 0 then + return string.format(message, ...) + end + return message +end + +function Transmog_CalculateSlot(slot) + if (slot == 0) then + slot = 1 + elseif (slot >= 2) then + slot = slot + 1 + end + return CALC + (slot * 2); +end + +function Transmog_CalculateSlotReverse(slot) + local reverseSlot = (slot - CALC) / 2 + if (reverseSlot == 1) then + return 0; + end + return reverseSlot; +end + +function Transmog_OnCharacterCreate(event, player) + local playerGUID = player:GetGUIDLow() + CharDBQuery("INSERT IGNORE INTO `character_transmog` (`player_guid`, `slot`, `item`, `real_item`) VALUES (" .. playerGUID .. ", '" .. PLAYER_VISIBLE_ITEM_1_ENTRYID .. "', NULL, '');") -- Head + CharDBQuery("INSERT IGNORE INTO `character_transmog` (`player_guid`, `slot`, `item`, `real_item`) VALUES (" .. playerGUID .. ", '" .. PLAYER_VISIBLE_ITEM_3_ENTRYID .. "', NULL, '');") -- Shoulder + CharDBQuery("INSERT IGNORE INTO `character_transmog` (`player_guid`, `slot`, `item`, `real_item`) VALUES (" .. playerGUID .. ", '" .. PLAYER_VISIBLE_ITEM_4_ENTRYID .. "', NULL, '');") -- Shirt + CharDBQuery("INSERT IGNORE INTO `character_transmog` (`player_guid`, `slot`, `item`, `real_item`) VALUES (" .. playerGUID .. ", '" .. PLAYER_VISIBLE_ITEM_5_ENTRYID .. "', NULL, '');") -- Chest + CharDBQuery("INSERT IGNORE INTO `character_transmog` (`player_guid`, `slot`, `item`, `real_item`) VALUES (" .. playerGUID .. ", '" .. PLAYER_VISIBLE_ITEM_6_ENTRYID .. "', NULL, '');") -- Waist + CharDBQuery("INSERT IGNORE INTO `character_transmog` (`player_guid`, `slot`, `item`, `real_item`) VALUES (" .. playerGUID .. ", '" .. PLAYER_VISIBLE_ITEM_7_ENTRYID .. "', NULL, '');") -- Legs + CharDBQuery("INSERT IGNORE INTO `character_transmog` (`player_guid`, `slot`, `item`, `real_item`) VALUES (" .. playerGUID .. ", '" .. PLAYER_VISIBLE_ITEM_8_ENTRYID .. "', NULL, '');") -- Feet + CharDBQuery("INSERT IGNORE INTO `character_transmog` (`player_guid`, `slot`, `item`, `real_item`) VALUES (" .. playerGUID .. ", '" .. PLAYER_VISIBLE_ITEM_9_ENTRYID .. "', NULL, '');") -- Wrist + CharDBQuery("INSERT IGNORE INTO `character_transmog` (`player_guid`, `slot`, `item`, `real_item`) VALUES (" .. playerGUID .. ", '" .. PLAYER_VISIBLE_ITEM_10_ENTRYID .. "', NULL, '');") -- Hands + CharDBQuery("INSERT IGNORE INTO `character_transmog` (`player_guid`, `slot`, `item`, `real_item`) VALUES (" .. playerGUID .. ", '" .. PLAYER_VISIBLE_ITEM_15_ENTRYID .. "', NULL, '');") -- Back + CharDBQuery("INSERT IGNORE INTO `character_transmog` (`player_guid`, `slot`, `item`, `real_item`) VALUES (" .. playerGUID .. ", '" .. PLAYER_VISIBLE_ITEM_16_ENTRYID .. "', NULL, '');") -- Main + CharDBQuery("INSERT IGNORE INTO `character_transmog` (`player_guid`, `slot`, `item`, `real_item`) VALUES (" .. playerGUID .. ", '" .. PLAYER_VISIBLE_ITEM_17_ENTRYID .. "', NULL, '');") -- Off + CharDBQuery("INSERT IGNORE INTO `character_transmog` (`player_guid`, `slot`, `item`, `real_item`) VALUES (" .. playerGUID .. ", '" .. PLAYER_VISIBLE_ITEM_18_ENTRYID .. "', NULL, '');") -- Ranged + CharDBQuery("INSERT IGNORE INTO `character_transmog` (`player_guid`, `slot`, `item`, `real_item`) VALUES (" .. playerGUID .. ", '" .. PLAYER_VISIBLE_ITEM_19_ENTRYID .. "', NULL, '');") -- Tabard +end + +function Transmog_OnCharacterDelete(event, guid) + CharDBQuery("DELETE FROM character_transmog WHERE player_guid = " .. guid .. "") +end + +function Transmog_OnCharacterLogin(event, player) + local playerGUID = player:GetGUIDLow() + local playerExistsQuery = CharDBQuery("SELECT COUNT(*) FROM character_transmog WHERE player_guid = " .. playerGUID .. ";") + local playerExists = playerExistsQuery:GetUInt32(0) > 0 + if not playerExists then + Transmog_OnCharacterCreate(event, player) + end +end + +function TransmogrificationHandler.LootItemLocale(player, item, count, locale) + local accountGUID = player:GetAccountId() + local itemID + local itemTemplate + + if type(item) == "number" then + itemID = item + itemTemplate = GetItemTemplate(itemID) + else + itemTemplate = item:GetItemTemplate() + itemID = itemTemplate:GetItemId() + end + + local inventoryType = itemTemplate:GetInventoryType() + local inventorySubType = itemTemplate:GetSubClass() + local class = itemTemplate:GetClass() + + if (class == 2 or class == 4) and not UNUSABLE_INVENTORY_TYPES[inventoryType] then + local countQuery = AuthDBQuery("SELECT COUNT(*) FROM account_transmog WHERE account_id = " .. accountGUID .. " AND unlocked_item_id = " .. itemID .. ";") + local count = countQuery:GetUInt32(0) + local isNewTransmog = (count == 0) + + local displayID = itemTemplate:GetDisplayId() + + local displayExistsQuery = AuthDBQuery("SELECT COUNT(*) FROM account_transmog WHERE account_id = " .. accountGUID .. " AND display_id = " .. displayID .. ";") + local displayExists = displayExistsQuery:GetUInt32(0) > 0 + + if isNewTransmog and not displayExists then + local itemName = itemTemplate:GetName() + local locItemName = itemTemplate:GetName(locale) + local itemQuality = itemTemplate:GetQuality() + + itemName = itemName:gsub("'", "''") + AuthDBQuery("INSERT IGNORE INTO `account_transmog` (`account_id`, `unlocked_item_id`, `inventory_type`, `inventory_subtype`,`display_id`, `item_name`) VALUES (" .. accountGUID .. ", " .. itemID .. ", " .. inventoryType .. ", " .. inventorySubType .. ", " .. displayID .. ", '" .. itemName .. "');") + + if locItemName == nil then + locItemName = itemTemplate:GetName(0) + end + + local qualityColors = { + [0] = "|cff9d9d9d", -- Poor + [1] = "|cffffffff", -- Common + [2] = "|cff1eff00", -- Uncommon + [3] = "|cff0070dd", -- Rare + [4] = "|cffa335ee", -- Epic + [5] = "|cffff8000", -- Legendary + [6] = "|cffe6cc80" -- Heirloom + } + + local colorCode = qualityColors[itemQuality] or "|cffffffff" -- Default to white if quality not found + + local itemLink = "|Hitem:" .. itemID .. ":0:0:0:0:0:0:0:0|h" .. colorCode .. "[" .. locItemName .. "]|r|h|r" + player:SendBroadcastMessage(itemLink .. GetLocalizedMessage("LOOT_ITEM_LOCALE", locale)) + end + end +end + +function GetDisplaySlotForEquipmentSlot(equipSlot) + local slotMapping = { + [0] = PLAYER_VISIBLE_ITEM_1_ENTRYID, -- Head + [2] = PLAYER_VISIBLE_ITEM_3_ENTRYID, -- Shoulders + [3] = PLAYER_VISIBLE_ITEM_4_ENTRYID, -- Shirt + [4] = PLAYER_VISIBLE_ITEM_5_ENTRYID, -- Chest + [5] = PLAYER_VISIBLE_ITEM_6_ENTRYID, -- Waist + [6] = PLAYER_VISIBLE_ITEM_7_ENTRYID, -- Legs + [7] = PLAYER_VISIBLE_ITEM_8_ENTRYID, -- Feet + [8] = PLAYER_VISIBLE_ITEM_9_ENTRYID, -- Wrists + [9] = PLAYER_VISIBLE_ITEM_10_ENTRYID, -- Hands + [14] = PLAYER_VISIBLE_ITEM_15_ENTRYID, -- Back + [15] = PLAYER_VISIBLE_ITEM_16_ENTRYID, -- Main Hand + [16] = PLAYER_VISIBLE_ITEM_17_ENTRYID, -- Off Hand + [17] = PLAYER_VISIBLE_ITEM_18_ENTRYID, -- Ranged + [18] = PLAYER_VISIBLE_ITEM_19_ENTRYID -- Tabard + } + + return slotMapping[equipSlot] +end + +function Transmog_OnEquipItem(event, player, item, bag, slot) + local itemID = item:GetItemTemplate():GetItemId() + local locale = player:GetDbLocaleIndex() + + if ADD_NEWLY_EQUIPPED_ITEMS_TO_THE_TRANSMOG_LIST then + TransmogrificationHandler.LootItemLocale(player, itemID, 1, locale) + end + + local class = item:GetItemTemplate():GetClass() + local inventoryType = item:GetItemTemplate():GetInventoryType() + + if (class == 2 or class == 4) and not UNUSABLE_INVENTORY_TYPES[inventoryType] then + local playerGUID = player:GetGUIDLow() + local displaySlot = GetDisplaySlotForEquipmentSlot(slot) + + if displaySlot then + CharDBQuery("UPDATE character_transmog SET real_item = " .. itemID .. " WHERE player_guid = " .. playerGUID .. " AND slot = " .. displaySlot) + end + end +end + +function Transmog_OnLootItem(event, player, item, count) + local locale = player:GetDbLocaleIndex() + TransmogrificationHandler.LootItemLocale(player, item, 1, locale) +end + +function Transmog_OnQuestComplete(event, player, quest) + local questID = quest:GetId() + local locale = player:GetDbLocaleIndex() + + local questRewardsQuery = WorldDBQuery("SELECT RewardItem1, RewardItem2, RewardItem3, RewardItem4, RewardChoiceItemID1, RewardChoiceItemID2, RewardChoiceItemID3, RewardChoiceItemID4, RewardChoiceItemID5, RewardChoiceItemID6 FROM quest_template WHERE ID = " .. questID .. ";") + + if not questRewardsQuery then + return + end + + for i = 0, 9 do + local itemID = questRewardsQuery:GetUInt32(i) + if itemID and itemID > 0 then + TransmogrificationHandler.LootItemLocale(player, itemID, 1, locale) + end + end +end + +function GetEquipmentSlot(displaySlot) + -- Map from display/visual slots to actual equipment slots + local slotMapping = { + [PLAYER_VISIBLE_ITEM_1_ENTRYID] = 0, -- Head (0 in equipment slot system) + [PLAYER_VISIBLE_ITEM_3_ENTRYID] = 2, -- Shoulders + [PLAYER_VISIBLE_ITEM_4_ENTRYID] = 3, -- Shirt + [PLAYER_VISIBLE_ITEM_5_ENTRYID] = 4, -- Chest + [PLAYER_VISIBLE_ITEM_6_ENTRYID] = 5, -- Waist + [PLAYER_VISIBLE_ITEM_7_ENTRYID] = 6, -- Legs + [PLAYER_VISIBLE_ITEM_8_ENTRYID] = 7, -- Feet + [PLAYER_VISIBLE_ITEM_9_ENTRYID] = 8, -- Wrists + [PLAYER_VISIBLE_ITEM_10_ENTRYID] = 9, -- Hands + [PLAYER_VISIBLE_ITEM_15_ENTRYID] = 14, -- Back/Cloak + [PLAYER_VISIBLE_ITEM_16_ENTRYID] = 15, -- Main Hand + [PLAYER_VISIBLE_ITEM_17_ENTRYID] = 16, -- Off Hand + [PLAYER_VISIBLE_ITEM_18_ENTRYID] = 17, -- Ranged + [PLAYER_VISIBLE_ITEM_19_ENTRYID] = 18, -- Tabard + } + + return slotMapping[displaySlot] or Transmog_CalculateSlotReverse(displaySlot) +end + +-- TODO: add lua/c++ function for unequip!! +function TransmogrificationHandler.OnUnequipItem(player) + local playerGUID = player:GetGUIDLow() + + -- Check all slots to see if any items were unequipped + local slots = { + PLAYER_VISIBLE_ITEM_1_ENTRYID, -- Head + PLAYER_VISIBLE_ITEM_3_ENTRYID, -- Shoulder + PLAYER_VISIBLE_ITEM_4_ENTRYID, -- Shirt + PLAYER_VISIBLE_ITEM_5_ENTRYID, -- Chest + PLAYER_VISIBLE_ITEM_6_ENTRYID, -- Waist + PLAYER_VISIBLE_ITEM_7_ENTRYID, -- Legs + PLAYER_VISIBLE_ITEM_8_ENTRYID, -- Feet + PLAYER_VISIBLE_ITEM_9_ENTRYID, -- Wrist + PLAYER_VISIBLE_ITEM_10_ENTRYID, -- Hands + PLAYER_VISIBLE_ITEM_15_ENTRYID, -- Back + PLAYER_VISIBLE_ITEM_16_ENTRYID, -- Main + PLAYER_VISIBLE_ITEM_17_ENTRYID, -- Off + PLAYER_VISIBLE_ITEM_18_ENTRYID, -- Ranged + PLAYER_VISIBLE_ITEM_19_ENTRYID -- Tabard + } + + for _, slot in ipairs(slots) do + -- Get the corresponding equipment slot + local equipmentSlot = GetEquipmentSlot(slot) + + -- Check if this slot has an item equipped + local currentItem = player:GetEquippedItemBySlot(equipmentSlot) + + -- If the slot is empty but we have a transmog value, we need to clear it + if not currentItem then + local transmogQuery = CharDBQuery("SELECT item FROM character_transmog WHERE player_guid = "..playerGUID.." AND slot = "..slot..";") + + if transmogQuery and transmogQuery:GetUInt32(0) and transmogQuery:GetUInt32(0) > 0 then + -- Clear the transmog by setting both item and real_item to NULL + CharDBQuery("UPDATE character_transmog SET item = NULL, real_item = NULL WHERE player_guid = "..playerGUID.." AND slot = "..slot..";") + player:SetUInt32Value(tonumber(slot), 0) + + -- Inform the client to update the display for this slot + AIO.Handle(player, "TransmogrificationServer", "ClearSlotTransmogrification", slot) + end + end + end +end + +function Transmog_Load(player) + local playerGUID = player:GetGUIDLow() + + local transmogs = CharDBQuery("SELECT item, slot FROM character_transmog WHERE player_guid = "..playerGUID..";") + if (transmogs == nil) then + return; + end + + for i = 1, transmogs:GetRowCount(), 1 do + local currentRow = transmogs:GetRow() + local slot = currentRow["slot"] + local item = currentRow["item"] + if (item ~= nil and item ~= '') then + player:SetUInt32Value(tonumber(slot), item) + end + transmogs:NextRow() + end +end + +function Transmog_OnLogin(event, player) + -- Apply transmog on login + -- Transmog_Load(player) + --local item = player:GetEquippedItemBySlot(4) + --print(item:GetName()) +end + +function TransmogrificationHandler.LoadPlayer(player) + Transmog_Load(player) + player:SetUInt32Value(147, 1) -- use unit padding +end + +function TransmogrificationHandler.EquipTransmogItem(player, item, slot) + local playerGUID = player:GetGUIDLow() + + if item == nil and item ~= 0 then + local oldItem = CharDBQuery("SELECT real_item FROM character_transmog WHERE player_guid = "..playerGUID.." AND slot = "..slot..";") + local oldItemID = oldItem:GetUInt32(0) + if oldItemID == nil or oldItemID == 0 then + CharDBQuery("INSERT INTO character_transmog (`player_guid`, `slot`, `item`) VALUES ("..playerGUID..", '"..slot.."', NULL) ON DUPLICATE KEY UPDATE item = VALUES(item);") + player:SetUInt32Value(tonumber(slot), 0) + return + end + + CharDBQuery("INSERT INTO character_transmog (`player_guid`, `slot`, `item`, `real_item`) VALUES ("..playerGUID..", '"..slot.."', NULL, "..oldItemID..") ON DUPLICATE KEY UPDATE item = VALUES(item), real_item = VALUES(real_item);") + player:SetUInt32Value(tonumber(slot), oldItemID) + return + end + + local oldItem = CharDBQuery("SELECT real_item FROM character_transmog WHERE player_guid = "..playerGUID.." AND slot = "..slot..";") + local oldItemID = oldItem:GetUInt32(0) + if oldItemID == nil or oldItemID == 0 then + CharDBQuery("INSERT INTO character_transmog (`player_guid`, `slot`, `item`) VALUES ("..playerGUID..", '"..slot.."', "..item..") ON DUPLICATE KEY UPDATE item = VALUES(item);") + else + CharDBQuery("INSERT INTO character_transmog (`player_guid`, `slot`, `item`, `real_item`) VALUES ("..playerGUID..", '"..slot.."', "..item..", "..oldItemID..") ON DUPLICATE KEY UPDATE item = VALUES(item), real_item = VALUES(real_item);") + end + player:SetUInt32Value(tonumber(slot), item) +end + +function TransmogrificationHandler.EquipAllTransmogItems(player, transmogPreview) + if (transmogPreview == {}) then + return; + end + + local playerGUID = player:GetGUIDLow() + + for slot, item in ipairs(transmogPreview) do + player:SetUInt32Value(tonumber(slot), item) + CharDBQuery("INSERT INTO character_transmog (`player_guid`, `slot`, `item`) VALUES ("..playerGUID..", '"..slot.."', "..item..") ON DUPLICATE KEY UPDATE item = VALUES(item);") + end +end + +function TransmogrificationHandler.UnequipTransmogItem(player, slot) + local playerGUID = player:GetGUIDLow() + + -- Get the corresponding equipment slot using our mapping function + local equipmentSlot = GetEquipmentSlot(slot) + + -- Check if there's an actual item equipped in this slot + local currentItem = player:GetEquippedItemBySlot(equipmentSlot) + + -- If no item is currently equipped, we should set the visual to 0 + if not currentItem then + CharDBQuery("UPDATE character_transmog SET item = NULL, real_item = NULL WHERE player_guid = "..playerGUID.." AND slot = "..slot..";") + player:SetUInt32Value(tonumber(slot), 0) + return + end + + -- Otherwise, handle normally but ensure we're setting to the real item or 0 + local oldItem = CharDBQuery("SELECT real_item FROM character_transmog WHERE player_guid = "..playerGUID.." AND slot = "..slot..";") + + -- If no record or null real_item, set to the actual item's appearance + if not oldItem or not oldItem:GetUInt32(0) or oldItem:GetUInt32(0) == 0 then + -- Here we set item to NULL (not 0) to indicate no transmog is applied + CharDBQuery("UPDATE character_transmog SET item = NULL WHERE player_guid = "..playerGUID.." AND slot = "..slot..";") + + -- Get the current equipped item's ID to display + local realItemID = currentItem:GetItemTemplate():GetItemId() + player:SetUInt32Value(tonumber(slot), realItemID) + return + end + + -- If we have a real_item value, restore that appearance + local oldItemID = oldItem:GetUInt32(0) + CharDBQuery("UPDATE character_transmog SET item = NULL WHERE player_guid = "..playerGUID.." AND slot = "..slot..";") + player:SetUInt32Value(tonumber(slot), oldItemID) +end + +function TransmogrificationHandler.displayTransmog(player, spellid) + AIO.Handle(player, "TransmogrificationServer", "TransmogrificationFrame") + return false +end + +function TransmogrificationHandler.Print(player, ...) + print(...) +end + +function TransmogrificationHandler.SetTransmogItemIDs(player) + local playerGUID = player:GetGUIDLow() + + local transmogs = CharDBQuery('SELECT item, real_item, slot FROM character_transmog WHERE player_guid = '..playerGUID..';') -- AND slot NOT IN ("313", "315", "317") + if (transmogs == nil) then + return; + end + + for i = 1, transmogs:GetRowCount(), 1 do + local currentRow = transmogs:GetRow() + local item = currentRow["item"] + local slot = currentRow["slot"] + local real_item = currentRow["real_item"] + local validSlotItem = player:GetUInt32Value(tonumber(slot)) + if (validSlotItem == 0) then + CharDBQuery("INSERT INTO character_transmog (`player_guid`, `slot`, `item`, `real_item`) VALUES ("..playerGUID..", '"..slot.."', 0, "..real_item..") ON DUPLICATE KEY UPDATE item = VALUES(item), real_item = VALUES(real_item);") + end + if (not item or item == 0 and real_item ~= nil and real_item ~= 0 and (validSlotItem ~= 0 or not validSlotItem)) then + AIO.Handle(player, "TransmogrificationServer", "SetTransmogItemIDClient", slot, 0, real_item) + else + AIO.Handle(player, "TransmogrificationServer", "SetTransmogItemIDClient", slot, item, real_item) + end + transmogs:NextRow() + end +end + +function TransmogrificationHandler.SetCurrentSlotItemIDs(player, slot, page) + local accountGUID = player:GetAccountId() + + -- Define inventory type mapping + local inventoryTypesMapping = { + [PLAYER_VISIBLE_ITEM_1_ENTRYID] = "= 1", + [PLAYER_VISIBLE_ITEM_3_ENTRYID] = "= 3", + [PLAYER_VISIBLE_ITEM_4_ENTRYID] = "= 4", + [PLAYER_VISIBLE_ITEM_5_ENTRYID] = "IN (5, 20)", + [PLAYER_VISIBLE_ITEM_6_ENTRYID] = "= 6", + [PLAYER_VISIBLE_ITEM_7_ENTRYID] = "= 7", + [PLAYER_VISIBLE_ITEM_8_ENTRYID] = "= 8", + [PLAYER_VISIBLE_ITEM_9_ENTRYID] = "= 9", + [PLAYER_VISIBLE_ITEM_10_ENTRYID] = "= 10", + [PLAYER_VISIBLE_ITEM_15_ENTRYID] = "= 16", + [PLAYER_VISIBLE_ITEM_16_ENTRYID] = "IN (13, 17, 21)", + [PLAYER_VISIBLE_ITEM_17_ENTRYID] = "IN (13, 17, 22, 23, 14)", + [PLAYER_VISIBLE_ITEM_18_ENTRYID] = "IN (15, 25, 26)", + [PLAYER_VISIBLE_ITEM_19_ENTRYID] = "= 19" + } + + -- Get the inventory type for the given slot + local inventoryTypes = inventoryTypesMapping[slot] + if not inventoryTypes then + return -- Slot not valid, exit early + end + + local equipmentSlot = nil + + if slot == PLAYER_VISIBLE_ITEM_3_ENTRYID then + equipmentSlot = 2 -- Shoulder + elseif slot == PLAYER_VISIBLE_ITEM_4_ENTRYID then + equipmentSlot = 3 -- Shirt + elseif slot == PLAYER_VISIBLE_ITEM_5_ENTRYID then + equipmentSlot = 4 -- Chest + elseif slot == PLAYER_VISIBLE_ITEM_6_ENTRYID then + equipmentSlot = 5 -- Waist + elseif slot == PLAYER_VISIBLE_ITEM_10_ENTRYID then + equipmentSlot = 9 -- Hands + elseif slot == PLAYER_VISIBLE_ITEM_15_ENTRYID then + equipmentSlot = 14 -- Back + elseif slot == PLAYER_VISIBLE_ITEM_16_ENTRYID then + equipmentSlot = 15 -- Main + elseif slot == PLAYER_VISIBLE_ITEM_17_ENTRYID then + equipmentSlot = 16 -- Off + elseif slot == PLAYER_VISIBLE_ITEM_18_ENTRYID then + equipmentSlot = 17 -- Ranged + else + equipmentSlot = Transmog_CalculateSlotReverse(slot) + end + + local currentItem = player:GetEquippedItemBySlot(equipmentSlot) + local equippedItemType = nil + local equippedItemSubType = nil + + if currentItem then + equippedItemType = currentItem:GetClass() + equippedItemSubType = currentItem:GetSubClass() + end + + -- Calculate page offset for pagination + local pageOffset = (page > 1) and (SLOTS * (page - 1)) or 0 + + local queryConditions = "account_id = " .. accountGUID .. " AND inventory_type " .. inventoryTypes + + if equippedItemSubType then + if (RESTRICT_ARMOR_TRANSMOG_TO_SIMILAR_MATERIALS and equippedItemType == 4) then + if slot == PLAYER_VISIBLE_ITEM_5_ENTRYID then -- Special check for chestpiece/robes. + queryConditions = queryConditions .. " AND inventory_subtype = " .. equippedItemSubType + else + queryConditions = queryConditions .. " AND inventory_subtype = " .. equippedItemSubType + end + elseif (RESTRICT_WEAPON_TRANSMOG_TO_SIMILAR_WEAPONS and equippedItemType == 2) then + queryConditions = queryConditions .. " AND inventory_subtype = " .. equippedItemSubType + end + end + + -- Query to count matching transmogs + local countQuery = string.format( + "SELECT COUNT(unlocked_item_id) FROM account_transmog WHERE %s", + queryConditions + ) + local countResult = AuthDBQuery(countQuery) + if not countResult then + AIO.Handle(player, "TransmogrificationServer", "InitTab", {}, page, false) + return + end + + -- Get the total number of transmogs + local totalTransmogs = countResult:GetUInt32(0) + local hasMorePages = (totalTransmogs > SLOTS * page) + + -- Query to retrieve transmogs for the current page + local transmogQuery = string.format( + "SELECT unlocked_item_id FROM account_transmog WHERE %s LIMIT %d OFFSET %d;", + queryConditions, SLOTS, pageOffset + ) + local transmogs = AuthDBQuery(transmogQuery) + if not transmogs then + AIO.Handle(player, "TransmogrificationServer", "InitTab", {}, page, false) + return + end + + -- Collect the unlocked item IDs + local currentSlotItemIDs = {} + for i = 1, transmogs:GetRowCount() do + local currentRow = transmogs:GetRow() + local item = currentRow["unlocked_item_id"] + table.insert(currentSlotItemIDs, item) + transmogs:NextRow() + end + + -- Return the result to the player + AIO.Handle(player, "TransmogrificationServer", "InitTab", currentSlotItemIDs, page, hasMorePages) +end + +function TransmogrificationHandler.SetSearchCurrentSlotItemIDs(player, slot, page, search) + -- Ensure search is not empty or nil + if ( search == nil or serach == '' ) then + return; + end + + -- Escape special characters in search string + search = search:gsub("[%'`&\"]", "%%") + + -- Define slot-to-inventory type mapping + local inventoryTypesMapping = { + [PLAYER_VISIBLE_ITEM_1_ENTRYID] = "= 1", + [PLAYER_VISIBLE_ITEM_3_ENTRYID] = "= 3", + [PLAYER_VISIBLE_ITEM_4_ENTRYID] = "= 4", + [PLAYER_VISIBLE_ITEM_5_ENTRYID] = "IN (5, 20)", + [PLAYER_VISIBLE_ITEM_6_ENTRYID] = "= 6", + [PLAYER_VISIBLE_ITEM_7_ENTRYID] = "= 7", + [PLAYER_VISIBLE_ITEM_8_ENTRYID] = "= 8", + [PLAYER_VISIBLE_ITEM_9_ENTRYID] = "= 9", + [PLAYER_VISIBLE_ITEM_10_ENTRYID] = "= 10", + [PLAYER_VISIBLE_ITEM_15_ENTRYID] = "= 16", + [PLAYER_VISIBLE_ITEM_16_ENTRYID] = "IN (13, 17, 21)", + [PLAYER_VISIBLE_ITEM_17_ENTRYID] = "IN (13, 17, 22, 23, 14)", + [PLAYER_VISIBLE_ITEM_18_ENTRYID] = "IN (15, 25, 26)", + [PLAYER_VISIBLE_ITEM_19_ENTRYID] = "= 19" + } + + -- Get inventory type for the given slot + local inventoryTypes = inventoryTypesMapping[slot] + if not inventoryTypes then + return -- Slot not valid + end + + local equipmentSlot = nil + + if slot == PLAYER_VISIBLE_ITEM_3_ENTRYID then + equipmentSlot = 2 -- Shoulder + elseif slot == PLAYER_VISIBLE_ITEM_4_ENTRYID then + equipmentSlot = 3 -- Shirt + elseif slot == PLAYER_VISIBLE_ITEM_5_ENTRYID then + equipmentSlot = 4 -- Chest + elseif slot == PLAYER_VISIBLE_ITEM_6_ENTRYID then + equipmentSlot = 5 -- Waist + elseif slot == PLAYER_VISIBLE_ITEM_10_ENTRYID then + equipmentSlot = 9 -- Hands + elseif slot == PLAYER_VISIBLE_ITEM_15_ENTRYID then + equipmentSlot = 14 -- Back + elseif slot == PLAYER_VISIBLE_ITEM_16_ENTRYID then + equipmentSlot = 15 -- Main + elseif slot == PLAYER_VISIBLE_ITEM_17_ENTRYID then + equipmentSlot = 16 -- Off + elseif slot == PLAYER_VISIBLE_ITEM_18_ENTRYID then + equipmentSlot = 17 -- Ranged + else + equipmentSlot = Transmog_CalculateSlotReverse(slot) + end + + local currentItem = player:GetEquippedItemBySlot(equipmentSlot) + local equippedItemType = nil + local equippedItemSubType = nil + + if currentItem then + equippedItemType = currentItem:GetClass() + equippedItemSubType = currentItem:GetSubClass() + end + + -- Calculate page offset + local pageOffset = (page > 1) and (SLOTS * (page - 1)) or 0 + + local queryConditions = "account_id = " .. player:GetAccountId() .. " AND inventory_type " .. inventoryTypes .. " AND (display_id LIKE '%" .. search .. "%' OR item_name LIKE '%" .. search .. "%')" + + if equippedItemSubType then + if (RESTRICT_ARMOR_TRANSMOG_TO_SIMILAR_MATERIALS and equippedItemType == 4) then + if slot == PLAYER_VISIBLE_ITEM_5_ENTRYID then -- Special check for chestpiece/robes. + queryConditions = queryConditions .. " AND inventory_subtype = " .. equippedItemSubType + else + queryConditions = queryConditions .. " AND inventory_subtype = " .. equippedItemSubType + end + elseif (RESTRICT_WEAPON_TRANSMOG_TO_SIMILAR_WEAPONS and equippedItemType == 2) then + queryConditions = queryConditions .. " AND inventory_subtype = " .. equippedItemSubType + end + end + + -- Query to count matching transmogs + local countQuery = string.format( + "SELECT COUNT(unlocked_item_id) FROM account_transmog WHERE %s;", + queryConditions + ) + local countResult = AuthDBQuery(countQuery) + if not countResult then + AIO.Handle(player, "TransmogrificationServer", "InitTab", {}, page, false) + return + end + + local totalTransmogs = countResult:GetUInt32(0) + local hasMorePages = (totalTransmogs > SLOTS * page) + + -- Query to get transmogs + local transmogQuery = string.format( + "SELECT unlocked_item_id FROM account_transmog WHERE %s LIMIT %d OFFSET %d;", + queryConditions, SLOTS, pageOffset + ) + local transmogs = AuthDBQuery(transmogQuery) + if not transmogs then + AIO.Handle(player, "TransmogrificationServer", "InitTab", {}, page, false) + return + end + + -- Collect the unlocked item IDs + local currentSlotItemIDs = {} + for i = 1, transmogs:GetRowCount() do + local currentRow = transmogs:GetRow() + local item = currentRow["unlocked_item_id"] + table.insert(currentSlotItemIDs, item) + transmogs:NextRow() + end + + -- Return the result + AIO.Handle(player, "TransmogrificationServer", "InitTab", currentSlotItemIDs, page, hasMorePages) +end + +function TransmogrificationHandler.SetEquipmentTransmogInfo(player, slot, currentSlotTooltip) + local playerGUID = player:GetGUIDLow() + + local transmog = CharDBQuery("SELECT COUNT(item) FROM character_transmog WHERE player_guid = "..playerGUID.." AND slot = '"..slot.."';") + if (transmog == nil) then + return; + end + + if (transmog:GetUInt32(0) ~= 0) then + AIO.Handle(player, "TransmogrificationServer", "SetEquipmentTransmogInfoClient", currentSlotTooltip) + end +end + +function TransmogrificationHandler.GetItemsWithSameAppearance(player, itemID) + -- Query the server for the display ID of the new item + local displayIDQuery = "SELECT displayid FROM item_template WHERE entry = " .. itemID .. ";" + local displayIDResult = WorldDBQuery(displayIDQuery) + + if not displayIDResult then + return + end + + local displayID = displayIDResult:GetUInt32(0) + + -- Find all items with the same display ID + local matchingItemsQuery = "SELECT entry FROM item_template WHERE displayid = " .. displayID .. ";" + local matchingItemsResult = WorldDBQuery(matchingItemsQuery) + + if not matchingItemsResult then + return + end + + -- Collect the matching item IDs into a table + local matchingItems = {} + for i = 1, matchingItemsResult:GetRowCount() do + local currentRow = matchingItemsResult:GetRow() + local matchingItemID = currentRow["entry"] + table.insert(matchingItems, matchingItemID) + matchingItemsResult:NextRow() + end + + -- Send the matching transmogs to the client + AIO.Handle(player, "TransmogrificationServer", "ReceiveMatchingAppearances", itemID, matchingItems) +end + +function TransmogrificationHandler.SendCollectedTransmogItemIDs(player) + local accountGUID = player:GetAccountId() + + -- Query to retrieve collected transmog display IDs + local collectedDisplayIDsQuery = "SELECT DISTINCT display_id FROM account_transmog WHERE account_id = " .. accountGUID .. ";" + local displayIDsResult = AuthDBQuery(collectedDisplayIDsQuery) + + if not displayIDsResult then + AIO.Handle(player, "TransmogrificationServer", "ReceiveCollectedAppearances", {}, 0) + return + end + + -- Count the unique appearances. + local uniqueAppearancesCount = displayIDsResult:GetRowCount() + + -- Collect the display IDs into a table + local collectedDisplayIDs = {} + for i = 1, displayIDsResult:GetRowCount() do + local currentRow = displayIDsResult:GetRow() + local displayID = currentRow["display_id"] + table.insert(collectedDisplayIDs, displayID) + displayIDsResult:NextRow() + end + + local collectedAppearances = {} + + -- For each display ID, find all items that share the appearance + for _, displayID in ipairs(collectedDisplayIDs) do + local itemsWithDisplayQuery = "SELECT entry FROM item_template WHERE displayid = " .. displayID .. ";" + local itemsResult = WorldDBQuery(itemsWithDisplayQuery) + + if itemsResult then + for j = 1, itemsResult:GetRowCount() do + local itemRow = itemsResult:GetRow() + local itemID = itemRow["entry"] + table.insert(collectedAppearances, itemID) + itemsResult:NextRow() + end + end + end + + -- Send the collected transmogs to the client + AIO.Handle(player, "TransmogrificationServer", "ReceiveCollectedAppearances", collectedAppearances, uniqueAppearancesCount) +end + +RegisterPlayerEvent(1, Transmog_OnCharacterCreate) +RegisterPlayerEvent(2, Transmog_OnCharacterDelete) +RegisterPlayerEvent(3, Transmog_OnCharacterLogin) + +RegisterPlayerEvent(29, Transmog_OnEquipItem) + +RegisterPlayerEvent(30, function(event, player, bag, slot) + if bag == 255 then + TransmogrificationHandler.OnUnequipItem(player) + end +end) + +if ADD_NEWLY_LOOTED_ITEMS_TO_THE_TRANSMOG_LIST then + RegisterPlayerEvent(32, Transmog_OnLootItem) + RegisterPlayerEvent(51, Transmog_OnLootItem) + RegisterPlayerEvent(52, Transmog_OnLootItem) + RegisterPlayerEvent(53, Transmog_OnLootItem) + RegisterPlayerEvent(56, Transmog_OnLootItem) +end + +if ADD_QUEST_REWARD_ITEMS_TO_THE_TRANSMOG_LIST then + RegisterPlayerEvent(54, Transmog_OnQuestComplete) +end + +RegisterPlayerEvent(42, function(event, player, command) + if command:lower() == "transmog sync" then + TransmogrificationHandler.SendCollectedTransmogItemIDs(player) + return false + end + return true +end) + +print("[Eluna] Transmog System loaded successfully.") diff --git a/sql/Transmogrification/auth.sql b/sql/Transmogrification/auth.sql new file mode 100644 index 000000000..7af93d249 --- /dev/null +++ b/sql/Transmogrification/auth.sql @@ -0,0 +1,35 @@ +-- -------------------------------------------------------- +-- Host: 192.168.0.167 +-- Server-Version: 8.3.0 - MySQL Community Server - GPL +-- Server-Betriebssystem: Linux +-- HeidiSQL Version: 12.8.0.6908 +-- -------------------------------------------------------- + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET NAMES utf8 */; +/*!50503 SET NAMES utf8mb4 */; +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; + +-- Exportiere Struktur von Tabelle acore_auth.account_transmog +CREATE TABLE IF NOT EXISTS `account_transmog` ( + `account_id` int unsigned NOT NULL, + `unlocked_item_id` int unsigned NOT NULL, + `inventory_type` int unsigned DEFAULT NULL, + `inventory_subtype` int unsigned DEFAULT NULL, + `display_id` int unsigned NOT NULL, + `item_name` varchar(255) COLLATE utf8mb4_general_ci DEFAULT NULL, + UNIQUE KEY `account_item_id` (`account_id`,`unlocked_item_id`) USING BTREE, + UNIQUE KEY `account_display_id` (`account_id`,`display_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; + +-- Daten-Export vom Benutzer nicht ausgewählt + +/*!40103 SET TIME_ZONE=IFNULL(@OLD_TIME_ZONE, 'system') */; +/*!40101 SET SQL_MODE=IFNULL(@OLD_SQL_MODE, '') */; +/*!40014 SET FOREIGN_KEY_CHECKS=IFNULL(@OLD_FOREIGN_KEY_CHECKS, 1) */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40111 SET SQL_NOTES=IFNULL(@OLD_SQL_NOTES, 1) */; diff --git a/sql/Transmogrification/char.sql b/sql/Transmogrification/char.sql new file mode 100644 index 000000000..b4ae5881a --- /dev/null +++ b/sql/Transmogrification/char.sql @@ -0,0 +1,33 @@ +-- -------------------------------------------------------- +-- Host: 192.168.0.167 +-- Server-Version: 8.3.0 - MySQL Community Server - GPL +-- Server-Betriebssystem: Linux +-- HeidiSQL Version: 12.8.0.6908 +-- -------------------------------------------------------- + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET NAMES utf8 */; +/*!50503 SET NAMES utf8mb4 */; +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; + +-- Exportiere Struktur von Tabelle acore_characters.character_transmog +CREATE TABLE IF NOT EXISTS `character_transmog` ( + `player_guid` int unsigned DEFAULT NULL, + `slot` varchar(3) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '', + `item` int unsigned DEFAULT NULL, + `real_item` int unsigned DEFAULT NULL, + UNIQUE KEY `player_and_slot` (`player_guid`,`slot`) USING BTREE, + KEY `player_and_slot_key` (`player_guid`,`slot`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; + +-- Daten-Export vom Benutzer nicht ausgewählt + +/*!40103 SET TIME_ZONE=IFNULL(@OLD_TIME_ZONE, 'system') */; +/*!40101 SET SQL_MODE=IFNULL(@OLD_SQL_MODE, '') */; +/*!40014 SET FOREIGN_KEY_CHECKS=IFNULL(@OLD_FOREIGN_KEY_CHECKS, 1) */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40111 SET SQL_NOTES=IFNULL(@OLD_SQL_NOTES, 1) */; From 4d36c6f70293fe9334544e0867e12d6631aa563e Mon Sep 17 00:00:00 2001 From: gasaichandesu Date: Fri, 7 Aug 2026 08:05:47 +0400 Subject: [PATCH 2/2] fix(sql): fix transmog sql being imported in incorrect database --- import-custom-sql.sh | 23 ++++++----------------- 1 file changed, 6 insertions(+), 17 deletions(-) diff --git a/import-custom-sql.sh b/import-custom-sql.sh index 4965ca9a0..aafb09597 100644 --- a/import-custom-sql.sh +++ b/import-custom-sql.sh @@ -145,7 +145,7 @@ import_mythicplus_sql() { WHEN EXISTS (SELECT 1 FROM creature_template WHERE entry = 900001) AND EXISTS (SELECT 1 FROM item_template WHERE entry = 900100) AND EXISTS (SELECT 1 FROM gameobject_template WHERE entry = 900000) - AND EXISTS (SELECT 1 FROM creature WHERE id = 900001) + AND EXISTS (SELECT 1 FROM creature WHERE id1 = 900001) AND EXISTS (SELECT 1 FROM gameobject WHERE id = 900000) THEN 1 ELSE 0 @@ -156,7 +156,7 @@ import_mythicplus_sql() { log "repairing MythicPlus world bootstrap entries" mysql_exec "acore_world" " DELETE FROM creature WHERE id = 900001; - DELETE FROM gameobject WHERE id = 900000; + DELETE FROM gameobject WHERE id1 = 900000; DELETE FROM creature_template_locale WHERE entry = 900001; DELETE FROM item_template_locale WHERE ID = 900100; DELETE FROM creature_template_model WHERE CreatureID = 900001; @@ -280,24 +280,13 @@ import_playerbots_ru_sql() { } import_transmog_sql() { + log "Started importing Transmogrification SQL files" + local account_transmog_sql="$ROOT_DIR/sql/Transmogrification/auth.sql" local character_transmog_sql="$ROOT_DIR/sql/Transmogrification/char.sql" - if table_exists "acore_world" "account_transmog"; then - log "account_transmog table already exists, skipping" - else - import_sql_file "acore_world" "$account_transmog_sql" - - log "account_transmog table was successfully imported" - fi - - if table_exists "acore_world" "character_transmog"; then - log "character_transmog table already exists, skipping" - else - import_sql_file "acore_world" "$character_transmog_sql" - - log "account_character table was successfully imported" - fi + maybe_import_table "acore_auth" "account_transmog" "$account_transmog_sql" + maybe_import_table "acore_characters" "character_transmog" "$character_transmog_sql" } configure_server_motd() {