annotate Import.lua @ 141:cc82eeeec1c8 v66

Fixed bug with multiple set import.
author yellowfive
date Tue, 06 Nov 2018 15:39:13 -0800
parents c229c759a125
children 35612aee8e15
rev   line source
yellowfive@57 1 local Amr = LibStub("AceAddon-3.0"):GetAddon("AskMrRobot")
yellowfive@57 2 local L = LibStub("AceLocale-3.0"):GetLocale("AskMrRobot", true)
yellowfive@57 3 local AceGUI = LibStub("AceGUI-3.0")
yellowfive@57 4
yellowfive@57 5 local _txtImport
yellowfive@57 6 local _lblError
yellowfive@69 7 local _panelCover
yellowfive@57 8
yellowfive@57 9 local function onImportOkClick(widget)
yellowfive@57 10 local txt = _txtImport:GetText()
yellowfive@57 11 local msg = Amr:ImportCharacter(txt)
yellowfive@57 12 if msg then
yellowfive@57 13 _lblError:SetText(msg)
yellowfive@57 14 _txtImport:SetFocus(true)
yellowfive@57 15 else
yellowfive@57 16 Amr:HideCover()
yellowfive@139 17 Amr:RefreshGearDisplay()
yellowfive@57 18 end
yellowfive@57 19 end
yellowfive@57 20
yellowfive@57 21 local function onImportCancelClick(widget)
yellowfive@57 22 Amr:HideCover()
yellowfive@57 23 end
yellowfive@57 24
yellowfive@69 25 local function onTextEnterPressed(widget)
yellowfive@69 26 -- hide the overwolf cover when import data is received
yellowfive@69 27 if _panelCover then
yellowfive@69 28 _panelCover:SetVisible(false)
yellowfive@69 29 end
yellowfive@69 30
yellowfive@69 31 -- do an import if the data starts and ends with a dollar sign
yellowfive@69 32 local txt = _txtImport:GetText()
yellowfive@69 33 local txtLen = string.len(txt)
yellowfive@69 34 if txtLen > 2 and string.sub(txt, 1, 1) == '$' then
yellowfive@69 35 onImportOkClick()
yellowfive@69 36 end
yellowfive@69 37
yellowfive@69 38 end
yellowfive@69 39
yellowfive@69 40 local function renderImportWindow(container, fromOverwolf)
yellowfive@57 41
yellowfive@57 42 local panelImport = Amr:RenderCoverChrome(container, 700, 450)
yellowfive@57 43
yellowfive@57 44 local lbl = AceGUI:Create("AmrUiLabel")
yellowfive@124 45 panelImport:AddChild(lbl)
yellowfive@57 46 lbl:SetWidth(600)
yellowfive@57 47 lbl:SetText(L.ImportHeader)
yellowfive@57 48 lbl:SetPoint("TOP", panelImport.content, "TOP", 0, -10)
yellowfive@57 49
yellowfive@57 50 _txtImport = AceGUI:Create("AmrUiTextarea")
yellowfive@57 51 _txtImport:SetWidth(600)
yellowfive@57 52 _txtImport:SetHeight(300)
yellowfive@57 53 _txtImport:SetFont(Amr.CreateFont("Regular", 12, Amr.Colors.Text))
yellowfive@69 54 _txtImport:SetCallback("OnEnterPressed", onTextEnterPressed)
yellowfive@57 55 panelImport:AddChild(_txtImport)
yellowfive@124 56 _txtImport:SetPoint("TOP", lbl.frame, "BOTTOM", 0, -10)
yellowfive@57 57
yellowfive@57 58 local btnImportOk = AceGUI:Create("AmrUiButton")
yellowfive@57 59 btnImportOk:SetText(L.ImportButtonOk)
yellowfive@57 60 btnImportOk:SetBackgroundColor(Amr.Colors.Green)
yellowfive@57 61 btnImportOk:SetFont(Amr.CreateFont("Bold", 16, Amr.Colors.White))
yellowfive@57 62 btnImportOk:SetWidth(120)
yellowfive@57 63 btnImportOk:SetHeight(28)
yellowfive@57 64 btnImportOk:SetCallback("OnClick", onImportOkClick)
yellowfive@57 65 panelImport:AddChild(btnImportOk)
yellowfive@124 66 btnImportOk:SetPoint("TOPLEFT", _txtImport.frame, "BOTTOMLEFT", 0, -10)
yellowfive@57 67
yellowfive@57 68 local btnImportCancel = AceGUI:Create("AmrUiButton")
yellowfive@57 69 btnImportCancel:SetText(L.ImportButtonCancel)
yellowfive@57 70 btnImportCancel:SetBackgroundColor(Amr.Colors.Green)
yellowfive@57 71 btnImportCancel:SetFont(Amr.CreateFont("Bold", 16, Amr.Colors.White))
yellowfive@57 72 btnImportCancel:SetWidth(120)
yellowfive@57 73 btnImportCancel:SetHeight(28)
yellowfive@57 74 btnImportCancel:SetCallback("OnClick", onImportCancelClick)
yellowfive@57 75 panelImport:AddChild(btnImportCancel)
yellowfive@124 76 btnImportCancel:SetPoint("LEFT", btnImportOk.frame, "RIGHT", 20, 0)
yellowfive@57 77
yellowfive@57 78 _lblError = AceGUI:Create("AmrUiLabel")
yellowfive@124 79 panelImport:AddChild(_lblError)
yellowfive@57 80 _lblError:SetWidth(600)
yellowfive@57 81 _lblError:SetFont(Amr.CreateFont("Bold", 14, Amr.Colors.Red))
yellowfive@57 82 _lblError:SetText("")
yellowfive@57 83 _lblError:SetPoint("TOPLEFT", btnImportOk.frame, "BOTTOMLEFT", 0, -20)
yellowfive@57 84
yellowfive@69 85 if fromOverwolf then
yellowfive@69 86 -- show a cover preventing interaction until we receive data from overwolf
yellowfive@69 87 _panelCover = AceGUI:Create("AmrUiPanel")
yellowfive@69 88 _panelCover:SetLayout("None")
yellowfive@69 89 _panelCover:EnableMouse(true)
yellowfive@69 90 _panelCover:SetBackgroundColor(Amr.Colors.Black, 0.75)
yellowfive@124 91 panelImport:AddChild(_panelCover)
yellowfive@69 92 _panelCover:SetPoint("TOPLEFT", panelImport.frame, "TOPLEFT")
yellowfive@69 93 _panelCover:SetPoint("BOTTOMRIGHT", panelImport.frame, "BOTTOMRIGHT")
yellowfive@69 94
yellowfive@69 95 local coverMsg = AceGUI:Create("AmrUiLabel")
yellowfive@124 96 _panelCover:AddChild(coverMsg)
yellowfive@69 97 coverMsg:SetWidth(500)
yellowfive@69 98 coverMsg:SetFont(Amr.CreateFont("Regular", 16, Amr.Colors.TextTan))
yellowfive@69 99 coverMsg:SetJustifyH("MIDDLE")
yellowfive@69 100 coverMsg:SetJustifyV("MIDDLE")
yellowfive@69 101 coverMsg:SetText(L.ImportOverwolfWait)
yellowfive@69 102 coverMsg:SetPoint("CENTER", _panelCover.frame, "CENTER", 0, 20)
yellowfive@69 103
yellowfive@69 104 -- after adding, set cover to sit on top of everything
yellowfive@69 105 _panelCover:SetStrata("FULLSCREEN_DIALOG")
yellowfive@69 106 _panelCover:SetLevel(Amr.FrameLevels.Highest)
yellowfive@69 107 end
yellowfive@57 108 end
yellowfive@57 109
yellowfive@69 110 function Amr:ShowImportWindow(fromOverwolf)
yellowfive@57 111 -- this is shown as a modal dialog
yellowfive@69 112 Amr:ShowCover(function(container)
yellowfive@69 113 renderImportWindow(container, fromOverwolf)
yellowfive@69 114 end)
yellowfive@57 115
yellowfive@57 116 _txtImport:SetText("")
yellowfive@57 117 _txtImport:SetFocus(true)
yellowfive@57 118 end
yellowfive@57 119
yellowfive@57 120 ----------------------------------------------------------------------------
yellowfive@57 121 -- Import Parsing
yellowfive@57 122 ----------------------------------------------------------------------------
yellowfive@57 123
yellowfive@57 124 --
yellowfive@57 125 -- Import a character, returning nil on success, otherwise an error message, import result stored in the db.
yellowfive@57 126 --
yellowfive@139 127 function Amr:ImportCharacter(data, isTest, isChild)
yellowfive@57 128
yellowfive@57 129 -- make sure all data is up to date before importing and get a local copy of player's current state
yellowfive@57 130 local currentPlayerData = self:ExportCharacter()
yellowfive@57 131
yellowfive@57 132 if data == nil or string.len(data) == 0 then
yellowfive@57 133 return L.ImportErrorEmpty
yellowfive@57 134 end
yellowfive@57 135
yellowfive@139 136 -- if multiple setups are included in the data, parse each individually, then quit
yellowfive@57 137 local specParts = { strsplit("\n", data) }
yellowfive@139 138 if #specParts > 1 then
yellowfive@139 139 -- clear out any previously-imported BiB setups when importing new ones (non-BiB will always be imported one at a time)
yellowfive@139 140 for i = #Amr.db.char.GearSetups, 1, -1 do
yellowfive@139 141 if Amr.db.char.GearSetups[i].IsBib then
yellowfive@139 142 table.remove(Amr.db.char.GearSetups, i)
yellowfive@139 143 end
yellowfive@139 144 end
yellowfive@139 145
yellowfive@141 146 for i = 1, #specParts do
yellowfive@141 147 if specParts[i] ~= "_bib_" then
yellowfive@141 148 local err = self:ImportCharacter(specParts[i], isTest, true)
yellowfive@141 149 if err ~= nil then
yellowfive@141 150 return err
yellowfive@141 151 end
yellowfive@141 152 end
yellowfive@139 153 end
yellowfive@139 154
yellowfive@139 155 -- ensure that all BiB setups are sorted to the top
yellowfive@139 156 local nonBib = {}
yellowfive@139 157 for i = #Amr.db.char.GearSetups, 1, -1 do
yellowfive@139 158 if not Amr.db.char.GearSetups[i].IsBib then
yellowfive@139 159 table.insert(nonBib, Amr.db.char.GearSetups[i])
yellowfive@139 160 table.remove(Amr.db.char.GearSetups, i)
yellowfive@139 161 end
yellowfive@139 162 end
yellowfive@139 163 for i, setup in ipairs(nonBib) do
yellowfive@139 164 table.insert(Amr.db.char.GearSetups, setup)
yellowfive@139 165 end
yellowfive@139 166
yellowfive@139 167 return
yellowfive@57 168 end
yellowfive@57 169
yellowfive@57 170 local data1 = { strsplit("$", data) }
yellowfive@57 171 if #data1 ~= 3 then
yellowfive@57 172 return L.ImportErrorFormat
yellowfive@57 173 end
yellowfive@57 174
yellowfive@57 175 local parts = { strsplit(";", data1[2]) }
yellowfive@57 176
yellowfive@57 177 -- require a minimum version
yellowfive@57 178 local ver = tonumber(parts[1])
yellowfive@57 179 if ver < Amr.MIN_IMPORT_VERSION then
yellowfive@57 180 return L.ImportErrorVersion
yellowfive@57 181 end
yellowfive@57 182
yellowfive@57 183 -- require name match (don't match realm due to language issues for now)
yellowfive@57 184 if not isTest then
yellowfive@57 185 local region = parts[2]
yellowfive@57 186 local realm = parts[3]
yellowfive@57 187 local name = parts[4]
yellowfive@57 188 if name ~= currentPlayerData.Name then
yellowfive@57 189 local importPlayerName = name .. " (" .. realm .. ")"
yellowfive@57 190 local you = currentPlayerData.Name .. " (" .. currentPlayerData.Realm .. ")"
yellowfive@57 191 return L.ImportErrorChar(importPlayerName, you)
yellowfive@57 192 end
yellowfive@57 193
yellowfive@57 194 -- require race match
yellowfive@57 195 local race = tonumber(parts[6])
yellowfive@57 196 if race ~= Amr.RaceIds[currentPlayerData.Race] then
yellowfive@57 197 return L.ImportErrorRace
yellowfive@57 198 end
yellowfive@57 199
yellowfive@57 200 -- require faction match
yellowfive@57 201 local faction = tonumber(parts[7])
yellowfive@57 202 if faction ~= Amr.FactionIds[currentPlayerData.Faction] then
yellowfive@57 203 return L.ImportErrorFaction
yellowfive@57 204 end
yellowfive@57 205
yellowfive@57 206 -- require level match
yellowfive@57 207 local level = tonumber(parts[8])
yellowfive@57 208 if level ~= currentPlayerData.Level then
yellowfive@57 209 return L.ImportErrorLevel
yellowfive@57 210 end
yellowfive@57 211 end
yellowfive@57 212
yellowfive@57 213 -- if we make it this far, the data is valid, so read item information
yellowfive@124 214 local specSlot = tonumber(parts[11])
yellowfive@57 215
yellowfive@57 216 local importData = {}
yellowfive@57 217 local enchantInfo = {}
yellowfive@57 218
yellowfive@57 219 local prevItemId = 0
yellowfive@57 220 local prevGemId = 0
yellowfive@57 221 local prevEnchantId = 0
yellowfive@57 222 local prevUpgradeId = 0
yellowfive@57 223 local prevBonusId = 0
yellowfive@124 224 local prevLevel = 0
yellowfive@124 225 local prevAzeriteId = 0
yellowfive@57 226 local digits = {
yellowfive@57 227 ["-"] = true,
yellowfive@57 228 ["0"] = true,
yellowfive@57 229 ["1"] = true,
yellowfive@57 230 ["2"] = true,
yellowfive@57 231 ["3"] = true,
yellowfive@57 232 ["4"] = true,
yellowfive@57 233 ["5"] = true,
yellowfive@57 234 ["6"] = true,
yellowfive@57 235 ["7"] = true,
yellowfive@57 236 ["8"] = true,
yellowfive@57 237 ["9"] = true,
yellowfive@57 238 }
yellowfive@124 239 for i = 16, #parts do
yellowfive@57 240 local itemString = parts[i]
yellowfive@57 241 if itemString ~= "" and itemString ~= "_" then
yellowfive@57 242 local tokens = {}
yellowfive@57 243 local bonusIds = {}
yellowfive@124 244 local azerite = {}
yellowfive@57 245 local hasBonuses = false
yellowfive@124 246 local hasAzerites = false
yellowfive@57 247 local token = ""
yellowfive@57 248 local prop = "i"
yellowfive@57 249 local tokenComplete = false
yellowfive@57 250 for j = 1, string.len(itemString) do
yellowfive@57 251 local c = string.sub(itemString, j, j)
yellowfive@57 252 if digits[c] == nil then
yellowfive@57 253 tokenComplete = true
yellowfive@57 254 else
yellowfive@57 255 token = token .. c
yellowfive@57 256 end
yellowfive@57 257
yellowfive@57 258 if tokenComplete or j == string.len(itemString) then
yellowfive@57 259 local val = tonumber(token)
yellowfive@57 260 if prop == "i" then
yellowfive@57 261 val = val + prevItemId
yellowfive@57 262 prevItemId = val
yellowfive@57 263 elseif prop == "u" then
yellowfive@57 264 val = val + prevUpgradeId
yellowfive@57 265 prevUpgradeId = val
yellowfive@81 266 elseif prop == "v" then
yellowfive@81 267 val = val + prevLevel
yellowfive@81 268 prevLevel = val
yellowfive@57 269 elseif prop == "b" then
yellowfive@57 270 val = val + prevBonusId
yellowfive@57 271 prevBonusId = val
yellowfive@57 272 elseif prop == "x" or prop == "y" or prop == "z" then
yellowfive@57 273 val = val + prevGemId
yellowfive@57 274 prevGemId = val
yellowfive@57 275 elseif prop == "e" then
yellowfive@57 276 val = val + prevEnchantId
yellowfive@57 277 prevEnchantId = val
yellowfive@124 278 elseif prop == "a" then
yellowfive@124 279 val = val + prevAzeriteId
yellowfive@124 280 prevAzeriteId = val
yellowfive@57 281 end
yellowfive@57 282
yellowfive@57 283 if prop == "b" then
yellowfive@57 284 table.insert(bonusIds, val)
yellowfive@57 285 hasBonuses = true
yellowfive@124 286 elseif prop == "a" then
yellowfive@124 287 table.insert(azerite, val)
yellowfive@124 288 hasAzerites = true
yellowfive@57 289 else
yellowfive@57 290 tokens[prop] = val
yellowfive@57 291 end
yellowfive@57 292
yellowfive@57 293 token = ""
yellowfive@57 294 tokenComplete = false
yellowfive@57 295
yellowfive@57 296 -- we have moved on to the next token
yellowfive@57 297 prop = c
yellowfive@57 298 end
yellowfive@57 299 end
yellowfive@57 300
yellowfive@57 301 local obj = {}
yellowfive@57 302 importData[tonumber(tokens["s"])] = obj
yellowfive@57 303
yellowfive@57 304 obj.id = tokens["i"]
yellowfive@57 305 obj.suffixId = tokens["f"] or 0
yellowfive@57 306 obj.upgradeId = tokens["u"] or 0
yellowfive@81 307 obj.level = tokens["v"] or 0
yellowfive@57 308 obj.enchantId = tokens["e"] or 0
yellowfive@89 309 obj.inventoryId = tokens["t"] or 0
yellowfive@57 310
yellowfive@57 311 obj.gemIds = {}
yellowfive@57 312 table.insert(obj.gemIds, tokens["x"] or 0)
yellowfive@57 313 table.insert(obj.gemIds, tokens["y"] or 0)
yellowfive@57 314 table.insert(obj.gemIds, tokens["z"] or 0)
yellowfive@57 315 table.insert(obj.gemIds, 0)
yellowfive@57 316
yellowfive@57 317 if hasBonuses then
yellowfive@57 318 obj.bonusIds = bonusIds
yellowfive@57 319 end
yellowfive@57 320
yellowfive@124 321 if hasAzerites then
yellowfive@124 322 obj.azerite = azerite
yellowfive@57 323 end
yellowfive@57 324 end
yellowfive@57 325 end
yellowfive@57 326
yellowfive@139 327 -- extra information contains setup id, display label, then extra enchant info
yellowfive@57 328 parts = { strsplit("@", data1[3]) }
yellowfive@139 329
yellowfive@139 330 local setupId = parts[2]
yellowfive@139 331 local setupName = parts[3]
yellowfive@139 332
yellowfive@139 333 for i = 4, #parts do
yellowfive@57 334 local infoParts = { strsplit("\\", parts[i]) }
yellowfive@57 335
yellowfive@124 336 if infoParts[1] == "e" then
yellowfive@57 337
yellowfive@57 338 local enchObj = {}
yellowfive@57 339 enchObj.id = tonumber(infoParts[2])
yellowfive@57 340 enchObj.itemId = tonumber(infoParts[3])
yellowfive@57 341 enchObj.spellId = tonumber(infoParts[4])
yellowfive@57 342 enchObj.text = string.gsub(infoParts[5], "_(%a+)_", function(s) return L.StatsShort[s] end)
yellowfive@57 343
yellowfive@57 344 local mats = infoParts[6]
yellowfive@57 345 if string.len(mats) > 0 then
yellowfive@57 346 enchObj.materials = {}
yellowfive@57 347 mats = { strsplit(",", mats) }
yellowfive@57 348 for j = 1, #mats do
yellowfive@57 349 local kv = { strsplit("=", mats[j]) }
yellowfive@57 350 enchObj.materials[tonumber(kv[1])] = tonumber(kv[2])
yellowfive@57 351 end
yellowfive@57 352 end
yellowfive@57 353
yellowfive@124 354 enchantInfo[enchObj.id] = enchObj
yellowfive@57 355 end
yellowfive@57 356 end
yellowfive@57 357
yellowfive@57 358 if isTest then
yellowfive@57 359 print("spec " .. specSlot)
yellowfive@57 360 -- print result for debugging
yellowfive@57 361 for k,v in pairs(importData) do
yellowfive@57 362 local blah = Amr.CreateItemLink(v)
yellowfive@57 363 --print(blah)
yellowfive@57 364 local name, link = GetItemInfo(blah)
yellowfive@57 365 print(link)
yellowfive@57 366 if link == nil then
yellowfive@57 367 print(blah)
yellowfive@57 368 print("bad item: " .. v.id)
yellowfive@57 369 end
yellowfive@133 370 end
yellowfive@57 371 else
yellowfive@57 372 -- we have succeeded, record the result
yellowfive@139 373 local result = {
yellowfive@139 374 IsBib = string.sub(setupId, 1, 3) ~= "AMR",
yellowfive@139 375 SpecSlot = tonumber(specSlot),
yellowfive@139 376 Id = setupId,
yellowfive@139 377 Label = setupName,
yellowfive@139 378 Gear = importData
yellowfive@139 379 }
yellowfive@139 380
yellowfive@139 381 if not result.IsBib then
yellowfive@139 382 -- replace if this setup already exists
yellowfive@139 383 local key = -1
yellowfive@139 384 for i,setup in ipairs(Amr.db.char.GearSetups) do
yellowfive@139 385 if setup.Id == result.Id then
yellowfive@139 386 key = i
yellowfive@139 387 break
yellowfive@139 388 end
yellowfive@139 389 end
yellowfive@139 390
yellowfive@139 391 if key ~= -1 then
yellowfive@139 392 Amr.db.char.GearSetups[key] = result
yellowfive@139 393 else
yellowfive@139 394 table.insert(Amr.db.char.GearSetups, result)
yellowfive@139 395 end
yellowfive@139 396
yellowfive@139 397 if not isChild then
yellowfive@139 398 -- if doing a single import of a setup, make it active
yellowfive@139 399 Amr:SetActiveSetupId(setupId)
yellowfive@139 400 end
yellowfive@139 401 else
yellowfive@139 402 table.insert(Amr.db.char.GearSetups, result)
yellowfive@139 403 end
yellowfive@124 404
yellowfive@124 405 for k,v in pairs(enchantInfo) do
yellowfive@124 406 Amr.db.char.ExtraEnchantData[k] = v
yellowfive@124 407 end
yellowfive@57 408
yellowfive@57 409 -- also update shopping list after import
yellowfive@57 410 Amr:UpdateShoppingData(currentPlayerData)
yellowfive@57 411 end
yellowfive@57 412 end