├── README.md
├── Media
├── Images
│ ├── edit.blp
│ ├── kofi.blp
│ ├── pin.tga
│ ├── true.blp
│ ├── false.blp
│ ├── paypal.blp
│ ├── upArrow.blp
│ ├── craftsim.tga
│ ├── downArrow.blp
│ ├── pixelHeart.blp
│ ├── expectedValue.blp
│ └── hsvVisualization.blp
├── Fonts
│ ├── Roboto-Regular.ttf
│ └── SpaceMono-Regular.ttf
└── Media.lua
├── Modules
├── SpecializationInfo
│ └── SpecializationInfo.lua
├── CostOptimization
│ └── CostOptimization.lua
├── Explanations
│ ├── Explanations.lua
│ └── UI.lua
├── PriceDetails
│ └── PriceDetails.lua
├── Cooldowns
│ └── Cooldowns.lua
├── PriceOverride
│ └── PriceOverride.lua
├── Statistics
│ └── Statistics.lua
├── ItemCount
│ └── ItemCount.lua
├── ConcentrationTracker
│ └── ConcentrationTracker.lua
├── AverageProfit
│ └── AverageProfit.lua
├── Supporters
│ └── UI.lua
└── Debug
│ └── Debug.lua
├── DevTools
└── DataScripts
│ ├── ConcentrationCurveData
│ ├── readme.txt
│ └── mapper.py
│ ├── SpecializationData
│ ├── wow_profession_tree.db
│ └── update.sh
│ ├── updateAll.py
│ ├── ReagentWeightData
│ ├── readme.txt
│ └── mapper.py
│ ├── EnchantData
│ └── mapper.py
│ └── wagoTools.py
├── .gitignore
├── Libs
├── AceDB-3.0
│ └── AceDB-3.0.xml
├── LibCompress
│ ├── lib.xml
│ ├── LibStub
│ │ ├── LibStub.toc
│ │ ├── tests
│ │ │ ├── test3.lua
│ │ │ ├── test4.lua
│ │ │ ├── test2.lua
│ │ │ └── test.lua
│ │ └── LibStub.lua
│ ├── CHANGES.txt
│ └── LibCompress.toc
├── AceAddon-3.0
│ └── AceAddon-3.0.xml
├── AceEvent-3.0
│ ├── AceEvent-3.0.xml
│ └── AceEvent-3.0.lua
├── AceSerializer-3.0
│ └── AceSerializer-3.0.xml
├── CallbackHandler-1.0
│ └── CallbackHandler-1.0.xml
├── LibDBIcon-1.0
│ ├── LibDBIcon-1.0
│ │ └── lib.xml
│ ├── embeds.xml
│ ├── LibDBIcon-1.0.toc
│ ├── LibStub
│ │ └── LibStub.lua
│ └── LibDataBroker-1.1
│ │ └── LibDataBroker-1.1.lua
├── AceComm-3.0
│ └── AceComm-3.0.xml
├── LibStub
│ ├── LibStub.toc
│ ├── Changelog-LibStub-1.0.2-70000.txt
│ ├── tests
│ │ ├── test3.lua
│ │ ├── test4.lua
│ │ ├── test2.lua
│ │ └── test.lua
│ └── LibStub.lua
└── classic.lua
├── Init
└── GLibs.lua
├── .github
├── workflows
│ ├── new-issue.yml
│ └── release.yml
├── ISSUE_TEMPLATE
│ ├── bug_report.md
│ └── feature_request.md
└── FUNDING.yml
├── .gitmodules
├── Classes
├── ReagentListItem.lua
├── CraftSimObject.lua
├── Statweights.lua
├── CraftResultItem.lua
├── TopGearResult.lua
├── CraftResultReagent.lua
├── OnCraftData.lua
├── ProfessionData.lua
├── SalvageReagentSlot.lua
├── CraftSessionData.lua
├── JSONBuilder.lua
├── OptionalReagent.lua
├── ProfessionStat.lua
├── Buff.lua
├── ConcentrationData.lua
├── ReagentOptimizationResult.lua
├── PerkData.lua
└── ReagentItem.lua
├── Util
├── API.lua
├── Widgets.lua
├── Comm.lua
└── API_README.md
├── embeds.xml
├── Locals
├── koKR.lua
├── esES.lua
├── esMX.lua
└── Localization.lua
├── LICENSE
├── .pkgmeta
├── DB
├── multicraftPreloadDB.lua
├── craftQueueDB.lua
├── DB.lua
├── recipeSubCrafterDB.lua
├── itemRecipeDB.lua
├── customerHistoryDB.lua
├── itemOptimizedCostsDB.lua
└── ItemCountDB.lua
├── CraftSim.toc
└── Data
└── SpecializationData
└── SpecializationData.lua
/README.md:
--------------------------------------------------------------------------------
1 | https://www.curseforge.com/wow/addons/craftsim
--------------------------------------------------------------------------------
/Media/Images/edit.blp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/derfloh205/CraftSim/HEAD/Media/Images/edit.blp
--------------------------------------------------------------------------------
/Media/Images/kofi.blp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/derfloh205/CraftSim/HEAD/Media/Images/kofi.blp
--------------------------------------------------------------------------------
/Media/Images/pin.tga:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/derfloh205/CraftSim/HEAD/Media/Images/pin.tga
--------------------------------------------------------------------------------
/Media/Images/true.blp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/derfloh205/CraftSim/HEAD/Media/Images/true.blp
--------------------------------------------------------------------------------
/Media/Images/false.blp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/derfloh205/CraftSim/HEAD/Media/Images/false.blp
--------------------------------------------------------------------------------
/Media/Images/paypal.blp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/derfloh205/CraftSim/HEAD/Media/Images/paypal.blp
--------------------------------------------------------------------------------
/Media/Images/upArrow.blp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/derfloh205/CraftSim/HEAD/Media/Images/upArrow.blp
--------------------------------------------------------------------------------
/Media/Images/craftsim.tga:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/derfloh205/CraftSim/HEAD/Media/Images/craftsim.tga
--------------------------------------------------------------------------------
/Media/Images/downArrow.blp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/derfloh205/CraftSim/HEAD/Media/Images/downArrow.blp
--------------------------------------------------------------------------------
/Media/Images/pixelHeart.blp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/derfloh205/CraftSim/HEAD/Media/Images/pixelHeart.blp
--------------------------------------------------------------------------------
/Media/Fonts/Roboto-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/derfloh205/CraftSim/HEAD/Media/Fonts/Roboto-Regular.ttf
--------------------------------------------------------------------------------
/Media/Images/expectedValue.blp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/derfloh205/CraftSim/HEAD/Media/Images/expectedValue.blp
--------------------------------------------------------------------------------
/Media/Fonts/SpaceMono-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/derfloh205/CraftSim/HEAD/Media/Fonts/SpaceMono-Regular.ttf
--------------------------------------------------------------------------------
/Media/Images/hsvVisualization.blp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/derfloh205/CraftSim/HEAD/Media/Images/hsvVisualization.blp
--------------------------------------------------------------------------------
/Modules/SpecializationInfo/SpecializationInfo.lua:
--------------------------------------------------------------------------------
1 | ---@class CraftSim
2 | local CraftSim = select(2, ...)
3 |
4 | CraftSim.SPECIALIZATION_INFO = {}
5 |
--------------------------------------------------------------------------------
/DevTools/DataScripts/ConcentrationCurveData/readme.txt:
--------------------------------------------------------------------------------
1 | Currently the 11.0.0 data is used for retail prepatch
2 | switch to newest build (autodownload) on tww release
--------------------------------------------------------------------------------
/DevTools/DataScripts/SpecializationData/wow_profession_tree.db:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/derfloh205/CraftSim/HEAD/DevTools/DataScripts/SpecializationData/wow_profession_tree.db
--------------------------------------------------------------------------------
/Modules/CostOptimization/CostOptimization.lua:
--------------------------------------------------------------------------------
1 | ---@class CraftSim
2 | local CraftSim = select(2, ...)
3 |
4 | ---@class CraftSim.COST_OPTIMIZATION
5 | CraftSim.COST_OPTIMIZATION = {}
6 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .vscode
2 | .release/
3 | Libs/
4 | !Libs/classic.lua
5 | DevTools/DataScripts/__pycache__
6 | DevTools/DataScripts/**/Result/
7 | DevTools/DataScripts/**/Data/
8 | DevTools/DataScripts/**.db
9 | !**/*.py
10 |
--------------------------------------------------------------------------------
/Modules/Explanations/Explanations.lua:
--------------------------------------------------------------------------------
1 | ---@class CraftSim
2 | local CraftSim = select(2, ...)
3 |
4 | ---@class CraftSim.EXPLANATIONS
5 | CraftSim.EXPLANATIONS = {}
6 |
7 | ---@type GGUI.Frame
8 | CraftSim.EXPLANATIONS.frame = nil
9 |
--------------------------------------------------------------------------------
/Libs/AceDB-3.0/AceDB-3.0.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/Libs/LibCompress/lib.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/Libs/AceAddon-3.0/AceAddon-3.0.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/Libs/AceEvent-3.0/AceEvent-3.0.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/Libs/AceSerializer-3.0/AceSerializer-3.0.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/Libs/CallbackHandler-1.0/CallbackHandler-1.0.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/Libs/LibDBIcon-1.0/LibDBIcon-1.0/lib.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Libs/AceComm-3.0/AceComm-3.0.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/DevTools/DataScripts/SpecializationData/update.sh:
--------------------------------------------------------------------------------
1 | cd wow-profession-tree
2 | python generate_database.py
3 | cd profession_traits
4 | python get_csv_output.py
5 | cd ../..
6 | rm Data/Latest/csv_profession_traits.csv
7 | mv wow-profession-tree/output/csv_profession_traits.csv Data/Latest/csv_profession_traits.csv
8 | python mapper.py
--------------------------------------------------------------------------------
/Init/GLibs.lua:
--------------------------------------------------------------------------------
1 | ---@class CraftSim
2 | local CraftSim = select(2, ...)
3 |
4 | ---@type GGUI-2.1
5 | CraftSim.GGUI = LibStub:GetLibrary("GGUI-2.1")
6 |
7 | ---@type GUTIL-2.0
8 | CraftSim.GUTIL = LibStub:GetLibrary("GUTIL-2.0")
9 |
10 | ---@type LibGraph-2.0
11 | CraftSim.LibGraph = LibStub:GetLibrary("LibGraph-2.0")
12 |
--------------------------------------------------------------------------------
/Libs/LibCompress/LibStub/LibStub.toc:
--------------------------------------------------------------------------------
1 | ## Interface: 80000
2 | ## Title: Lib: LibStub
3 | ## Notes: Universal Library Stub
4 | ## Credits: Kaelten, Cladhaire, ckknight, Mikk, Ammo, Nevcairiel
5 | ## X-Website: http://www.wowace.com/addons/libstub/
6 | ## X-Category: Library
7 | ## X-License: Public Domain
8 |
9 | LibStub.lua
10 |
--------------------------------------------------------------------------------
/.github/workflows/new-issue.yml:
--------------------------------------------------------------------------------
1 | name: New Issue
2 | on:
3 | issues:
4 | types: [opened]
5 | jobs:
6 | add-to-project:
7 | runs-on: ubuntu-latest
8 | steps:
9 | - uses: actions/add-to-project@v1.0.2
10 | with:
11 | project-url: https://github.com/users/derfloh205/projects/4
12 | github-token: ${{ secrets.REPO_PROJECT }}
13 |
--------------------------------------------------------------------------------
/Libs/LibDBIcon-1.0/embeds.xml:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "Libs/GGUI"]
2 | path = Libs/GGUI
3 | url = https://github.com/derfloh205/GGUI.git
4 | [submodule "Libs/GUTIL"]
5 | path = Libs/GUTIL
6 | url = https://github.com/derfloh205/GUTIL.git
7 | [submodule "DevTools/DataScripts/SpecializationData/wow-profession-tree"]
8 | path = DevTools/DataScripts/SpecializationData/wow-profession-tree
9 | url = https://github.com/mr120/wow-profession-tree
10 |
--------------------------------------------------------------------------------
/Classes/ReagentListItem.lua:
--------------------------------------------------------------------------------
1 | ---@class CraftSim
2 | local CraftSim = select(2, ...)
3 |
4 | ---@class CraftSim.ReagentListItem : CraftSim.CraftSimObject
5 | CraftSim.ReagentListItem = CraftSim.CraftSimObject:extend()
6 |
7 | ---@param itemID number
8 | ---@param quantity number
9 | function CraftSim.ReagentListItem:new(itemID, quantity)
10 | self.itemID = itemID
11 | self.quantity = quantity
12 | end
13 |
--------------------------------------------------------------------------------
/Libs/LibCompress/CHANGES.txt:
--------------------------------------------------------------------------------
1 | ------------------------------------------------------------------------
2 | r85 | galmok@gmail.com | 2021-02-27 07:30:34 +0000 (Sat, 27 Feb 2021) | 2 lines
3 | Changed paths:
4 | M /trunk/LibCompress.toc
5 |
6 | Updated TOC to recent game version. Library seems fully compatible without change.
7 |
8 | ------------------------------------------------------------------------
9 |
10 |
--------------------------------------------------------------------------------
/Libs/LibDBIcon-1.0/LibDBIcon-1.0.toc:
--------------------------------------------------------------------------------
1 | ## Interface: 100107
2 | ## Version: v10.1.6
3 | ## LoadOnDemand: 1
4 | ## Title: Lib: DataBrokerIcon-1.0
5 | ## Notes: Allows addons to easily create a lightweight minimap icon as an alternative to heavier LDB displays.
6 | ## Author: Funkydude
7 | ## X-Category: Library
8 | ## X-License: All Rights Reserved
9 | ## X-Credits: Rabbit, copystring
10 |
11 | embeds.xml
12 | LibDBIcon-1.0\lib.xml
13 |
14 |
--------------------------------------------------------------------------------
/Modules/PriceDetails/PriceDetails.lua:
--------------------------------------------------------------------------------
1 | ---@class CraftSim
2 | local CraftSim = select(2, ...)
3 |
4 | CraftSim.PRICE_DETAILS = {}
5 |
6 | local print = CraftSim.DEBUG:RegisterDebugID("Modules.PriceDetails")
7 |
8 | ---@param recipeData CraftSim.RecipeData
9 | ---@param exportMode number
10 | function CraftSim.PRICE_DETAILS:UpdateDisplay(recipeData, exportMode)
11 | CraftSim.PRICE_DETAILS.UI:UpdateDisplay(recipeData, exportMode)
12 | end
13 |
--------------------------------------------------------------------------------
/Libs/LibCompress/LibCompress.toc:
--------------------------------------------------------------------------------
1 | ## Interface: 90002
2 |
3 | ## Title: Lib: Compress
4 | ## Notes: Compression and Decompression library
5 | ## Author: Galmok at Stormrage-EU (Horde) and JJSheets
6 | ## Version: r86-release
7 | ## X-Website: http://www.wowace.com/addons/libcompress/
8 | ## X-Category: Library
9 | ## X-eMail: galmok AT gmail DOT com, sheets DOT jeff AT gmail DOT com
10 | ## X-License: GPL v2
11 | ## LoadOnDemand: 1
12 |
13 | LibStub\LibStub.lua
14 | lib.xml
15 |
--------------------------------------------------------------------------------
/Libs/LibStub/LibStub.toc:
--------------------------------------------------------------------------------
1 | ## Interface: 70000
2 | ## Title: Lib: LibStub
3 | ## Notes: Universal Library Stub
4 | ## Credits: Kaelten, Cladhaire, ckknight, Mikk, Ammo, Nevcairiel
5 | ## X-Website: http://www.wowace.com/addons/libstub/
6 | ## X-Category: Library
7 | ## X-License: Public Domain
8 | ## X-Curse-Packaged-Version: 1.0.2-70000
9 | ## X-Curse-Project-Name: LibStub
10 | ## X-Curse-Project-ID: libstub
11 | ## X-Curse-Repository-ID: wow/libstub/mainline
12 |
13 | LibStub.lua
14 |
--------------------------------------------------------------------------------
/Classes/CraftSimObject.lua:
--------------------------------------------------------------------------------
1 | ---@class CraftSim
2 | local CraftSim = select(2, ...)
3 |
4 | --- Base Class for CraftSim Classes
5 | ---@class CraftSim.CraftSimObject : CraftSim.Object
6 | CraftSim.CraftSimObject = CraftSim.Object:extend()
7 |
8 | function CraftSim.CraftSimObject:new()
9 | end
10 |
11 | --- Adds the object to DevTool if DevTool is loaded
12 | ---@param label string
13 | function CraftSim.CraftSimObject:DebugInspect(label)
14 | if DevTool then
15 | DevTool:AddData(self, label)
16 | end
17 | end
18 |
--------------------------------------------------------------------------------
/DevTools/DataScripts/updateAll.py:
--------------------------------------------------------------------------------
1 | import os
2 | import sys
3 | import shutil
4 | import importlib
5 |
6 | dataScripts = ["ConcentrationCurveData", "EnchantData", "OptionalReagentData", "ReagentWeightData"] ## SpecializationData is a special case (manually)
7 |
8 | if __name__ == '__main__':
9 | args = sys.argv[1:]
10 | buildVersion = len(args) > 0 and args[0]
11 |
12 | for folderName in dataScripts:
13 | print("Updating data script: " + folderName)
14 | os.chdir(folderName)
15 | exec(open('mapper.py').read())
16 | os.chdir("..")
--------------------------------------------------------------------------------
/Libs/LibStub/Changelog-LibStub-1.0.2-70000.txt:
--------------------------------------------------------------------------------
1 | ------------------------------------------------------------------------
2 | r106 | kaelten | 2016-08-18 04:06:06 +0000 (Thu, 18 Aug 2016) | 1 line
3 | Changed paths:
4 | A /tags/1.0.2-70000 (from /trunk:105)
5 |
6 | Tagging as 1.0.2-70000
7 | ------------------------------------------------------------------------
8 | r105 | kaelten | 2016-08-18 04:00:27 +0000 (Thu, 18 Aug 2016) | 2 lines
9 | Changed paths:
10 | M /trunk/LibStub.toc
11 |
12 | Updating ToC for Legion.
13 |
14 | ------------------------------------------------------------------------
15 |
--------------------------------------------------------------------------------
/Classes/Statweights.lua:
--------------------------------------------------------------------------------
1 | ---@class CraftSim
2 | local CraftSim = select(2, ...)
3 |
4 | ---@class CraftSim.Statweights : CraftSim.CraftSimObject
5 | CraftSim.Statweights = CraftSim.CraftSimObject:extend()
6 |
7 | ---@param averageProfit number
8 | ---@param multicraftWeight number
9 | ---@param resourcefulnessWeight number
10 | ---@param concentrationWeight number
11 | function CraftSim.Statweights:new(averageProfit, multicraftWeight, resourcefulnessWeight, concentrationWeight)
12 | self.averageProfit = averageProfit
13 | self.multicraftWeight = multicraftWeight
14 | self.resourcefulnessWeight = resourcefulnessWeight
15 | self.concentrationWeight = concentrationWeight
16 | end
17 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: "[] "
5 | labels: bug
6 | assignees: derfloh205
7 |
8 | ---
9 |
10 | **Describe the bug**
11 | A clear and concise description of what the bug is.
12 |
13 | **To Reproduce**
14 | Steps to reproduce the behavior:
15 | 1. Go to '...'
16 | 2. Click on '....'
17 | 3. Scroll down to '....'
18 | 4. See error
19 |
20 | **Expected behavior**
21 | A clear and concise description of what you expected to happen.
22 |
23 | **Screenshots**
24 | If applicable, add screenshots to help explain your problem.
25 |
26 | **Addon Version:** [e.g. 19.7.1]
27 |
28 | **Additional context**
29 | Add any other context about the problem here.
30 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: "[] "
5 | labels: enhancement
6 | assignees: derfloh205
7 |
8 | ---
9 |
10 | **Is your feature request related to a problem? Please describe.**
11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
12 |
13 | **Describe the solution you'd like**
14 | A clear and concise description of what you want to happen.
15 |
16 | **Describe alternatives you've considered**
17 | A clear and concise description of any alternative solutions or features you've considered.
18 |
19 | **Additional context**
20 | Add any other context or screenshots about the feature request here.
21 |
--------------------------------------------------------------------------------
/DevTools/DataScripts/ReagentWeightData/readme.txt:
--------------------------------------------------------------------------------
1 | necessary tables as csv from wago.tools:
2 | - ModifiedCraftingReagentItem -> Maps ModifiedCraftingReagentItemID to ModifiedCraftingCategoryID
3 | - ModifiedCraftingCategory -> Maps ModifiedCraftingCategoryID to MatQualityWeight
4 | - Item -> ClassID 7 = TradeSkillReagents, Maps ItemID to ModifiedCraftingReagentItemID, everything with id not 0 is relevant
5 |
6 | Mapping Process
7 |
8 | For each TradeSkillReagent Item in Item with ClassID 7 and ModifiedCraftingReagentItemID not 0 and CraftingQualityID not 0:
9 | fetch the ModifiedCraftingCategoryID from ModifiedCraftingReagentItem by ModifiedCraftingReagentItemID
10 | fetch the MatQualityWeight from ModifiedCraftingCategory by ModifiedCraftingCategoryID
11 |
12 |
--------------------------------------------------------------------------------
/Util/API.lua:
--------------------------------------------------------------------------------
1 | ---@class CraftSim
2 | local CraftSim = select(2, ...)
3 |
4 | CraftSimAPI = {}
5 |
6 | ---Fetch a CraftSim.RecipeData instance for a recipe
7 | ---@param options CraftSim.RecipeData.ConstructorOptions
8 | ---@return CraftSim.RecipeData recipeData
9 | function CraftSimAPI:GetRecipeData(options)
10 | return CraftSim.RecipeData(options)
11 | end
12 |
13 | ---Fetch the currently open CraftSim.RecipeData instance (or the last one opened if profession window was closed)
14 | ---@return CraftSim.RecipeData | nil
15 | function CraftSimAPI:GetOpenRecipeData()
16 | return CraftSim.INIT.currentRecipeData
17 | end
18 |
19 | ---Get the whole CraftSim addon table for whatever reason. Have Fun!
20 | function CraftSimAPI:GetCraftSim()
21 | return CraftSim
22 | end
23 |
--------------------------------------------------------------------------------
/embeds.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/Libs/LibStub/tests/test3.lua:
--------------------------------------------------------------------------------
1 | debugstack = debug.traceback
2 | strmatch = string.match
3 |
4 | loadfile("../LibStub.lua")()
5 |
6 | local proxy = newproxy() -- non-string
7 |
8 | assert(not pcall(LibStub.NewLibrary, LibStub, proxy, 1)) -- should error, proxy is not a string, it's userdata
9 | local success, ret = pcall(LibStub.GetLibrary, proxy, true)
10 | assert(not success or not ret) -- either error because proxy is not a string or because it's not actually registered.
11 |
12 | assert(not pcall(LibStub.NewLibrary, LibStub, "Something", "No number in here")) -- should error, minor has no string in it.
13 |
14 | assert(not LibStub:GetLibrary("Something", true)) -- shouldn't've created it from the above statement
15 |
--------------------------------------------------------------------------------
/Locals/koKR.lua:
--------------------------------------------------------------------------------
1 | ---@class CraftSim
2 | local CraftSim = select(2, ...)
3 |
4 | CraftSim.LOCAL_KO = {}
5 |
6 | function CraftSim.LOCAL_KO:GetData()
7 | local f = CraftSim.GUTIL:GetFormatter()
8 | return {
9 | -- REQUIRED:
10 | [CraftSim.CONST.TEXT.STAT_MULTICRAFT] = "복수 제작",
11 | [CraftSim.CONST.TEXT.STAT_RESOURCEFULNESS] = "지혜",
12 | [CraftSim.CONST.TEXT.STAT_CRAFTINGSPEED] = "제작 속도",
13 | [CraftSim.CONST.TEXT.EQUIP_MATCH_STRING] = "착용 효과:",
14 | [CraftSim.CONST.TEXT.ENCHANTED_MATCH_STRING] = "마법부여:",
15 | [CraftSim.CONST.TEXT.STAT_INGENUITY] = "독창성",
16 |
17 | -- Details Frame
18 | [CraftSim.CONST.TEXT.RECIPE_DIFFICULTY_LABEL] = "제작 난이도: ",
19 | [CraftSim.CONST.TEXT.MULTICRAFT_LABEL] = "복수 제작: ",
20 | [CraftSim.CONST.TEXT.RESOURCEFULNESS_LABEL] = "지혜: ",
21 | }
22 | end
23 |
--------------------------------------------------------------------------------
/Libs/LibCompress/LibStub/tests/test3.lua:
--------------------------------------------------------------------------------
1 | debugstack = debug.traceback
2 | strmatch = string.match
3 |
4 | loadfile("../LibStub.lua")()
5 |
6 | local proxy = newproxy() -- non-string
7 |
8 | assert(not pcall(LibStub.NewLibrary, LibStub, proxy, 1)) -- should error, proxy is not a string, it's userdata
9 | local success, ret = pcall(LibStub.GetLibrary, proxy, true)
10 | assert(not success or not ret) -- either error because proxy is not a string or because it's not actually registered.
11 |
12 | assert(not pcall(LibStub.NewLibrary, LibStub, "Something", "No number in here")) -- should error, minor has no string in it.
13 |
14 | assert(not LibStub:GetLibrary("Something", true)) -- shouldn't've created it from the above statement
15 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
4 | patreon: # Replace with a single Patreon username
5 | open_collective: # Replace with a single Open Collective username
6 | ko_fi: craftsim
7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
9 | liberapay: # Replace with a single Liberapay username
10 | issuehunt: # Replace with a single IssueHunt username
11 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
12 | polar: # Replace with a single Polar username
13 | buy_me_a_coffee: # Replace with a single Buy Me a Coffee username
14 | thanks_dev: # Replace with a single thanks.dev username
15 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
16 |
--------------------------------------------------------------------------------
/Libs/LibStub/tests/test4.lua:
--------------------------------------------------------------------------------
1 | debugstack = debug.traceback
2 | strmatch = string.match
3 |
4 | loadfile("../LibStub.lua")()
5 |
6 |
7 | -- Pretend like loaded libstub is old and doesn't have :IterateLibraries
8 | assert(LibStub.minor)
9 | LibStub.minor = LibStub.minor - 0.0001
10 | LibStub.IterateLibraries = nil
11 |
12 | loadfile("../LibStub.lua")()
13 |
14 | assert(type(LibStub.IterateLibraries) == "function")
15 |
16 |
17 | -- Now pretend that we're the same version -- :IterateLibraries should NOT be re-created
18 | LibStub.IterateLibraries = 123
19 |
20 | loadfile("../LibStub.lua")()
21 |
22 | assert(LibStub.IterateLibraries == 123)
23 |
24 |
25 | -- Now pretend that a newer version is loaded -- :IterateLibraries should NOT be re-created
26 | LibStub.minor = LibStub.minor + 0.0001
27 |
28 | loadfile("../LibStub.lua")()
29 |
30 | assert(LibStub.IterateLibraries == 123)
31 |
32 |
33 | -- Again with a huge number
34 | LibStub.minor = LibStub.minor + 1234567890
35 |
36 | loadfile("../LibStub.lua")()
37 |
38 | assert(LibStub.IterateLibraries == 123)
39 |
40 |
41 | print("OK")
42 |
--------------------------------------------------------------------------------
/Libs/LibCompress/LibStub/tests/test4.lua:
--------------------------------------------------------------------------------
1 | debugstack = debug.traceback
2 | strmatch = string.match
3 |
4 | loadfile("../LibStub.lua")()
5 |
6 |
7 | -- Pretend like loaded libstub is old and doesn't have :IterateLibraries
8 | assert(LibStub.minor)
9 | LibStub.minor = LibStub.minor - 0.0001
10 | LibStub.IterateLibraries = nil
11 |
12 | loadfile("../LibStub.lua")()
13 |
14 | assert(type(LibStub.IterateLibraries) == "function")
15 |
16 |
17 | -- Now pretend that we're the same version -- :IterateLibraries should NOT be re-created
18 | LibStub.IterateLibraries = 123
19 |
20 | loadfile("../LibStub.lua")()
21 |
22 | assert(LibStub.IterateLibraries == 123)
23 |
24 |
25 | -- Now pretend that a newer version is loaded -- :IterateLibraries should NOT be re-created
26 | LibStub.minor = LibStub.minor + 0.0001
27 |
28 | loadfile("../LibStub.lua")()
29 |
30 | assert(LibStub.IterateLibraries == 123)
31 |
32 |
33 | -- Again with a huge number
34 | LibStub.minor = LibStub.minor + 1234567890
35 |
36 | loadfile("../LibStub.lua")()
37 |
38 | assert(LibStub.IterateLibraries == 123)
39 |
40 |
41 | print("OK")
42 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 Florian Schneider
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/.pkgmeta:
--------------------------------------------------------------------------------
1 | package-as: CraftSim
2 |
3 | enable-nolib-creation: no
4 |
5 | externals:
6 | Libs/LibStub: https://repos.curseforge.com/wow/libstub/trunk
7 | Libs/CallbackHandler-1.0: https://repos.curseforge.com/wow/callbackhandler/trunk/CallbackHandler-1.0
8 | Libs/AceAddon-3.0: https://repos.curseforge.com/wow/ace3/trunk/AceAddon-3.0
9 | Libs/AceEvent-3.0: https://repos.curseforge.com/wow/ace3/trunk/AceEvent-3.0
10 | Libs/AceDB-3.0: https://repos.curseforge.com/wow/ace3/trunk/AceDB-3.0
11 | Libs/AceComm-3.0: https://repos.curseforge.com/wow/ace3/trunk/AceComm-3.0
12 | Libs/AceSerializer-3.0: https://repos.curseforge.com/wow/ace3/trunk/AceSerializer-3.0
13 | Libs/LibCompress: https://repos.curseforge.com/wow/libcompress/trunk
14 | Libs/LibDBIcon-1.0: https://repos.curseforge.com/wow/libdbicon-1-0/trunk
15 | Libs/LibGraph-2.0: https://repos.curseforge.com/wow/libgraph-2-0/trunk
16 |
17 | Libs/GUTIL:
18 | url: https://github.com/derfloh205/GUTIL.git
19 | tag: 2.0
20 | Libs/GGUI:
21 | url: https://github.com/derfloh205/GGUI.git
22 | tag: 2.1
23 |
24 | ignore:
25 | - Libs/LibStub/tests
26 | - Libs/**/*.textile
27 | - Libs/**/*.txt
28 | - README.md
29 | - DevTools
--------------------------------------------------------------------------------
/Libs/LibStub/tests/test2.lua:
--------------------------------------------------------------------------------
1 | debugstack = debug.traceback
2 | strmatch = string.match
3 |
4 | loadfile("../LibStub.lua")()
5 |
6 | for major, library in LibStub:IterateLibraries() do
7 | -- check that MyLib doesn't exist yet, by iterating through all the libraries
8 | assert(major ~= "MyLib")
9 | end
10 |
11 | assert(not LibStub:GetLibrary("MyLib", true)) -- check that MyLib doesn't exist yet by direct checking
12 | assert(not pcall(LibStub.GetLibrary, LibStub, "MyLib")) -- don't silently fail, thus it should raise an error.
13 | local lib = LibStub:NewLibrary("MyLib", 1) -- create the lib
14 | assert(lib) -- check it exists
15 | assert(rawequal(LibStub:GetLibrary("MyLib"), lib)) -- verify that :GetLibrary("MyLib") properly equals the lib reference
16 |
17 | assert(LibStub:NewLibrary("MyLib", 2)) -- create a new version
18 |
19 | local count = 0
20 | for major, library in LibStub:IterateLibraries() do
21 | -- check that MyLib exists somewhere in the libraries, by iterating through all the libraries
22 | if major == "MyLib" then -- we found it!
23 | count = count + 1
24 | assert(rawequal(library, lib)) -- verify that the references are equal
25 | end
26 | end
27 | assert(count == 1) -- verify that we actually found it, and only once
28 |
--------------------------------------------------------------------------------
/Libs/LibCompress/LibStub/tests/test2.lua:
--------------------------------------------------------------------------------
1 | debugstack = debug.traceback
2 | strmatch = string.match
3 |
4 | loadfile("../LibStub.lua")()
5 |
6 | for major, library in LibStub:IterateLibraries() do
7 | -- check that MyLib doesn't exist yet, by iterating through all the libraries
8 | assert(major ~= "MyLib")
9 | end
10 |
11 | assert(not LibStub:GetLibrary("MyLib", true)) -- check that MyLib doesn't exist yet by direct checking
12 | assert(not pcall(LibStub.GetLibrary, LibStub, "MyLib")) -- don't silently fail, thus it should raise an error.
13 | local lib = LibStub:NewLibrary("MyLib", 1) -- create the lib
14 | assert(lib) -- check it exists
15 | assert(rawequal(LibStub:GetLibrary("MyLib"), lib)) -- verify that :GetLibrary("MyLib") properly equals the lib reference
16 |
17 | assert(LibStub:NewLibrary("MyLib", 2)) -- create a new version
18 |
19 | local count = 0
20 | for major, library in LibStub:IterateLibraries() do
21 | -- check that MyLib exists somewhere in the libraries, by iterating through all the libraries
22 | if major == "MyLib" then -- we found it!
23 | count = count + 1
24 | assert(rawequal(library, lib)) -- verify that the references are equal
25 | end
26 | end
27 | assert(count == 1) -- verify that we actually found it, and only once
28 |
--------------------------------------------------------------------------------
/Modules/Cooldowns/Cooldowns.lua:
--------------------------------------------------------------------------------
1 | ---@class CraftSim
2 | local CraftSim = select(2, ...)
3 |
4 | ---@class CraftSim.COOLDOWNS
5 | CraftSim.COOLDOWNS = {}
6 |
7 | local GUTIL = CraftSim.GUTIL
8 | local GGUI = CraftSim.GGUI
9 |
10 | local print = CraftSim.DEBUG:RegisterDebugID("Modules.Cooldowns")
11 |
12 | CraftSim.COOLDOWNS.isUpdatingTimers = false
13 |
14 | function CraftSim.COOLDOWNS:StartTimerUpdate()
15 | -- prevent duplicate timer updates
16 | if not CraftSim.COOLDOWNS.isUpdatingTimers then
17 | CraftSim.COOLDOWNS.isUpdatingTimers = true
18 | CraftSim.COOLDOWNS:PeriodicTimerUpdate()
19 | end
20 | end
21 |
22 | function CraftSim.COOLDOWNS:StopTimerUpdate()
23 | CraftSim.COOLDOWNS.isUpdatingTimers = false
24 | end
25 |
26 | function CraftSim.COOLDOWNS:PeriodicTimerUpdate()
27 | if not CraftSim.COOLDOWNS.isUpdatingTimers then return end
28 | CraftSim.COOLDOWNS.UI:UpdateTimers()
29 | C_Timer.After(1, CraftSim.COOLDOWNS.PeriodicTimerUpdate)
30 | end
31 |
32 | ---@return CraftSim.EXPANSION_IDS[]
33 | function CraftSim.COOLDOWNS:GetIncludedExpansions()
34 | local expansionIDs = {}
35 |
36 | for expansionID, included in pairs(CraftSim.DB.OPTIONS:Get("COOLDOWNS_FILTERED_EXPANSIONS") or {}) do
37 | if included then
38 | tinsert(expansionIDs, expansionID)
39 | end
40 | end
41 |
42 | return expansionIDs
43 | end
44 |
--------------------------------------------------------------------------------
/Libs/classic.lua:
--------------------------------------------------------------------------------
1 | --
2 | -- classic
3 | --
4 | -- Copyright (c) 2014, rxi
5 | --
6 | -- This module is free software; you can redistribute it and/or modify it under
7 | -- the terms of the MIT license. See LICENSE for details.
8 | --
9 |
10 | ---@class CraftSim
11 | local CraftSim = select(2, ...)
12 |
13 | ---@class classicObject
14 | local Object = {}
15 | Object.__index = Object
16 |
17 | ---@class CraftSim.Object : classicObject
18 | CraftSim.Object = Object
19 |
20 |
21 | function Object:new()
22 | end
23 |
24 | function Object:extend()
25 | local cls = {}
26 | for k, v in pairs(self) do
27 | if k:find("__") == 1 then
28 | cls[k] = v
29 | end
30 | end
31 | cls.__index = cls
32 | cls.super = self
33 | setmetatable(cls, self)
34 | return cls
35 | end
36 |
37 | function Object:implement(...)
38 | for _, cls in pairs({ ... }) do
39 | for k, v in pairs(cls) do
40 | if self[k] == nil and type(v) == "function" then
41 | self[k] = v
42 | end
43 | end
44 | end
45 | end
46 |
47 | function Object:is(T)
48 | local mt = getmetatable(self)
49 | while mt do
50 | if mt == T then
51 | return true
52 | end
53 | mt = getmetatable(mt)
54 | end
55 | return false
56 | end
57 |
58 | function Object:__tostring()
59 | return "Object"
60 | end
61 |
62 | function Object:__call(...)
63 | local obj = setmetatable({}, self)
64 | obj:new(...)
65 | return obj
66 | end
67 |
68 | return Object
69 |
--------------------------------------------------------------------------------
/Util/Widgets.lua:
--------------------------------------------------------------------------------
1 | ---@class CraftSim
2 | local CraftSim = select(2, ...)
3 |
4 | local GGUI = CraftSim.GGUI
5 | local GUTIL = CraftSim.GUTIL
6 | local L = CraftSim.UTIL:GetLocalizer()
7 | local f = CraftSim.GUTIL:GetFormatter()
8 |
9 | ---@class Craftsim.WIDGETS
10 | CraftSim.WIDGETS = {}
11 |
12 | ---@class CraftSim.WIDGETS.OptionsButton.ConstructorOptions
13 | ---@field parent Frame
14 | ---@field anchorPoints GGUI.AnchorPoint[]
15 | ---@field menuUtilCallback fun(ownerRegion: Region, rootDescription: any)
16 |
17 | ---@class CraftSim.WIDGETS.OptionsButton : GGUI.Button
18 | ---@overload fun(options: CraftSim.WIDGETS.OptionsButton.ConstructorOptions): CraftSim.WIDGETS.OptionsButton
19 | CraftSim.WIDGETS.OptionsButton = GGUI.Button:extend()
20 | ---@param options CraftSim.WIDGETS.OptionsButton.ConstructorOptions
21 | function CraftSim.WIDGETS.OptionsButton:new(options)
22 | ---@type GGUI.Button.ConstructorOptions
23 | local buttonOptions = {
24 | parent = options.parent,
25 | anchorPoints = options.anchorPoints,
26 | cleanTemplate = true,
27 | buttonTextureOptions = CraftSim.CONST.BUTTON_TEXTURE_OPTIONS.OPTIONS,
28 | sizeX = 20,
29 | sizeY = 20,
30 | clickCallback = function(button, mouseButton)
31 | MenuUtil.CreateContextMenu(UIParent, function(ownerRegion, rootDescription)
32 | options.menuUtilCallback(ownerRegion, rootDescription)
33 | end)
34 | end
35 | }
36 |
37 | CraftSim.WIDGETS.OptionsButton.super.new(self, buttonOptions)
38 | end
39 |
--------------------------------------------------------------------------------
/Classes/CraftResultItem.lua:
--------------------------------------------------------------------------------
1 | ---@class CraftSim
2 | local CraftSim = select(2, ...)
3 |
4 | ---@class CraftSim.CraftResultItem : CraftSim.CraftSimObject
5 | CraftSim.CraftResultItem = CraftSim.CraftSimObject:extend()
6 |
7 | ---@param itemLink string
8 | ---@param quantity number
9 | ---@param quantityMulticraft number
10 | ---@param qualityID number?
11 | function CraftSim.CraftResultItem:new(itemLink, quantity, quantityMulticraft, qualityID)
12 | self.qualityID = qualityID
13 | self.item = Item:CreateFromItemLink(itemLink)
14 | self.quantity = quantity - quantityMulticraft
15 | self.quantityMulticraft = quantityMulticraft
16 | end
17 |
18 | function CraftSim.CraftResultItem:Debug()
19 | local debugLines = {
20 | "Q" .. tostring(self.qualityID) .. " " .. tostring(self.item:GetItemLink()) .. " x " .. self.quantity,
21 | }
22 | if self.quantityMulticraft > 0 then
23 | table.insert(debugLines, "Multicraft: " .. self.quantityMulticraft)
24 | end
25 | return debugLines
26 | end
27 |
28 | function CraftSim.CraftResultItem:GetJSON(intent)
29 | intent = intent or 0
30 | local jb = CraftSim.JSONBuilder(intent)
31 | jb:Begin()
32 | jb:Add("itemID", self.item:GetItemID())
33 | jb:Add("itemString", CraftSim.GUTIL:GetItemStringFromLink(self.item:GetItemLink()))
34 | jb:Add("qualityID", self.qualityID)
35 | jb:Add("quantity", self.quantity)
36 | jb:Add("quantityMulticraft", self.quantityMulticraft, true)
37 | jb:End()
38 | return jb.json
39 | end
40 |
41 | ---@return CraftSim.CraftResultItem
42 | function CraftSim.CraftResultItem:Copy()
43 | return CraftSim.CraftResultItem(self.item:GetItemLink(), self.quantity, self.quantityMulticraft, self.qualityID)
44 | end
45 |
--------------------------------------------------------------------------------
/DevTools/DataScripts/EnchantData/mapper.py:
--------------------------------------------------------------------------------
1 | import sys
2 | sys.path.append('../')
3 | import wagoTools
4 | import shutil
5 |
6 | wagoTables = ["CraftingData", "CraftingDataEnchantQuality"]
7 |
8 | def copy(buildVersion):
9 | shutil.copy(f"Result/{buildVersion}/EnchantData.lua", "../../../Data/EnchantData.lua")
10 |
11 | def map(download, buildVersion):
12 | csvTables = wagoTools.getWagoTables(wagoTables, download, buildVersion)
13 | craftingDataTable = csvTables[0]
14 | enchantDataTable = csvTables[1]
15 |
16 | enchantDataMappedTable = {}
17 |
18 | count = 0
19 | total = len(craftingDataTable)
20 | for craftingData in craftingDataTable:
21 | count = count + 1
22 | wagoTools.updateProgressBar(count, total)
23 | if craftingData["Type"] == "3": # 3 .. Enchant
24 | craftingDataID = int(craftingData["ID"])
25 | for enchantData in enchantDataTable:
26 | if enchantData["CraftingDataID"] == str(craftingDataID):
27 | qualityID = int(enchantData["Rank"])
28 | itemID = int(enchantData["ItemID"])
29 | if craftingDataID not in enchantDataMappedTable:
30 | enchantDataMappedTable[craftingDataID] = {}
31 | enchantDataMappedTable[craftingDataID][f"q{qualityID}"] = itemID
32 |
33 |
34 |
35 | wagoTools.writeLuaTable(enchantDataMappedTable, "EnchantData", "---@class CraftSim\nlocal CraftSim = select(2, ...)\nCraftSim.ENCHANT_RECIPE_DATA = ", buildVersion)
36 |
37 | def update(buildVersion):
38 | map(True, buildVersion)
39 | copy(buildVersion)
40 |
41 | if __name__ == '__main__':
42 | args = sys.argv[1:]
43 | buildVersion = (len(args) > 0 and args[0]) or "Latest"
44 | update(buildVersion)
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/Media/Media.lua:
--------------------------------------------------------------------------------
1 | ---@class CraftSim
2 | local CraftSim = select(2, ...)
3 |
4 | CraftSim.MEDIA = {}
5 |
6 | CraftSim.MEDIA.BASE_PATH = "Interface/Addons/CraftSim/Media/Images/"
7 |
8 | local print = CraftSim.DEBUG:RegisterDebugID("Media")
9 |
10 | function CraftSim.MEDIA:GetAsTextIcon(image, scale)
11 | if tContains(CraftSim.MEDIA.IMAGES, image) then
12 | scale = scale or 1
13 | local width = image.dimensions.x * scale
14 | local height = image.dimensions.y * scale
15 |
16 | -- a print here causes a stack overflow... so be careful with debugging here
17 | return CraftSim.GUTIL:IconToText(CraftSim.MEDIA.BASE_PATH .. image.file, height, width, 0, 0, image.dimensions.x,
18 | image.dimensions.y)
19 | else
20 | return ""
21 | end
22 | end
23 |
24 | CraftSim.MEDIA.IMAGES = {
25 | EXPECTED_VALUE = { file = "expectedValue.blp", dimensions = { x = 128, y = 32 } },
26 | FALSE = { file = "false.blp", dimensions = { x = 128, y = 128 } },
27 | TRUE = { file = "true.blp", dimensions = { x = 128, y = 128 } },
28 | HSV_EXAMPLE = { file = "hsvVisualization.blp", dimensions = { x = 256, y = 64 } },
29 | ARROW_UP = { file = "upArrow.blp", dimensions = { x = 64, y = 64 } },
30 | ARROW_DOWN = { file = "downArrow.blp", dimensions = { x = 64, y = 64 } },
31 | PIXEL_HEART = { file = "pixelHeart.blp", dimensions = { x = 64, y = 64 } },
32 | KOFI = { file = "kofi.blp", dimensions = { x = 64, y = 64 } },
33 | PAYPAL = { file = "paypal.blp", dimensions = { x = 64, y = 64 } },
34 | EDIT_PEN = { file = "edit.blp", dimensions = { x = 25, y = 25 } },
35 | PIN = { file = "pin.tga", dimensions = { x = 32, y = 32 } },
36 | }
37 |
38 | function CraftSim.MEDIA:GetImagePath(image)
39 | return CraftSim.MEDIA.BASE_PATH .. image.file
40 | end
41 |
--------------------------------------------------------------------------------
/Modules/PriceOverride/PriceOverride.lua:
--------------------------------------------------------------------------------
1 | ---@class CraftSim
2 | local CraftSim = select(2, ...)
3 |
4 | CraftSim.PRICE_OVERRIDE = {}
5 |
6 | local print = CraftSim.DEBUG:RegisterDebugID("Modules.PriceOverride")
7 |
8 | ---@param overrideDropdownData CraftSim.PRICE_OVERRIDE.overrideDropdownData
9 | function CraftSim.PRICE_OVERRIDE:DeleteOverrideDataByDropdown(recipeID, overrideDropdownData)
10 | if overrideDropdownData.isResult then
11 | CraftSim.DB.PRICE_OVERRIDE:DeleteResultOverride(recipeID, overrideDropdownData.qualityID)
12 | else
13 | CraftSim.DB.PRICE_OVERRIDE:DeleteGlobalOverride(overrideDropdownData.item:GetItemID())
14 | end
15 | end
16 |
17 | ---@param recipeID RecipeID
18 | ---@param overrideDropdownData CraftSim.PRICE_OVERRIDE.overrideDropdownData
19 | function CraftSim.PRICE_OVERRIDE:SaveOverrideDataByDropdown(recipeID, overrideDropdownData)
20 | local exportMode = CraftSim.UTIL:GetExportModeByVisibility()
21 | local priceOverrideFrame = nil
22 | if exportMode == CraftSim.CONST.EXPORT_MODE.WORK_ORDER then
23 | priceOverrideFrame = CraftSim.GGUI:GetFrame(CraftSim.INIT.FRAMES, CraftSim.CONST.FRAMES
24 | .PRICE_OVERRIDE_WORK_ORDER)
25 | else
26 | priceOverrideFrame = CraftSim.GGUI:GetFrame(CraftSim.INIT.FRAMES, CraftSim.CONST.FRAMES.PRICE_OVERRIDE)
27 | end
28 |
29 | local price = priceOverrideFrame.content.overrideOptions.currencyInputGold.total or 0
30 |
31 | local overrideData = {
32 | recipeID = recipeID,
33 | itemID = overrideDropdownData.item:GetItemID(),
34 | qualityID = overrideDropdownData.qualityID,
35 | price = price,
36 | }
37 |
38 | if overrideDropdownData.isResult then
39 | CraftSim.DB.PRICE_OVERRIDE:SaveResultOverride(overrideData)
40 | else
41 | CraftSim.DB.PRICE_OVERRIDE:SaveGlobalOverride(overrideData)
42 | end
43 | end
44 |
--------------------------------------------------------------------------------
/DevTools/DataScripts/ReagentWeightData/mapper.py:
--------------------------------------------------------------------------------
1 | import sys
2 | sys.path.append('../')
3 | import wagoTools
4 | import shutil
5 |
6 | wagoTables = ["Item", "ModifiedCraftingReagentItem", "ModifiedCraftingCategory"]
7 |
8 | def getItemWeight(reagentItemID, reagentItemTable, craftingCategoryTable):
9 | for reagentItem in reagentItemTable:
10 | if reagentItemID == reagentItem["ID"]:
11 | craftingCategoryID = reagentItem["ModifiedCraftingCategoryID"]
12 | for craftingCategory in craftingCategoryTable:
13 | if craftingCategoryID == craftingCategory["ID"]:
14 | return int(craftingCategory["MatQualityWeight"])
15 | return 0
16 |
17 | def copy(buildVersion):
18 | shutil.copy(f"Result/{buildVersion}/ReagentWeightData.lua", "../../../Data/ReagentWeightData.lua")
19 |
20 | def map(download, buildVersion):
21 | csvTables = wagoTools.getWagoTables(wagoTables, download, buildVersion)
22 | tradeSkillItemTable = csvTables[0]
23 | reagentItemTable = csvTables[1]
24 | craftingCategoryTable = csvTables[2]
25 |
26 | itemWeightTable = {}
27 |
28 | for item in tradeSkillItemTable:
29 | itemID = item["ID"]
30 | reagentItemID = item["ModifiedCraftingReagentItemID"]
31 | weight = getItemWeight(reagentItemID, reagentItemTable, craftingCategoryTable)
32 | if weight and weight > 0:
33 | itemWeightTable[int(itemID)] = {"weight": weight}
34 |
35 | wagoTools.writeLuaTable(itemWeightTable, "ReagentWeightData", "---@class CraftSim\nlocal CraftSim = select(2, ...)\nCraftSim.REAGENT_DATA = ", buildVersion)
36 |
37 | def update(buildVersion):
38 | map(True, buildVersion)
39 | copy(buildVersion)
40 |
41 | if __name__ == '__main__':
42 | args = sys.argv[1:]
43 | buildVersion = (len(args) > 0 and args[0]) or buildVersion
44 |
45 | update(buildVersion)
--------------------------------------------------------------------------------
/Classes/TopGearResult.lua:
--------------------------------------------------------------------------------
1 | ---@class CraftSim
2 | local CraftSim = select(2, ...)
3 |
4 | ---@class CraftSim.TopGearResult : CraftSim.CraftSimObject
5 | CraftSim.TopGearResult = CraftSim.CraftSimObject:extend()
6 |
7 | ---@param professionGearSet CraftSim.ProfessionGearSet
8 | ---@param averageProfit number
9 | ---@param relativeProfit number
10 | ---@param relativeStats CraftSim.ProfessionStats
11 | ---@param expectedQuality number
12 | ---@param expectedQualityUpgrade number
13 | function CraftSim.TopGearResult:new(professionGearSet, averageProfit, relativeProfit, concentrationValue,
14 | relativeConcentrationValue, relativeStats, expectedQuality,
15 | expectedQualityUpgrade)
16 | self.relativeStats = relativeStats
17 | self.professionGearSet = professionGearSet
18 | self.averageProfit = averageProfit
19 | self.relativeProfit = relativeProfit
20 | self.concentrationValue = concentrationValue
21 | self.relativeConcentrationValue = relativeConcentrationValue
22 | self.expectedQuality = expectedQuality
23 | self.expectedQualityUpgrade = expectedQualityUpgrade
24 | end
25 |
26 | function CraftSim.TopGearResult:Debug()
27 | local debugLines = {
28 | "Average Profit: " .. CraftSim.UTIL:FormatMoney(self.averageProfit, true),
29 | "Relative Profit: " .. CraftSim.UTIL:FormatMoney(self.relativeProfit, true),
30 | "Relative Profit Exact: " .. self.relativeProfit,
31 | "ExpectedQuality: " .. self.expectedQuality,
32 | "ExpectedQualityUpgrade: " .. (self.expectedQualityUpgrade or "none"),
33 | "Profession Gear Set:"
34 | }
35 |
36 | debugLines = CraftSim.GUTIL:Concat({ debugLines, self.professionGearSet:Debug() })
37 |
38 | table.insert(debugLines, "Relative Stats:")
39 | debugLines = CraftSim.GUTIL:Concat({ debugLines, self.relativeStats:Debug() })
40 | return debugLines
41 | end
42 |
--------------------------------------------------------------------------------
/Classes/CraftResultReagent.lua:
--------------------------------------------------------------------------------
1 | ---@class CraftSim
2 | local CraftSim = select(2, ...)
3 |
4 |
5 | ---@class CraftSim.CraftResultReagent : CraftSim.CraftSimObject
6 | ---@overload fun(recipeData: CraftSim.RecipeData, itemID: ItemID, quantity: number, isOrderReagent: boolean?) : CraftSim.CraftResultReagent
7 | CraftSim.CraftResultReagent = CraftSim.CraftSimObject:extend()
8 |
9 | ---@param recipeData CraftSim.RecipeData
10 | ---@param itemID number
11 | ---@param quantity number
12 | ---@param isOrderReagent boolean?
13 | function CraftSim.CraftResultReagent:new(recipeData, itemID, quantity, isOrderReagent)
14 | isOrderReagent = isOrderReagent or false
15 | if not recipeData then return end
16 | self.isOrderReagent = isOrderReagent
17 | self.item = Item:CreateFromItemID(itemID)
18 | self.quantity = quantity
19 | self.costs = CraftSim.PRICE_SOURCE:GetMinBuyoutByItemID(itemID, true) * self.quantity
20 | self.qualityID = recipeData.reagentData:GetReagentQualityIDByItemID(itemID)
21 | end
22 |
23 | ---@return CraftSim.CraftResultReagent
24 | function CraftSim.CraftResultReagent:Copy()
25 | local copy = CraftSim.CraftResultReagent()
26 | copy.item = self.item
27 | copy.isOrderReagent = self.isOrderReagent
28 | copy.quantity = self.quantity
29 | copy.costs = self.costs
30 | copy.qualityID = self.qualityID
31 | return copy
32 | end
33 |
34 | function CraftSim.CraftResultReagent:Debug()
35 | return {
36 | "Q" .. self.qualityID .. " " .. (self.item:GetItemLink() or self.item:GetItemID()) .. " x " .. self.quantity,
37 | "Costs: " .. CraftSim.UTIL:FormatMoney(self.costs),
38 | }
39 | end
40 |
41 | function CraftSim.CraftResultReagent:GetJSON(indent)
42 | indent = indent or 0
43 | local jb = CraftSim.JSONBuilder(indent)
44 | jb:Begin()
45 | jb:Add("itemID", self.item:GetItemID())
46 | jb:Add("itemString", CraftSim.GUTIL:GetItemStringFromLink(self.item:GetItemLink() or ""))
47 | jb:Add("qualityID", self.qualityID)
48 | jb:Add("quantity", self.quantity)
49 | jb:Add("costs", self.costs, true)
50 | jb:End()
51 | return jb.json
52 | end
53 |
--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | # description of this workflow, can be anything you want
2 | name: Package and release
3 |
4 | # we need to let GitHub know _when_ we want to release, typically only when we create a new tag.
5 | # this will target only tags, and not all pushes to the master branch.
6 | # this part can be heavily customized to your liking, like targeting only tags that match a certain word,
7 | # other branches or even pullrequests.
8 | on:
9 | push:
10 | tags:
11 | - '**'
12 |
13 | # a workflow is built up as jobs, and within these jobs are steps
14 | jobs:
15 |
16 | # "release" is a job, you can name it anything you want
17 | release:
18 |
19 | # we can run our steps on pretty much anything, but the "ubuntu-latest" image is a safe bet
20 | # since latest was changed to 24 which does not include svn anymore need to enforce 22.04
21 | runs-on: ubuntu-22.04
22 |
23 | # specify the environment variables used by the packager, matching the secrets from the project on GitHub
24 | env:
25 | CF_API_KEY: ${{ secrets.CF_API_KEY }}
26 | WOWI_API_TOKEN: ${{ secrets.WOWI_API_TOKEN }}
27 | WAGO_API_TOKEN: ${{ secrets.WAGO_API_TOKEN }}
28 | GITHUB_OAUTH: ${{ secrets.GITHUB_TOKEN }} # "GITHUB_TOKEN" is a secret always provided to the workflow
29 | # for your own token, the name cannot start with "GITHUB_"
30 |
31 | # "steps" holds a list of all the steps needed to package and release our AddOn
32 | steps:
33 |
34 | - name: Checkout repository and submodules
35 | uses: actions/checkout@v2
36 | with:
37 | submodules: recursive
38 | fetch-depth: 0 # gets entire git history, needed for automatic changelogs
39 |
40 | # we first have to clone the AddOn project, this is a required step
41 | #- name: Clone project
42 | # uses: actions/checkout@v3
43 | # with:
44 | # fetch-depth: 0 # gets entire git history, needed for automatic changelogs
45 |
46 | # once cloned, we just run the GitHub Action for the packager project
47 | - name: Package and release
48 | uses: BigWigsMods/packager@v2
49 |
--------------------------------------------------------------------------------
/Util/Comm.lua:
--------------------------------------------------------------------------------
1 | ---@class CraftSim
2 | local CraftSim = select(2, ...)
3 |
4 | ---@class CraftSim.COMM : AceAddon
5 | CraftSim.COMM = LibStub("AceAddon-3.0"):NewAddon("CraftSim.COMM", "AceComm-3.0", "AceSerializer-3.0")
6 |
7 | CraftSim.COMM.registeredPrefixes = {}
8 |
9 | local print = CraftSim.DEBUG:RegisterDebugID("Util.Comm")
10 |
11 | local function encodeData(data)
12 | local serializedData = CraftSim.COMM:Serialize(data)
13 | local compressedData, compressError = CraftSim.LibCompress:Compress(serializedData)
14 | local encodedData = CraftSim.LibCompress:GetAddonEncodeTable():Encode(compressedData)
15 | return encodedData
16 | end
17 |
18 | local function decodeData(payload)
19 | local decodedData = CraftSim.LibCompress:GetAddonEncodeTable():Decode(payload)
20 | local decompressedData, error = CraftSim.LibCompress:Decompress(decodedData)
21 |
22 | if not decompressedData then
23 | print("CraftSim COMM Error: " .. tostring(error))
24 | return
25 | end
26 |
27 | local success, deserializedData = CraftSim.COMM:Deserialize(decompressedData)
28 |
29 | if not success then
30 | print("CraftSim COMM Error: Could not deserialize incoming data")
31 | end
32 |
33 | return deserializedData
34 | end
35 |
36 | function CraftSim.COMM:RegisterPrefix(prefix, callback)
37 | CraftSim.COMM:RegisterComm(prefix)
38 | CraftSim.COMM.registeredPrefixes[prefix] = callback
39 | end
40 |
41 | function CraftSim.COMM:OnCommReceived(prefix, payload)
42 | print("CraftSim.COMM: Receive " .. tostring(prefix))
43 | if CraftSim.COMM.registeredPrefixes[prefix] then
44 | CraftSim.COMM.registeredPrefixes[prefix](decodeData(payload))
45 | else
46 | error("CraftSim COMM Error: Prefix not registered: " .. tostring(prefix))
47 | end
48 | end
49 |
50 | function CraftSim.COMM:SendData(prefix, data, channel, target, progressCallback)
51 | if channel == "WHISPER" and not target then
52 | print("CraftSim COMM: No target for WHISPER provided")
53 | return
54 | end
55 |
56 | local payload = encodeData(data)
57 |
58 | print("CraftSim.COMM: Send " .. tostring(prefix))
59 | CraftSim.COMM:SendCommMessage(prefix, payload, channel, target, "NORMAL", progressCallback)
60 | end
61 |
--------------------------------------------------------------------------------
/DB/multicraftPreloadDB.lua:
--------------------------------------------------------------------------------
1 | ---@class CraftSim
2 | local CraftSim = select(2, ...)
3 |
4 | local GUTIL = CraftSim.GUTIL
5 |
6 | ---@class CraftSim.DB
7 | CraftSim.DB = CraftSim.DB
8 |
9 | ---@class CraftSim.DB.MULTICRAFT_PRELOAD : CraftSim.DB.Repository
10 | CraftSim.DB.MULTICRAFT_PRELOAD = CraftSim.DB:RegisterRepository()
11 |
12 | local print = CraftSim.DEBUG:RegisterDebugID("Database.multicraftPreloadDB")
13 |
14 | function CraftSim.DB.MULTICRAFT_PRELOAD:Init()
15 | if not CraftSimDB.multicraftPreloadDB then
16 | ---@type CraftSimDB.Database
17 | CraftSimDB.multicraftPreloadDB = {
18 | version = 0,
19 | ---@type table
20 | data = {},
21 | }
22 | end
23 |
24 | CraftSimDB.multicraftPreloadDB.data = CraftSimDB.multicraftPreloadDB.data or {}
25 | end
26 |
27 | function CraftSim.DB.MULTICRAFT_PRELOAD:Migrate()
28 | -- 0 -> 1
29 | if CraftSimDB.multicraftPreloadDB.version == 0 then
30 | local CraftSimRecipeDataCache = _G["CraftSimRecipeDataCache"]
31 | if CraftSimRecipeDataCache then
32 | CraftSimDB.multicraftPreloadDB.data = CraftSimRecipeDataCache["postLoadedMulticraftInformationProfessions"] or
33 | {}
34 | end
35 | CraftSimDB.multicraftPreloadDB.version = 1
36 | end
37 | end
38 |
39 | function CraftSim.DB.MULTICRAFT_PRELOAD:ClearAll()
40 | wipe(CraftSimDB.multicraftPreloadDB.data)
41 | end
42 |
43 | ---@param profession Enum.Profession
44 | ---@param preloaded boolean
45 | function CraftSim.DB.MULTICRAFT_PRELOAD:Save(profession, preloaded)
46 | CraftSimDB.multicraftPreloadDB.data[profession] = preloaded
47 | end
48 |
49 | ---@param profession Enum.Profession
50 | ---@return boolean preloaded
51 | function CraftSim.DB.MULTICRAFT_PRELOAD:Get(profession)
52 | return CraftSimDB.multicraftPreloadDB.data[profession] == true -- to convert to boolean
53 | end
54 |
55 | function CraftSim.DB.MULTICRAFT_PRELOAD:CleanUp()
56 | local CraftSimRecipeDataCache = _G["CraftSimRecipeDataCache"]
57 | if CraftSimRecipeDataCache and CraftSimRecipeDataCache["postLoadedMulticraftInformationProfessions"] then
58 | CraftSimRecipeDataCache["postLoadedMulticraftInformationProfessions"] = nil
59 | end
60 | end
61 |
--------------------------------------------------------------------------------
/Modules/Explanations/UI.lua:
--------------------------------------------------------------------------------
1 | ---@class CraftSim
2 | local CraftSim = select(2, ...)
3 |
4 | local GGUI = CraftSim.GGUI
5 | local GUTIL = CraftSim.GUTIL
6 |
7 | local L = CraftSim.UTIL:GetLocalizer()
8 | local f = GUTIL:GetFormatter()
9 |
10 | ---@class CraftSim.EXPLANATIONS
11 | CraftSim.EXPLANATIONS = CraftSim.EXPLANATIONS
12 |
13 | ---@class CraftSim.EXPLANATIONS.UI
14 | CraftSim.EXPLANATIONS.UI = {}
15 |
16 | function CraftSim.EXPLANATIONS.UI:Init()
17 | CraftSim.EXPLANATIONS.frame = GGUI.Frame {
18 | title = L(CraftSim.CONST.TEXT.EXPLANATIONS_TITLE),
19 | parent = ProfessionsFrame, anchorParent = ProfessionsFrame,
20 | sizeX = 1000, sizeY = 600,
21 | frameConfigTable = CraftSim.DB.OPTIONS:Get("GGUI_CONFIG"), frameTable = CraftSim.INIT.FRAMES,
22 | frameID = CraftSim.CONST.FRAMES.EXPLANATIONS, moveable = true, closeable = true, collapseable = true,
23 | backdropOptions = CraftSim.CONST.DEFAULT_BACKDROP_OPTIONS,
24 | onCloseCallback = CraftSim.CONTROL_PANEL:HandleModuleClose("MODULE_EXPLANATIONS"),
25 | frameStrata = CraftSim.CONST.MODULES_FRAME_STRATA,
26 | raiseOnInteraction = true,
27 | frameLevel = CraftSim.UTIL:NextFrameLevel()
28 | }
29 |
30 | local function createContent(frame)
31 | frame:Hide()
32 | frame.content.profitExplanationTab = GGUI.BlizzardTab {
33 | parent = frame.content, anchorParent = frame.content,
34 | sizeX = 900, sizeY = 500,
35 | top = true, initialTab = true,
36 | buttonOptions = {
37 | offsetY = -5,
38 | label = L(CraftSim.CONST.TEXT.EXPLANATIONS_BASIC_PROFIT_TAB),
39 | },
40 | }
41 |
42 | frame.content.profitExplanationTab.content.description = GGUI.Text {
43 | parent = frame.content.profitExplanationTab.content, anchorParent = frame.content.profitExplanationTab.content,
44 | text = L(CraftSim.CONST.TEXT.EXPLANATIONS_PROFIT_CALCULATION_EXPLANATION), anchorA = "TOPLEFT", anchorB = "TOPLEFT",
45 | offsetY = -20, justifyOptions = { type = "H", align = "LEFT" }, wrap = true
46 | }
47 |
48 |
49 | GGUI.BlizzardTabSystem { frame.content.profitExplanationTab }
50 | end
51 |
52 | createContent(CraftSim.EXPLANATIONS.frame)
53 | end
54 |
--------------------------------------------------------------------------------
/DB/craftQueueDB.lua:
--------------------------------------------------------------------------------
1 | ---@class CraftSim
2 | local CraftSim = select(2, ...)
3 |
4 | local GUTIL = CraftSim.GUTIL
5 |
6 | ---@class CraftSim.DB
7 | CraftSim.DB = CraftSim.DB
8 |
9 | ---@class CraftSim.DB.CRAFT_QUEUE : CraftSim.DB.Repository
10 | CraftSim.DB.CRAFT_QUEUE = CraftSim.DB:RegisterRepository()
11 |
12 | local print = CraftSim.DEBUG:RegisterDebugID("Database.craftQueueDB")
13 |
14 | function CraftSim.DB.CRAFT_QUEUE:Init()
15 | if not CraftSimDB.craftQueueDB then
16 | ---@class CraftSimDB.CraftQueueDB : CraftSimDB.Database
17 | CraftSimDB.craftQueueDB = {
18 | version = 0,
19 | ---@type CraftSim.CraftQueueItem.Serialized[]
20 | data = {},
21 | }
22 | end
23 |
24 | CraftSimDB.craftQueueDB.data = CraftSimDB.craftQueueDB.data or {}
25 | end
26 |
27 | function CraftSim.DB.CRAFT_QUEUE:Migrate()
28 | local migrate = CraftSim.DB:GetMigrateFunction(CraftSimDB.craftQueueDB)
29 |
30 | migrate(0, 1, function()
31 | if _G["CraftSimCraftQueueCache"] then
32 | CraftSimDB.craftQueueDB.data = _G["CraftSimCraftQueueCache"]
33 | end
34 | end)
35 | migrate(1, 2, function()
36 | CraftSim.DB.CRAFT_QUEUE:ClearAll()
37 | end)
38 | migrate(2, 3, function()
39 | CraftSim.DB.CRAFT_QUEUE:ClearAll()
40 | end)
41 | migrate(3, 4, function()
42 | CraftSim.DB.CRAFT_QUEUE:ClearAll()
43 | end)
44 | migrate(4, 5, function()
45 | CraftSim.DB.CRAFT_QUEUE:ClearAll()
46 | end)
47 | migrate(5, 6, function()
48 | CraftSim.DB.CRAFT_QUEUE:ClearAll()
49 | end)
50 | migrate(6, 7, function()
51 | CraftSim.DB.CRAFT_QUEUE:ClearAll()
52 | end)
53 | end
54 |
55 | function CraftSim.DB.CRAFT_QUEUE:ClearAll()
56 | wipe(CraftSimDB.craftQueueDB.data)
57 | end
58 |
59 | function CraftSim.DB.CRAFT_QUEUE:CleanUp()
60 | if _G["CraftSimCraftQueueCache"] then
61 | _G["CraftSimCraftQueueCache"] = nil
62 | end
63 | end
64 |
65 | function CraftSim.DB.CRAFT_QUEUE:GetAll()
66 | return CraftSimDB.craftQueueDB.data
67 | end
68 |
69 | ---@param craftQueueItemSerialized CraftSim.CraftQueueItem.Serialized
70 | function CraftSim.DB.CRAFT_QUEUE:Add(craftQueueItemSerialized)
71 | tinsert(CraftSimDB.craftQueueDB.data, craftQueueItemSerialized)
72 | end
73 |
--------------------------------------------------------------------------------
/Libs/LibStub/LibStub.lua:
--------------------------------------------------------------------------------
1 | -- $Id: LibStub.lua 103 2014-10-16 03:02:50Z mikk $
2 | -- LibStub is a simple versioning stub meant for use in Libraries. http://www.wowace.com/addons/libstub/ for more info
3 | -- LibStub is hereby placed in the Public Domain
4 | -- Credits: Kaelten, Cladhaire, ckknight, Mikk, Ammo, Nevcairiel, joshborke
5 | local LIBSTUB_MAJOR, LIBSTUB_MINOR = "LibStub",
6 | 2 -- NEVER MAKE THIS AN SVN REVISION! IT NEEDS TO BE USABLE IN ALL REPOS!
7 | local LibStub = _G[LIBSTUB_MAJOR]
8 |
9 | -- Check to see is this version of the stub is obsolete
10 | if not LibStub or LibStub.minor < LIBSTUB_MINOR then
11 | LibStub = LibStub or { libs = {}, minors = {} }
12 | _G[LIBSTUB_MAJOR] = LibStub
13 | LibStub.minor = LIBSTUB_MINOR
14 |
15 | -- LibStub:NewLibrary(major, minor)
16 | -- major (string) - the major version of the library
17 | -- minor (string or number ) - the minor version of the library
18 | --
19 | -- returns nil if a newer or same version of the lib is already present
20 | -- returns empty library object or old library object if upgrade is needed
21 | function LibStub:NewLibrary(major, minor)
22 | assert(type(major) == "string", "Bad argument #2 to `NewLibrary' (string expected)")
23 | minor = assert(tonumber(strmatch(minor, "%d+")), "Minor version must either be a number or contain a number.")
24 |
25 | local oldminor = self.minors[major]
26 | if oldminor and oldminor >= minor then return nil end
27 | self.minors[major], self.libs[major] = minor, self.libs[major] or {}
28 | return self.libs[major], oldminor
29 | end
30 |
31 | -- LibStub:GetLibrary(major, [silent])
32 | -- major (string) - the major version of the library
33 | -- silent (boolean) - if true, library is optional, silently return nil if its not found
34 | --
35 | -- throws an error if the library can not be found (except silent is set)
36 | -- returns the library object if found
37 | function LibStub:GetLibrary(major, silent)
38 | if not self.libs[major] and not silent then
39 | error(("Cannot find a library instance of %q."):format(tostring(major)), 2)
40 | end
41 | return self.libs[major], self.minors[major]
42 | end
43 |
44 | -- LibStub:IterateLibraries()
45 | --
46 | -- Returns an iterator for the currently registered libraries
47 | function LibStub:IterateLibraries()
48 | return pairs(self.libs)
49 | end
50 |
51 | setmetatable(LibStub, { __call = LibStub.GetLibrary })
52 | end
53 |
--------------------------------------------------------------------------------
/Libs/LibDBIcon-1.0/LibStub/LibStub.lua:
--------------------------------------------------------------------------------
1 | -- $Id: LibStub.lua 76 2007-09-03 01:50:17Z mikk $
2 | -- LibStub is a simple versioning stub meant for use in Libraries. http://www.wowace.com/wiki/LibStub for more info
3 | -- LibStub is hereby placed in the Public Domain
4 | -- Credits: Kaelten, Cladhaire, ckknight, Mikk, Ammo, Nevcairiel, joshborke
5 | local LIBSTUB_MAJOR, LIBSTUB_MINOR = "LibStub",
6 | 2 -- NEVER MAKE THIS AN SVN REVISION! IT NEEDS TO BE USABLE IN ALL REPOS!
7 | local LibStub = _G[LIBSTUB_MAJOR]
8 |
9 | -- Check to see is this version of the stub is obsolete
10 | if not LibStub or LibStub.minor < LIBSTUB_MINOR then
11 | LibStub = LibStub or { libs = {}, minors = {} }
12 | _G[LIBSTUB_MAJOR] = LibStub
13 | LibStub.minor = LIBSTUB_MINOR
14 |
15 | -- LibStub:NewLibrary(major, minor)
16 | -- major (string) - the major version of the library
17 | -- minor (string or number ) - the minor version of the library
18 | --
19 | -- returns nil if a newer or same version of the lib is already present
20 | -- returns empty library object or old library object if upgrade is needed
21 | function LibStub:NewLibrary(major, minor)
22 | assert(type(major) == "string", "Bad argument #2 to `NewLibrary' (string expected)")
23 | minor = assert(tonumber(strmatch(minor, "%d+")), "Minor version must either be a number or contain a number.")
24 |
25 | local oldminor = self.minors[major]
26 | if oldminor and oldminor >= minor then return nil end
27 | self.minors[major], self.libs[major] = minor, self.libs[major] or {}
28 | return self.libs[major], oldminor
29 | end
30 |
31 | -- LibStub:GetLibrary(major, [silent])
32 | -- major (string) - the major version of the library
33 | -- silent (boolean) - if true, library is optional, silently return nil if its not found
34 | --
35 | -- throws an error if the library can not be found (except silent is set)
36 | -- returns the library object if found
37 | function LibStub:GetLibrary(major, silent)
38 | if not self.libs[major] and not silent then
39 | error(("Cannot find a library instance of %q."):format(tostring(major)), 2)
40 | end
41 | return self.libs[major], self.minors[major]
42 | end
43 |
44 | -- LibStub:IterateLibraries()
45 | --
46 | -- Returns an iterator for the currently registered libraries
47 | function LibStub:IterateLibraries()
48 | return pairs(self.libs)
49 | end
50 |
51 | setmetatable(LibStub, { __call = LibStub.GetLibrary })
52 | end
53 |
--------------------------------------------------------------------------------
/Libs/LibCompress/LibStub/LibStub.lua:
--------------------------------------------------------------------------------
1 | -- $Id: LibStub.lua 103 2014-10-16 03:02:50Z mikk $
2 | -- LibStub is a simple versioning stub meant for use in Libraries. http://www.wowace.com/addons/libstub/ for more info
3 | -- LibStub is hereby placed in the Public Domain
4 | -- Credits: Kaelten, Cladhaire, ckknight, Mikk, Ammo, Nevcairiel, joshborke
5 | local LIBSTUB_MAJOR, LIBSTUB_MINOR = "LibStub",
6 | 2 -- NEVER MAKE THIS AN SVN REVISION! IT NEEDS TO BE USABLE IN ALL REPOS!
7 | local LibStub = _G[LIBSTUB_MAJOR]
8 |
9 | -- Check to see is this version of the stub is obsolete
10 | if not LibStub or LibStub.minor < LIBSTUB_MINOR then
11 | LibStub = LibStub or { libs = {}, minors = {} }
12 | _G[LIBSTUB_MAJOR] = LibStub
13 | LibStub.minor = LIBSTUB_MINOR
14 |
15 | -- LibStub:NewLibrary(major, minor)
16 | -- major (string) - the major version of the library
17 | -- minor (string or number ) - the minor version of the library
18 | --
19 | -- returns nil if a newer or same version of the lib is already present
20 | -- returns empty library object or old library object if upgrade is needed
21 | function LibStub:NewLibrary(major, minor)
22 | assert(type(major) == "string", "Bad argument #2 to `NewLibrary' (string expected)")
23 | minor = assert(tonumber(strmatch(minor, "%d+")), "Minor version must either be a number or contain a number.")
24 |
25 | local oldminor = self.minors[major]
26 | if oldminor and oldminor >= minor then return nil end
27 | self.minors[major], self.libs[major] = minor, self.libs[major] or {}
28 | return self.libs[major], oldminor
29 | end
30 |
31 | -- LibStub:GetLibrary(major, [silent])
32 | -- major (string) - the major version of the library
33 | -- silent (boolean) - if true, library is optional, silently return nil if its not found
34 | --
35 | -- throws an error if the library can not be found (except silent is set)
36 | -- returns the library object if found
37 | function LibStub:GetLibrary(major, silent)
38 | if not self.libs[major] and not silent then
39 | error(("Cannot find a library instance of %q."):format(tostring(major)), 2)
40 | end
41 | return self.libs[major], self.minors[major]
42 | end
43 |
44 | -- LibStub:IterateLibraries()
45 | --
46 | -- Returns an iterator for the currently registered libraries
47 | function LibStub:IterateLibraries()
48 | return pairs(self.libs)
49 | end
50 |
51 | setmetatable(LibStub, { __call = LibStub.GetLibrary })
52 | end
53 |
--------------------------------------------------------------------------------
/Locals/esES.lua:
--------------------------------------------------------------------------------
1 | ---@class CraftSim
2 | local CraftSim = select(2, ...)
3 |
4 | CraftSim.LOCAL_ES = {}
5 |
6 | function CraftSim.LOCAL_ES:GetData()
7 | local f = CraftSim.GUTIL:GetFormatter()
8 | return {
9 | -- REQUIRED:
10 | [CraftSim.CONST.TEXT.STAT_MULTICRAFT] = "Multifabricación",
11 | [CraftSim.CONST.TEXT.STAT_RESOURCEFULNESS] = "Inventiva",
12 | [CraftSim.CONST.TEXT.STAT_INGENUITY] = "Ingenio",
13 | [CraftSim.CONST.TEXT.STAT_CRAFTINGSPEED] = "Velocidad de fabricación",
14 | [CraftSim.CONST.TEXT.EQUIP_MATCH_STRING] = "Equipar:",
15 | [CraftSim.CONST.TEXT.ENCHANTED_MATCH_STRING] = "Encantado:",
16 |
17 | -- OPTIONAL (Defaulting to EN if not available):
18 | -- Profit Breakdown Tooltips
19 |
20 | [CraftSim.CONST.TEXT.RECIPE_DIFFICULTY_EXPLANATION_TOOLTIP] =
21 | "Dificultad de la receta determina cuanta Habilidad es necesaria para fabricar la receta en cada calidad.\n\nPara recetas con cinco calidades es 20%, 50%, 80% y 100% de la Dificultad de la receta como Habilidad\nPara recetas con tres calidades es 50% y 100%",
22 | [CraftSim.CONST.TEXT.MULTICRAFT_EXPLANATION_TOOLTIP] =
23 | "Multifabricación da una probabilidad de fabricar mas objetos de los que normalmente fabricaría la receta.\n\nLa cantidad adicional es entre 1 y 2.5y\ndonde y = es la cantidad normal que da la fabricación.",
24 | [CraftSim.CONST.TEXT.RESOURCEFULNESS_EXPLANATION_TOOLTIP] =
25 | "Ingenio da una probabilidad POR MATERIAL de ahorrar de media un 30% de su cantidad.\n\nComo la probabilidad puede suceder por cada material individualmente hay muchas combinaciones posibles a considerar\ncomo que suceda en todos los materiales a la vez (la probabilidad de esto es muy muy baja)",
26 | [CraftSim.CONST.TEXT.REAGENTSKILL_EXPLANATION_TOOLTIP] =
27 | "La calidad de los componentes de fabricación puede otorgar hasta un maximo de un 25% de la Dificultad de la receta como Habilidad.\n\nTodos los componentes C1: 0% Bonus\nTodos los componentes C2: 12.5% Bonus\nTodos los componentes C3: 25% Bonus\n\nLa Habilidad es calculada en base a la cantidad, calidad y un peso extra que es unico de cada componente de fabricación de Dragonflight",
28 |
29 | -- Details Frame
30 | [CraftSim.CONST.TEXT.RECIPE_DIFFICULTY_LABEL] = "Dificultad de la receta: ",
31 | [CraftSim.CONST.TEXT.MULTICRAFT_LABEL] = "Multifabricación: ",
32 | [CraftSim.CONST.TEXT.RESOURCEFULNESS_LABEL] = "Inventiva: ",
33 | }
34 | end
35 |
--------------------------------------------------------------------------------
/DB/DB.lua:
--------------------------------------------------------------------------------
1 | ---@class CraftSim
2 | local CraftSim = select(2, ...)
3 |
4 | local GUTIL = CraftSim.GUTIL
5 |
6 | ---@class CraftSim.DB
7 | CraftSim.DB = {}
8 |
9 | ---@alias CrafterUID string Name-Server
10 | ---@alias RecipeID number
11 | ---@alias CooldownDataSerializationID RecipeID | CraftSim.SHARED_PROFESSION_COOLDOWNS
12 | ---@alias ItemID number
13 | ---@alias QualityID number between 1 and 5
14 |
15 | local print = CraftSim.DEBUG:RegisterDebugID("Database")
16 |
17 | ---@class CraftSim.DB.Repository
18 | ---@field Init function
19 | ---@field ClearAll function
20 | ---@field Migrate function
21 | ---@field CleanUp function
22 |
23 | ---@class CraftSimDB.Database
24 | ---@field version number
25 | ---@field data table
26 |
27 | ---@class CraftSimDB
28 | CraftSimDB = CraftSimDB or {}
29 |
30 | ---@type CraftSim.DB.Repository[]
31 | CraftSim.DB.repositories = {}
32 |
33 | ---@return CraftSim.DB.Repository
34 | function CraftSim.DB:RegisterRepository()
35 | ---@type CraftSim.DB.Repository
36 | local repository = {
37 | Init = function() end,
38 | Migrate = function() end,
39 | ClearAll = function() end,
40 | CleanUp = function() end,
41 | }
42 | tinsert(CraftSim.DB.repositories, repository)
43 | return repository
44 | end
45 |
46 | function CraftSim.DB:Init()
47 | for _, repository in ipairs(self.repositories) do
48 | repository:Init()
49 | repository:Migrate()
50 | repository:CleanUp()
51 | end
52 |
53 | CraftSim.DB:PostInitCleanUp()
54 | end
55 |
56 | function CraftSim.DB:PostInitCleanUp()
57 | if _G["CraftSimRecipeDataCache"] then
58 | _G["CraftSimRecipeDataCache"].cacheVersions = nil
59 | local empty = GUTIL:Count(_G["CraftSimRecipeDataCache"]) == 0
60 | if empty then
61 | _G["CraftSimRecipeDataCache"] = nil
62 | end
63 | end
64 |
65 | if _G["CraftSimDebugData"] then
66 | _G["CraftSimDebugData"] = nil
67 | end
68 | end
69 |
70 | function CraftSim.DB:ClearAll()
71 | for _, repository in ipairs(self.repositories) do
72 | repository:ClearAll()
73 | end
74 | end
75 |
76 | ---@param db CraftSimDB.Database
77 | ---@return fun(from: number, to:number, migrate: function)
78 | function CraftSim.DB:GetMigrateFunction(db)
79 | return function(from, to, migrate)
80 | if db.version == from then
81 | migrate()
82 | db.version = to
83 | end
84 | end
85 | end
86 |
--------------------------------------------------------------------------------
/Locals/esMX.lua:
--------------------------------------------------------------------------------
1 | ---@class CraftSim
2 | local CraftSim = select(2, ...)
3 | CraftSim.LOCAL_MX = {}
4 |
5 | function CraftSim.LOCAL_MX:GetData()
6 | local f = CraftSim.GUTIL:GetFormatter()
7 | return {
8 | -- REQUIRED:
9 | [CraftSim.CONST.TEXT.STAT_MULTICRAFT] = "Fabricación múltiple",
10 | [CraftSim.CONST.TEXT.STAT_RESOURCEFULNESS] = "Inventiva",
11 | [CraftSim.CONST.TEXT.STAT_INGENUITY] = "Ingenio",
12 | [CraftSim.CONST.TEXT.STAT_CRAFTINGSPEED] = "Velocidad de fabricación",
13 | [CraftSim.CONST.TEXT.EQUIP_MATCH_STRING] = "Equipar:",
14 | [CraftSim.CONST.TEXT.ENCHANTED_MATCH_STRING] = "Encantado:",
15 |
16 | -- OPTIONAL (Defaulting to EN if not available):
17 | -- Profit Breakdown Tooltips
18 |
19 | [CraftSim.CONST.TEXT.RECIPE_DIFFICULTY_EXPLANATION_TOOLTIP] =
20 | "Dificultad de la receta determina cuanta Habilidad es necesaria para fabricar la receta en cada calidad.\n\nPara recetas con cinco calidades es 20%, 50%, 80% y 100% de la Dificultad de la receta como Habilidad\nPara recetas con tres calidades es 50% y 100%",
21 | [CraftSim.CONST.TEXT.MULTICRAFT_EXPLANATION_TOOLTIP] =
22 | "Multifabricación da una probabilidad de fabricar mas objetos de los que normalmente fabricaría la receta.\n\nLa cantidad adicional es entre 1 y 2.5y\ndonde y = es la cantidad normal que da la fabricación.",
23 | [CraftSim.CONST.TEXT.RESOURCEFULNESS_EXPLANATION_TOOLTIP] =
24 | "Ingenio da una probabilidad POR MATERIAL de ahorrar de media un 30% de su cantidad.\n\nComo la probabilidad puede suceder por cada material individualmente hay muchas combinaciones posibles a considerar\ncomo que suceda en todos los materiales a la vez (la probabilidad de esto es muy muy baja)",
25 | [CraftSim.CONST.TEXT.REAGENTSKILL_EXPLANATION_TOOLTIP] =
26 | "La calidad de los componentes de fabricación puede otorgar hasta un maximo de un 25% de la Dificultad de la receta como Habilidad.\n\nTodos los componentes C1: 0% Bonus\nTodos los componentes C2: 12.5% Bonus\nTodos los componentes C3: 25% Bonus\n\nLa Habilidad es calculada en base a la cantidad, calidad y un peso extra que es unico de cada componente de fabricación de Dragonflight",
27 |
28 | -- Details Frame
29 | [CraftSim.CONST.TEXT.RECIPE_DIFFICULTY_LABEL] = "Dificultad de la receta: ",
30 | [CraftSim.CONST.TEXT.MULTICRAFT_LABEL] = "Fabricación múltiple: ",
31 | [CraftSim.CONST.TEXT.RESOURCEFULNESS_LABEL] = "Inventiva: ",
32 | }
33 | end
34 |
--------------------------------------------------------------------------------
/Classes/OnCraftData.lua:
--------------------------------------------------------------------------------
1 | ---@class CraftSim
2 | local CraftSim = select(2, ...)
3 |
4 | local GUTIL = CraftSim.GUTIL
5 |
6 | ---@class CraftSim.OnCraftData : CraftSim.CraftSimObject
7 | ---@overload fun(options: CraftSim.OnCraftData.Options): CraftSim.OnCraftData
8 | CraftSim.OnCraftData = CraftSim.CraftSimObject:extend()
9 |
10 | local print = CraftSim.DEBUG:RegisterDebugID("Classes.OnCraftData")
11 |
12 | ---@class CraftSim.OnCraftData.Options
13 | ---@field recipeID RecipeID
14 | ---@field amount number
15 | ---@field recipeLevel number?
16 | ---@field craftingReagentInfoTbl CraftingReagentInfo[]?
17 | ---@field itemTargetLocation ItemLocationMixin?
18 | ---@field itemGUID string? for recrafts
19 | ---@field isEnchant boolean?
20 | ---@field isRecraft boolean?
21 | ---@field orderData CraftingOrderInfo?
22 | ---@field concentrating boolean?
23 | ---@field callerData table
24 |
25 | ---@param options CraftSim.OnCraftData.Options
26 | function CraftSim.OnCraftData:new(options)
27 | self.recipeID = options.recipeID
28 | self.amount = options.amount or 1
29 | self.recipeLevel = options.recipeLevel
30 | self.craftingReagentInfoTbl = options.craftingReagentInfoTbl or {}
31 | self.itemTargetLocation = options.itemTargetLocation
32 | self.itemGUID = options.itemGUID
33 | self.isEnchant = options.isEnchant
34 | self.isRecraft = options.isRecraft
35 | self.orderData = options.orderData
36 | self.concentrating = options.concentrating
37 | --- for debug
38 | self.callerData = options.callerData
39 | end
40 |
41 | ---@return CraftSim.RecipeData
42 | function CraftSim.OnCraftData:CreateRecipeData()
43 | local recipeData = CraftSim.RecipeData({
44 | recipeID = self.recipeID,
45 | orderData = self.orderData,
46 | isRecraft = self.isRecraft,
47 | })
48 |
49 | recipeData:SetNonQualityReagentsMax()
50 | recipeData:SetReagentsByCraftingReagentInfoTbl(self.craftingReagentInfoTbl)
51 |
52 | recipeData:SetEquippedProfessionGearSet()
53 |
54 | recipeData.concentrating = self.concentrating
55 |
56 | if recipeData.isSalvageRecipe then
57 | -- itemTargetLocation HAS to be set
58 | local item = Item:CreateFromItemLocation(self.itemTargetLocation)
59 | --CraftSim.DEBUG:InspectTable(item or {}, "salvage - itemTargetLocation item")
60 | if item then
61 | recipeData:SetSalvageItem(item:GetItemID())
62 | end
63 | end
64 |
65 | if recipeData.isRecraft then
66 | recipeData.allocationItemGUID = self.itemGUID
67 | end
68 |
69 | recipeData:Update()
70 |
71 | return recipeData
72 | end
73 |
--------------------------------------------------------------------------------
/Classes/ProfessionData.lua:
--------------------------------------------------------------------------------
1 | ---@class CraftSim
2 | local CraftSim = select(2, ...)
3 |
4 | local GUTIL = CraftSim.GUTIL
5 |
6 | local print = CraftSim.DEBUG:RegisterDebugID("Classes.RecipeData.ProfessionData")
7 |
8 | ---@class CraftSim.ProfessionData.ConstructorOptions
9 | ---@field recipeData CraftSim.RecipeData
10 | ---@field forceCache? boolean
11 |
12 | ---@class CraftSim.ProfessionData : CraftSim.CraftSimObject
13 | ---@overload fun(options: CraftSim.ProfessionData.ConstructorOptions) : CraftSim.ProfessionData
14 | CraftSim.ProfessionData = CraftSim.CraftSimObject:extend()
15 |
16 | ---@param options CraftSim.ProfessionData.ConstructorOptions
17 | function CraftSim.ProfessionData:new(options)
18 | options = options or {}
19 | self.recipeData = options.recipeData
20 | local recipeID = self.recipeData.recipeID
21 | local crafterUID = self.recipeData:GetCrafterUID()
22 | local forceCache = options.forceCache or false
23 | -- if not the crafter get from cache, if not cached take data-less info
24 | if not self.recipeData:IsCrafter() or forceCache then
25 | self.professionInfo = CraftSim.DB.CRAFTER:GetProfessionInfoForRecipe(crafterUID, recipeID)
26 | if not self.professionInfo then
27 | self.professionInfo = C_TradeSkillUI.GetProfessionInfoByRecipeID(recipeID)
28 | self.professionInfoCached = false
29 | else
30 | self.professionInfoCached = true
31 | end
32 | else
33 | self.professionInfo = C_TradeSkillUI.GetProfessionInfoByRecipeID(recipeID)
34 |
35 | -- check if loaded
36 | if self.professionInfo.profession then
37 | -- save to db
38 | CraftSim.DB.CRAFTER:SaveProfessionInfoForRecipe(crafterUID, recipeID, self.professionInfo)
39 | else
40 | -- take from cache or take plain
41 | self.professionInfo = CraftSim.DB.CRAFTER:GetProfessionInfoForRecipe(crafterUID, recipeID)
42 |
43 | if not self.professionInfo then
44 | error("No professionInfo cached for " .. crafterUID .. ": " .. tostring(recipeID))
45 | end
46 | end
47 | end
48 | self.skillLineID = self.professionInfo.professionID
49 | self.configID = C_ProfSpecs.GetConfigIDForSkillLine(self.skillLineID)
50 | for expansionID, skillLineID in pairs(CraftSim.CONST.TRADESKILLLINEIDS[self.professionInfo.profession]) do
51 | if skillLineID == self.skillLineID then
52 | self.expansionID = expansionID
53 | break
54 | end
55 | end
56 | end
57 |
58 | function CraftSim.ProfessionData:UsesGear()
59 | return self.professionInfo.profession
60 | end
61 |
62 | function CraftSim.ProfessionData:GetJSON(indent)
63 | indent = indent or 0
64 | local jb = CraftSim.JSONBuilder(indent)
65 | jb:Begin()
66 | jb:Add("professionInfo", self.professionInfo)
67 | jb:Add("skillLineID", self.skillLineID, true)
68 | jb:End()
69 | return jb.json
70 | end
71 |
--------------------------------------------------------------------------------
/Classes/SalvageReagentSlot.lua:
--------------------------------------------------------------------------------
1 | ---@class CraftSim
2 | local CraftSim = select(2, ...)
3 |
4 | ---@class CraftSim.SalvageReagentSlot : CraftSim.CraftSimObject
5 | ---@overload fun(recipeData: CraftSim.RecipeData): CraftSim.SalvageReagentSlot
6 | CraftSim.SalvageReagentSlot = CraftSim.CraftSimObject:extend()
7 |
8 | ---@param recipeData CraftSim.RecipeData
9 | function CraftSim.SalvageReagentSlot:new(recipeData)
10 | ---@type ItemMixin[]
11 | self.possibleItems = {}
12 | local itemIDs = C_TradeSkillUI.GetSalvagableItemIDs(recipeData.recipeID)
13 | if itemIDs then
14 | self.possibleItems = CraftSim.GUTIL:Map(itemIDs, function(itemID) return Item:CreateFromItemID(itemID) end)
15 | self.requiredQuantity = 0
16 | end
17 |
18 | self.activeItem = nil
19 | self.recipeData = recipeData
20 | end
21 |
22 | ---@param itemID number
23 | function CraftSim.SalvageReagentSlot:SetItem(itemID)
24 | local item = CraftSim.GUTIL:Find(self.possibleItems, function(item) return item:GetItemID() == itemID end)
25 |
26 | if not item then
27 | error("Error CraftSim.SalvageReagentSlot: Trying to set item which is not in possible salvage item list")
28 | end
29 | ---@type ItemMixin?
30 | self.activeItem = item
31 | end
32 |
33 | function CraftSim.SalvageReagentSlot:Debug()
34 | local debugLines = {
35 | 'activeItem: ' .. (self.activeItem and (self.activeItem:GetItemLink() or self.activeItem:GetItemID()) or "None"),
36 | 'Possible Salvage Items: ',
37 | }
38 |
39 | for _, item in pairs(self.possibleItems) do
40 | table.insert(debugLines, "-" .. (item:GetItemLink() or item:GetItemID()))
41 | end
42 |
43 | return debugLines
44 | end
45 |
46 | function CraftSim.SalvageReagentSlot:GetJSON(indent)
47 | indent = indent or 0
48 | local jb = CraftSim.JSONBuilder(indent)
49 | jb:Begin()
50 | local itemList = {}
51 | table.foreach(self.possibleItems, function(_, item)
52 | table.insert(itemList, {
53 | itemID = item:GetItemID(),
54 | itemLink = item:GetItemLink()
55 | })
56 | end)
57 | jb:AddList("possibleReagents", itemList)
58 | if self.activeItem then
59 | jb:Add("activeItemID", self.activeItem:GetItemID())
60 | else
61 | jb:Add("activeItemID", nil)
62 | end
63 | jb:Add("requiredQuantity", self.requiredQuantity, true)
64 | jb:End()
65 | return jb.json
66 | end
67 |
68 | ---@return CraftSim.SalvageReagentSlot
69 | function CraftSim.SalvageReagentSlot:Copy()
70 | local copy = CraftSim.SalvageReagentSlot(self.recipeData)
71 | copy.activeItem = self.recipeData.reagentData.salvageReagentSlot.activeItem
72 | copy.requiredQuantity = self.requiredQuantity
73 | return copy
74 | end
75 |
--------------------------------------------------------------------------------
/Classes/CraftSessionData.lua:
--------------------------------------------------------------------------------
1 | ---@class CraftSim
2 | local CraftSim = select(2, ...)
3 |
4 | local print = CraftSim.DEBUG:RegisterDebugID("Classes.CraftSessionData")
5 |
6 | ---@class CraftSim.CraftSessionData : CraftSim.CraftSimObject
7 | ---@overload fun(): CraftSim.CraftSessionData
8 | CraftSim.CraftSessionData = CraftSim.CraftSimObject:extend()
9 |
10 | function CraftSim.CraftSessionData:new()
11 | self.totalProfit = 0
12 | self.numCrafts = 0
13 | ---@type CraftSim.CraftResultItem[]
14 | self.totalItems = {}
15 | ---@type CraftSim.CraftResultReagent[]
16 | self.totalReagents = {}
17 | ---@type CraftSim.CraftResultReagent[]
18 | self.totalSavedReagents = {}
19 | ---@type table
20 | self.craftRecipeData = {}
21 | ---@type CraftSim.CraftResult[]
22 | self.craftResults = {}
23 | end
24 |
25 | ---@param recipeID number
26 | ---@return CraftSim.CraftRecipeData craftRecipeData
27 | function CraftSim.CraftSessionData:GetCraftRecipeData(recipeID)
28 | self.craftRecipeData[recipeID] = self.craftRecipeData[recipeID] or CraftSim.CraftRecipeData(recipeID)
29 | return self.craftRecipeData[recipeID]
30 | end
31 |
32 | ---@param craftResult CraftSim.CraftResult
33 | ---@param enableAdvData boolean
34 | ---@param aNumCrafts number
35 | function CraftSim.CraftSessionData:AddCraftResult(craftResult, enableAdvData, aNumCrafts)
36 | print("SessionData: AddCraftResult")
37 | self.numCrafts = self.numCrafts + aNumCrafts
38 | table.insert(self.craftResults, craftResult)
39 |
40 | local craftGarbageCollectEnabled = CraftSim.DB.OPTIONS:Get("CRAFTING_GARBAGE_COLLECTION_ENABLED")
41 | local craftGarbageCollectCrafts = CraftSim.DB.OPTIONS:Get("CRAFTING_GARBAGE_COLLECTION_CRAFTS")
42 |
43 | -- if enabled and the correct number of modulo crafts -> collect garbage
44 | if craftGarbageCollectEnabled and craftGarbageCollectCrafts > 0 then
45 | if (self.numCrafts % craftGarbageCollectCrafts) == 0 then
46 | collectgarbage()
47 | end
48 | end
49 |
50 | self.totalProfit = self.totalProfit + craftResult.profit
51 |
52 | if enableAdvData then
53 | CraftSim.CRAFT_LOG:MergeCraftResultItemData(self.totalItems, craftResult.craftResultItems)
54 | CraftSim.CRAFT_LOG:MergeReagentsItemData(self.totalReagents, craftResult.reagents)
55 | CraftSim.CRAFT_LOG:MergeReagentsItemData(self.totalSavedReagents, craftResult.savedReagents)
56 | end
57 | end
58 |
59 | function CraftSim.CraftSessionData:GetJSON(intend)
60 | intend = intend or 0
61 | local jb = CraftSim.JSONBuilder(intend)
62 | jb:Begin()
63 | jb:Add("totalProfit", self.totalProfit)
64 | jb:Add("numCrafts", self.numCrafts)
65 | jb:AddList("totalItems", self.totalItems)
66 | jb:AddList("totalSavedReagents", self.totalSavedReagents)
67 | jb:AddList("craftRecipeData", self.craftRecipeData, true)
68 | jb:End()
69 | return jb.json
70 | end
71 |
--------------------------------------------------------------------------------
/DB/recipeSubCrafterDB.lua:
--------------------------------------------------------------------------------
1 | ---@class CraftSim
2 | local CraftSim = select(2, ...)
3 |
4 | local GUTIL = CraftSim.GUTIL
5 |
6 | ---@class CraftSim.DB
7 | CraftSim.DB = CraftSim.DB
8 |
9 | ---@class CraftSim.DB.RECIPE_SUB_CRAFTER : CraftSim.DB.Repository
10 | CraftSim.DB.RECIPE_SUB_CRAFTER = CraftSim.DB:RegisterRepository()
11 |
12 | local print = CraftSim.DEBUG:RegisterDebugID("Database.recipeSubCrafterDB")
13 |
14 | function CraftSim.DB.RECIPE_SUB_CRAFTER:Init()
15 | if not CraftSimDB.recipeSubCrafterDB then
16 | ---@type CraftSimDB.Database
17 | CraftSimDB.recipeSubCrafterDB = {
18 | version = 0,
19 | ---@type table
20 | data = {},
21 | }
22 | end
23 | CraftSimDB.recipeSubCrafterDB.data = CraftSimDB.recipeSubCrafterDB.data or {}
24 | end
25 |
26 | function CraftSim.DB.RECIPE_SUB_CRAFTER:Migrate()
27 | -- 0 -> 1
28 | if CraftSimDB.recipeSubCrafterDB.version == 0 then
29 | local CraftSimRecipeDataCache = _G["CraftSimRecipeDataCache"]
30 | if CraftSimRecipeDataCache then
31 | CraftSimDB.recipeSubCrafterDB.data = CraftSimRecipeDataCache["subRecipeCrafterCache"] or {}
32 | end
33 | CraftSimDB.recipeSubCrafterDB.version = 1
34 | end
35 |
36 | -- 1 -> 2 (16.1.2 -> 16.1.3)
37 | if CraftSimDB.recipeSubCrafterDB.version == 1 then
38 | -- remove any crafter entries with colored names...
39 | for itemID, crafterUID in pairs(CraftSimDB.recipeSubCrafterDB.data or {}) do
40 | if string.find(crafterUID, '\124c') then
41 | CraftSimDB.recipeSubCrafterDB.data[itemID] = nil
42 | end
43 | end
44 |
45 | CraftSimDB.recipeSubCrafterDB.version = 2
46 | end
47 |
48 | -- reset for tww refactor
49 | if CraftSimDB.recipeSubCrafterDB.version == 2 then
50 | self:ClearAll()
51 | CraftSimDB.recipeSubCrafterDB.version = 3
52 | end
53 | end
54 |
55 | function CraftSim.DB.RECIPE_SUB_CRAFTER:ClearAll()
56 | wipe(CraftSimDB.recipeSubCrafterDB.data)
57 | end
58 |
59 | function CraftSim.DB.RECIPE_SUB_CRAFTER:CleanUp()
60 | local CraftSimRecipeDataCache = _G["CraftSimRecipeDataCache"]
61 | if CraftSimRecipeDataCache and CraftSimRecipeDataCache["subRecipeCrafterCache"] then
62 | CraftSimRecipeDataCache["subRecipeCrafterCache"] = nil
63 | end
64 | end
65 |
66 | ---@param recipeID RecipeID
67 | ---@return CrafterUID crafterUID?
68 | function CraftSim.DB.RECIPE_SUB_CRAFTER:GetCrafter(recipeID)
69 | return CraftSimDB.recipeSubCrafterDB.data[recipeID]
70 | end
71 |
72 | ---@param recipeID RecipeID
73 | ---@param crafterUID CrafterUID
74 | ---@return boolean
75 | function CraftSim.DB.RECIPE_SUB_CRAFTER:IsCrafter(recipeID, crafterUID)
76 | return crafterUID == CraftSimDB.recipeSubCrafterDB.data[recipeID]
77 | end
78 |
79 | ---@param recipeID RecipeID
80 | ---@param crafterUID CrafterUID
81 | function CraftSim.DB.RECIPE_SUB_CRAFTER:SetCrafter(recipeID, crafterUID)
82 | CraftSimDB.recipeSubCrafterDB.data[recipeID] = crafterUID
83 | end
84 |
--------------------------------------------------------------------------------
/Libs/LibStub/tests/test.lua:
--------------------------------------------------------------------------------
1 | debugstack = debug.traceback
2 | strmatch = string.match
3 |
4 | loadfile("../LibStub.lua")()
5 |
6 | local lib, oldMinor = LibStub:NewLibrary("Pants", 1) -- make a new thingy
7 | assert(lib) -- should return the library table
8 | assert(not oldMinor) -- should not return the old minor, since it didn't exist
9 |
10 | -- the following is to create data and then be able to check if the same data exists after the fact
11 | function lib:MyMethod()
12 | end
13 |
14 | local MyMethod = lib.MyMethod
15 | lib.MyTable = {}
16 | local MyTable = lib.MyTable
17 |
18 | local newLib, newOldMinor = LibStub:NewLibrary("Pants", 1) -- try to register a library with the same version, should silently fail
19 | assert(not newLib) -- should not return since out of date
20 |
21 | local newLib, newOldMinor = LibStub:NewLibrary("Pants", 0) -- try to register a library with a previous, should silently fail
22 | assert(not newLib) -- should not return since out of date
23 |
24 | local newLib, newOldMinor = LibStub:NewLibrary("Pants", 2) -- register a new version
25 | assert(newLib) -- library table
26 | assert(rawequal(newLib, lib)) -- should be the same reference as the previous
27 | assert(newOldMinor == 1) -- should return the minor version of the previous version
28 |
29 | assert(rawequal(lib.MyMethod, MyMethod)) -- verify that values were saved
30 | assert(rawequal(lib.MyTable, MyTable)) -- verify that values were saved
31 |
32 | local newLib, newOldMinor = LibStub:NewLibrary("Pants", "Blah 3 Blah") -- register a new version with a string minor version (instead of a number)
33 | assert(newLib) -- library table
34 | assert(newOldMinor == 2) -- previous version was 2
35 |
36 | local newLib, newOldMinor = LibStub:NewLibrary("Pants", "Blah 4 and please ignore 15 Blah") -- register a new version with a string minor version (instead of a number)
37 | assert(newLib)
38 | assert(newOldMinor == 3) -- previous version was 3 (even though it gave a string)
39 |
40 | local newLib, newOldMinor = LibStub:NewLibrary("Pants", 5) -- register a new library, using a normal number instead of a string
41 | assert(newLib)
42 | assert(newOldMinor == 4) -- previous version was 4 (even though it gave a string)
43 |
--------------------------------------------------------------------------------
/Libs/LibCompress/LibStub/tests/test.lua:
--------------------------------------------------------------------------------
1 | debugstack = debug.traceback
2 | strmatch = string.match
3 |
4 | loadfile("../LibStub.lua")()
5 |
6 | local lib, oldMinor = LibStub:NewLibrary("Pants", 1) -- make a new thingy
7 | assert(lib) -- should return the library table
8 | assert(not oldMinor) -- should not return the old minor, since it didn't exist
9 |
10 | -- the following is to create data and then be able to check if the same data exists after the fact
11 | function lib:MyMethod()
12 | end
13 |
14 | local MyMethod = lib.MyMethod
15 | lib.MyTable = {}
16 | local MyTable = lib.MyTable
17 |
18 | local newLib, newOldMinor = LibStub:NewLibrary("Pants", 1) -- try to register a library with the same version, should silently fail
19 | assert(not newLib) -- should not return since out of date
20 |
21 | local newLib, newOldMinor = LibStub:NewLibrary("Pants", 0) -- try to register a library with a previous, should silently fail
22 | assert(not newLib) -- should not return since out of date
23 |
24 | local newLib, newOldMinor = LibStub:NewLibrary("Pants", 2) -- register a new version
25 | assert(newLib) -- library table
26 | assert(rawequal(newLib, lib)) -- should be the same reference as the previous
27 | assert(newOldMinor == 1) -- should return the minor version of the previous version
28 |
29 | assert(rawequal(lib.MyMethod, MyMethod)) -- verify that values were saved
30 | assert(rawequal(lib.MyTable, MyTable)) -- verify that values were saved
31 |
32 | local newLib, newOldMinor = LibStub:NewLibrary("Pants", "Blah 3 Blah") -- register a new version with a string minor version (instead of a number)
33 | assert(newLib) -- library table
34 | assert(newOldMinor == 2) -- previous version was 2
35 |
36 | local newLib, newOldMinor = LibStub:NewLibrary("Pants", "Blah 4 and please ignore 15 Blah") -- register a new version with a string minor version (instead of a number)
37 | assert(newLib)
38 | assert(newOldMinor == 3) -- previous version was 3 (even though it gave a string)
39 |
40 | local newLib, newOldMinor = LibStub:NewLibrary("Pants", 5) -- register a new library, using a normal number instead of a string
41 | assert(newLib)
42 | assert(newOldMinor == 4) -- previous version was 4 (even though it gave a string)
43 |
--------------------------------------------------------------------------------
/Classes/JSONBuilder.lua:
--------------------------------------------------------------------------------
1 | ---@class CraftSim
2 | local CraftSim = select(2, ...)
3 |
4 |
5 | ---@class CraftSim.JSONBuilder : CraftSim.CraftSimObject
6 | ---@overload fun(indent:number?):CraftSim.JSONBuilder
7 | CraftSim.JSONBuilder = CraftSim.CraftSimObject:extend()
8 |
9 | ---@param indent number?
10 | function CraftSim.JSONBuilder:new(indent)
11 | self.indent = indent or 0
12 | self.json = ""
13 | end
14 |
15 | function CraftSim.JSONBuilder:Begin()
16 | self.json = self:GetIndent() .. "{\n"
17 | end
18 |
19 | function CraftSim.JSONBuilder:End(sep)
20 | sep = sep or ""
21 | self.json = self.json .. "\n" .. self:GetIndent() .. "}" .. sep
22 | end
23 |
24 | ---@return string indentSpaces
25 | function CraftSim.JSONBuilder:GetIndent(extra)
26 | extra = extra or 0
27 | local int = self.indent + extra
28 | local spaces = ""
29 | for i = 1, int, 1 do
30 | spaces = spaces .. " "
31 | end
32 | return spaces
33 | end
34 |
35 | function CraftSim.JSONBuilder:AddList(name, list, last)
36 | local sep = (not last and ",\n") or ""
37 | local jsonList = self:GetIndent(1) .. "\"" .. name .. "\": [\n"
38 |
39 | local numListEntries = CraftSim.GUTIL:Count(list)
40 | local index = 1
41 | for _, listItem in pairs(list) do
42 | local subSep = (index == numListEntries and "") or ",\n"
43 | if type(listItem) == 'table' and listItem.GetJSON then
44 | jsonList = jsonList .. self:GetIndent(2) .. listItem:GetJSON(self.indent + 3) .. subSep
45 | else
46 | local strEncase = (type(listItem) == 'string' and "\"") or ""
47 | jsonList = jsonList .. self:GetIndent(2) .. strEncase .. tostring(listItem) .. strEncase .. subSep
48 | end
49 | index = index + 1
50 | end
51 |
52 | jsonList = jsonList .. "\n" .. self:GetIndent(1) .. "]" .. sep
53 |
54 | self.json = self.json .. jsonList
55 | end
56 |
57 | function CraftSim.JSONBuilder:Add(name, data, last)
58 | local strEncase = (type(data) == 'string' and "\"") or ""
59 | local sep = (not last and ",\n") or ""
60 | if type(data) == 'table' and data.GetJSON then
61 | self.json = self.json ..
62 | self:GetIndent(1) .. "\"" .. name .. "\": " .. strEncase .. data:GetJSON(self.indent + 1) .. strEncase .. sep
63 | elseif type(data) == 'table' then
64 | self.json = self.json .. self:GetIndent(1) .. "\"" .. name .. '\": {\n'
65 | local index = 1
66 | local numData = CraftSim.GUTIL:Count(data)
67 | for key, value in pairs(data) do
68 | local sep = (index ~= numData and ",\n") or ""
69 | local strEncase = (type(value) == 'string' and "\"") or ""
70 | local valueText = (type(value) == 'table' and 'Table') or tostring(value)
71 | self.json = self.json ..
72 | self:GetIndent(3) .. "\"" .. key .. "\": " .. strEncase .. valueText .. strEncase .. sep
73 | index = index + 1
74 | end
75 | self.json = self.json .. self:GetIndent(2) .. '\n}' .. sep
76 | else
77 | self.json = self.json ..
78 | self:GetIndent(1) .. "\"" .. name .. "\": " .. strEncase .. tostring(data) .. strEncase .. sep
79 | end
80 | end
81 |
--------------------------------------------------------------------------------
/DevTools/DataScripts/ConcentrationCurveData/mapper.py:
--------------------------------------------------------------------------------
1 | import sys
2 | sys.path.append('../')
3 | import wagoTools
4 | import shutil
5 |
6 | wagoTables = ["CraftingData", "CraftingDifficulty", "CurvePoint"]
7 |
8 | def copy(buildVersion):
9 | shutil.copy(f"Result/{buildVersion}/ConcentrationCurveData.lua", "../../../Data/ConcentrationCurveData.lua")
10 |
11 | def map(download, buildVersion):
12 | csvTables = wagoTools.getWagoTables(wagoTables, download, buildVersion)
13 | craftingDataTable = csvTables[0]
14 | craftingDifficultyTable = csvTables[1]
15 | curvePointTable = csvTables[2]
16 |
17 | concentrationCostDataTable = {}
18 |
19 | print("Mapping Concentration Curve Data")
20 |
21 | counter = 0
22 | total = len(craftingDataTable)
23 | for craftingData in craftingDataTable:
24 | counter = counter + 1
25 | craftingDataID = int(craftingData["ID"])
26 | craftingDifficultyID = craftingData["CraftingDifficultyID"]
27 | wagoTools.updateProgressBar(counter, total, craftingDataID)
28 | for craftingDifficulty in craftingDifficultyTable:
29 | if craftingDifficulty["ID"] == craftingDifficultyID:
30 | curveID = craftingDifficulty["ConcentrationSkillCurveID"]
31 | constantCurveID = craftingDifficulty["ConcentrationDifficultyCurveID"]
32 |
33 | if craftingDataID not in concentrationCostDataTable:
34 | concentrationCostDataTable[craftingDataID] = {
35 | "costConstantData": {},
36 | "curveData": {}
37 | }
38 |
39 | for curvePoint in curvePointTable:
40 | if curvePoint["CurveID"] == constantCurveID:
41 | if curvePoint["Pos_0"] is not None:
42 | if curvePoint["Pos_1"] is not None:
43 |
44 | recipeDifficultyThreshold = float(curvePoint["Pos_0"])
45 | multiplier = float(curvePoint["Pos_1"])
46 |
47 | concentrationCostDataTable[craftingDataID]["costConstantData"][recipeDifficultyThreshold] = multiplier
48 |
49 | for curvePoint in curvePointTable:
50 | if curvePoint["CurveID"] == curveID:
51 | if curvePoint["Pos_0"] is not None:
52 | if curvePoint["Pos_1"] is not None:
53 |
54 | recipeDifficultyThreshold = float(curvePoint["Pos_0"]) / 100
55 | skillCurveValue = float(curvePoint["Pos_1"])
56 |
57 | concentrationCostDataTable[craftingDataID]["curveData"][recipeDifficultyThreshold] = skillCurveValue
58 |
59 | wagoTools.writeLuaTable(concentrationCostDataTable, "ConcentrationCurveData", "---@class CraftSim\nlocal CraftSim = select(2, ...)\nCraftSim.CONCENTRATION_CURVE_DATA = ", buildVersion)
60 |
61 | def update(buildVersion):
62 | map(True, buildVersion)
63 | copy(buildVersion)
64 |
65 | if __name__ == '__main__':
66 | args = sys.argv[1:]
67 | buildVersion = (len(args) > 0 and args[0])
68 |
69 | update(buildVersion)
70 |
--------------------------------------------------------------------------------
/Modules/Statistics/Statistics.lua:
--------------------------------------------------------------------------------
1 | ---@class CraftSim
2 | local CraftSim = select(2, ...)
3 |
4 | ---@class CraftSim.STATISTICS
5 | CraftSim.STATISTICS = {}
6 |
7 | ---@type GGUI.Frame
8 | CraftSim.STATISTICS.frameNO_WO = nil
9 | ---@type GGUI.Frame
10 | CraftSim.STATISTICS.frameWO = nil
11 |
12 | local print = CraftSim.DEBUG:RegisterDebugID("Modules.Statistics")
13 |
14 | -- https://math.stackexchange.com/questions/888165/abramowitz-and-stegun-approximation-for-cumulative-normal-distribution
15 | function CraftSim.STATISTICS:CDF(q, mu, sd)
16 | local function Phi(z)
17 | local pdfx = 1 / (math.sqrt(2 * math.pi)) * math.exp(-z * z / 2)
18 | local t = 1 / (1 + 0.2316419 * z)
19 | return (1 - pdfx * (0.319381530 * t - 0.356563782 * t ^ 2
20 | + 1.781477937 * t ^ 3 - 1.821255978 * t ^ 4 + 1.330274429 * t ^ 5))
21 | end
22 |
23 | local zValue = (q - mu) / sd
24 |
25 | local phi_Z = Phi(zValue)
26 | if phi_Z <= 0.0001 then -- catch the case of it returning wierd stuff
27 | return 1
28 | elseif phi_Z >= 1 then
29 | return 0
30 | end
31 | return phi_Z
32 | end
33 |
34 | function CraftSim.STATISTICS:GetProbabilityOfPositiveProfitByCrafts(probabilityTable, numCrafts)
35 | local meanOneCraft = 0
36 |
37 | probabilityTable = CraftSim.GUTIL:Filter(probabilityTable, function(entry)
38 | return entry.chance > 0
39 | end)
40 |
41 | local allNegative = true
42 | local allPositive = true
43 | for _, probability in pairs(probabilityTable) do
44 | meanOneCraft = meanOneCraft + (probability.profit * probability.chance)
45 | if probability.profit > 0 then
46 | allNegative = false
47 | end
48 | if probability.profit <= 0 then
49 | allPositive = false
50 | end
51 | end
52 |
53 | if allPositive then
54 | return 1
55 | end
56 |
57 | if allNegative then
58 | return 0
59 | end
60 |
61 |
62 |
63 | local standardDeviation = 0
64 |
65 | for _, probability in pairs(probabilityTable) do
66 | standardDeviation = standardDeviation + (probability.profit - meanOneCraft) ^ 2
67 | end
68 |
69 | standardDeviation = standardDeviation / #probabilityTable
70 |
71 | standardDeviation = math.sqrt(standardDeviation)
72 | local standardDeviationNumCrafts = math.sqrt(numCrafts) * standardDeviation
73 | local meanNumCrafts = meanOneCraft * numCrafts
74 |
75 | print("mean (profit) of 1 craft: " .. CraftSim.UTIL:FormatMoney(meanOneCraft, true))
76 | print("mean (profit) of " .. numCrafts .. " crafts: " .. CraftSim.UTIL:FormatMoney(meanNumCrafts, true))
77 | print("standardDeviation 1 craft: " .. CraftSim.UTIL:FormatMoney(standardDeviation, true))
78 | print("standardDeviation " .. numCrafts ..
79 | " crafts: " .. CraftSim.UTIL:FormatMoney(standardDeviationNumCrafts, true))
80 |
81 |
82 | -- CDF:
83 | -- test override:
84 | --meanNumCrafts = 5
85 | --standardDeviationNumCrafts = 1
86 |
87 | print("CDF of: " .. tostring(meanNumCrafts) .. ", " .. tostring(standardDeviationNumCrafts))
88 | local cdfResult = CraftSim.STATISTICS:CDF(0, meanNumCrafts, standardDeviationNumCrafts)
89 | print("result: " .. tostring(cdfResult))
90 |
91 | -- get probability of x or higher:
92 | local chanceOfHavingHigher = 1 - cdfResult
93 |
94 | print("chance for profit > 0 after crafts: " .. tostring(chanceOfHavingHigher))
95 |
96 | return chanceOfHavingHigher
97 | end
98 |
--------------------------------------------------------------------------------
/Libs/LibDBIcon-1.0/LibDataBroker-1.1/LibDataBroker-1.1.lua:
--------------------------------------------------------------------------------
1 | assert(LibStub, "LibDataBroker-1.1 requires LibStub")
2 | assert(LibStub:GetLibrary("CallbackHandler-1.0", true), "LibDataBroker-1.1 requires CallbackHandler-1.0")
3 |
4 | local lib, oldminor = LibStub:NewLibrary("LibDataBroker-1.1", 4)
5 | if not lib then return end
6 | oldminor = oldminor or 0
7 |
8 |
9 | lib.callbacks = lib.callbacks or LibStub:GetLibrary("CallbackHandler-1.0"):New(lib)
10 | lib.attributestorage, lib.namestorage, lib.proxystorage = lib.attributestorage or {}, lib.namestorage or {},
11 | lib.proxystorage or {}
12 | local attributestorage, namestorage, callbacks = lib.attributestorage, lib.namestorage, lib.callbacks
13 |
14 | if oldminor < 2 then
15 | lib.domt = {
16 | __metatable = "access denied",
17 | __index = function(self, key) return attributestorage[self] and attributestorage[self][key] end,
18 | }
19 | end
20 |
21 | if oldminor < 3 then
22 | lib.domt.__newindex = function(self, key, value)
23 | if not attributestorage[self] then attributestorage[self] = {} end
24 | if attributestorage[self][key] == value then return end
25 | attributestorage[self][key] = value
26 | local name = namestorage[self]
27 | if not name then return end
28 | callbacks:Fire("LibDataBroker_AttributeChanged", name, key, value, self)
29 | callbacks:Fire("LibDataBroker_AttributeChanged_" .. name, name, key, value, self)
30 | callbacks:Fire("LibDataBroker_AttributeChanged_" .. name .. "_" .. key, name, key, value, self)
31 | callbacks:Fire("LibDataBroker_AttributeChanged__" .. key, name, key, value, self)
32 | end
33 | end
34 |
35 | if oldminor < 2 then
36 | function lib:NewDataObject(name, dataobj)
37 | if self.proxystorage[name] then return end
38 |
39 | if dataobj then
40 | assert(type(dataobj) == "table", "Invalid dataobj, must be nil or a table")
41 | self.attributestorage[dataobj] = {}
42 | for i, v in pairs(dataobj) do
43 | self.attributestorage[dataobj][i] = v
44 | dataobj[i] = nil
45 | end
46 | end
47 | dataobj = setmetatable(dataobj or {}, self.domt)
48 | self.proxystorage[name], self.namestorage[dataobj] = dataobj, name
49 | self.callbacks:Fire("LibDataBroker_DataObjectCreated", name, dataobj)
50 | return dataobj
51 | end
52 | end
53 |
54 | if oldminor < 1 then
55 | function lib:DataObjectIterator()
56 | return pairs(self.proxystorage)
57 | end
58 |
59 | function lib:GetDataObjectByName(dataobjectname)
60 | return self.proxystorage[dataobjectname]
61 | end
62 |
63 | function lib:GetNameByDataObject(dataobject)
64 | return self.namestorage[dataobject]
65 | end
66 | end
67 |
68 | if oldminor < 4 then
69 | local next = pairs(attributestorage)
70 | function lib:pairs(dataobject_or_name)
71 | local t = type(dataobject_or_name)
72 | assert(t == "string" or t == "table", "Usage: ldb:pairs('dataobjectname') or ldb:pairs(dataobject)")
73 |
74 | local dataobj = self.proxystorage[dataobject_or_name] or dataobject_or_name
75 | assert(attributestorage[dataobj], "Data object not found")
76 |
77 | return next, attributestorage[dataobj], nil
78 | end
79 |
80 | local ipairs_iter = ipairs(attributestorage)
81 | function lib:ipairs(dataobject_or_name)
82 | local t = type(dataobject_or_name)
83 | assert(t == "string" or t == "table", "Usage: ldb:ipairs('dataobjectname') or ldb:ipairs(dataobject)")
84 |
85 | local dataobj = self.proxystorage[dataobject_or_name] or dataobject_or_name
86 | assert(attributestorage[dataobj], "Data object not found")
87 |
88 | return ipairs_iter, attributestorage[dataobj], 0
89 | end
90 | end
91 |
--------------------------------------------------------------------------------
/DevTools/DataScripts/wagoTools.py:
--------------------------------------------------------------------------------
1 | import httpx
2 | import os
3 | import luadata
4 | import csv
5 |
6 | dataDirectoryPrefix = "Data/"
7 | resultDirectoryPrefix = "Result/"
8 | latestDirectoryPrefix = "Latest/"
9 |
10 | # just a utility to make it easier to wait ;D
11 | def updateProgressBar(progress, total, label=""):
12 | percent = 100 * (progress / float(total))
13 | bar = '█' * int(percent) + '-' * (100 - int(percent))
14 | print(f"\r|{bar}| {percent:.2f}% {label}", end=' \r')
15 |
16 | def getBuildDirectoryPrefix(buildVersion=None):
17 | if buildVersion:
18 | return f"{buildVersion}/"
19 | return latestDirectoryPrefix
20 |
21 | def downloadWagoTablesCSV(wagoTables, buildVersion=None):
22 | count = 0
23 | total = len(wagoTables)
24 | for table in wagoTables:
25 | count = count + 1
26 | filename = f"{dataDirectoryPrefix}{getBuildDirectoryPrefix(buildVersion)}{table}.csv"
27 | os.makedirs(os.path.dirname(filename), exist_ok=True)
28 | if os.path.isfile(filename):
29 | print("File already exists, skipping download: " + filename)
30 | continue
31 | updateProgressBar(count, total, table)
32 | buildParameter = f"?build={buildVersion}"
33 | if buildVersion == None:
34 | buildParameter = ""
35 | download = httpx.get(f"https://wago.tools/db2/{table}/csv{buildParameter}")
36 | decoded_content = download.content.decode('utf-8')
37 | with open(filename, 'w', errors="replace") as f:
38 | f.writelines(decoded_content)
39 |
40 | def loadCSVTables(wagoTables, buildVersion=None):
41 | csvTables = []
42 | for table in wagoTables:
43 | print(f"Loading {table}: ", end='')
44 | filename = f"{dataDirectoryPrefix}{getBuildDirectoryPrefix(buildVersion)}{table}.csv"
45 | with open(filename, mode='r') as file:
46 | csv_reader = csv.DictReader(file)
47 | data_table = []
48 | for row in csv_reader:
49 | data_table.append(row)
50 | csvTables.append(data_table)
51 | print(f"- Size: {str(len(data_table))}")
52 | return csvTables
53 |
54 | def getWagoTables(wagoTables, download, buildVersion=None):
55 | if download:
56 | print("Downloading Tables")
57 | downloadWagoTablesCSV(wagoTables, buildVersion)
58 | print("Loading Tables")
59 | return loadCSVTables(wagoTables, buildVersion)
60 |
61 | # searchTerms: {multiple: boolean, conditions: dict}
62 | def searchTable(table, searchTerms):
63 | singleResult = ("singleResult" in searchTerms) and searchTerms["singleResult"]
64 | conditions = searchTerms["conditions"]
65 |
66 | results = []
67 |
68 | for row in table:
69 | match = True
70 | for key, value in conditions.items():
71 | if row[key] != value:
72 | match = False
73 | if match:
74 | results.append(row)
75 | if singleResult:
76 | return row
77 |
78 | if singleResult:
79 | return None
80 |
81 | return results
82 |
83 | def copyResult(file, destination):
84 | shutil.copy(file, destination)
85 |
86 | def writeLuaTable(dataTable, fileName, prefix, buildVersion=None, silent=False):
87 | if not silent: print(f"\nWriting Lua File: {fileName}")
88 | fileName = f"{resultDirectoryPrefix}{getBuildDirectoryPrefix(buildVersion)}{fileName}.lua"
89 | os.makedirs(os.path.dirname(fileName), exist_ok=True)
90 | luadata.write(fileName, dataTable, encoding="utf-8", indent="\t", prefix=prefix)
--------------------------------------------------------------------------------
/Util/API_README.md:
--------------------------------------------------------------------------------
1 | # **CraftSim Ingame API**
2 |
3 | ## *CraftSimAPI:GetRecipeData(options)*
4 |
5 | This lets you fetch a RecipeData instance for a recipeID.
6 | This object represents a recipe in CraftSim and offers various methods to manipulate the recipe or extract information from.
7 | It is implemented in [RecipeData.lua](../Data/Classes/RecipeData.lua)
8 | The parameter options refers to a table containing the constructor options (See declaration above RecipeData:new)
9 |
10 | ## *CraftSimAPI:GetOpenRecipeData()*
11 |
12 | This lets you fetch the RecipeData instance for the currently opened recipe
13 | See [RecipeData.lua](../Data/Classes/RecipeData.lua)
14 |
15 | ### recipeData:Update()
16 |
17 | This processes all changes done to the recipeData and updates its resultData and professionStats.
18 | It is important to call this after you change professionGearSet or reagentData. Some methods call it automatically.
19 |
20 | ### recipeData:OptimizeProfit() _(Depricated)_
21 |
22 | Optimizes reagentData and professionGearSet in order to achieve the highest possible profit for this recipe. Automatically calls Update().
23 |
24 | Automatically calls Update()
25 |
26 | ### recipeData:GetAverageProfit()
27 |
28 | Calculates the average profit based on professionGearSet, reagentData, resultData and professionStats.
29 |
30 | It has two return values. The first is the average profit in copper and the second is a table containing the 'Proc to Profit' probability distribution of the recipe.
31 |
32 | ### recipeData:OptimizeGear(mode: string)
33 |
34 | Optimizes professionGearSet based on the given mode. Automatically calls Update() if a better professionGearSet was set.
35 | Possible modes are
36 | - "Top Profit"
37 | - "Top Skill"
38 | - "Top Multicraft"
39 | - "Top Resourcefulness"
40 | - "Top Crafting Speed"
41 |
42 | ### recipeData:OptimizeReagents()
43 |
44 | Optimizes the quality based required reagents for highest achievable quality with lowest cost.
45 |
46 | Automatically calls Update()
47 |
48 | ### recipeData:SetAllReagentsBySchematicForm()
49 |
50 | This sets all required and optional reagents based on the set reagents in the visible default blizzard crafting GUI.
51 |
52 | ### recipeData:SetConcentrationBySchematicForm()
53 |
54 | Toggle the concentrating property of the recipe based on the visible default blizzard crafting GUI
55 |
56 | ### recipeData:SetOptionalReagents(itemIDList: number[])
57 |
58 | Takes a list of itemIDs of optional reagents which will, if available, be set as active in the reagentData.
59 | Automatically calls Update()
60 |
61 | ### recipeData:SetReagents(reagentList: ReagentListItem[])
62 |
63 | Takes a list of *ReagentListItem* objects to set the required reagents of the recipe. Per default all quality based reagents are set to quantity 0 and all non quality reagents are set to their required quantity.
64 |
65 | #### ReagentListItem
66 | {
67 | itemID: number,
68 | quantity: number
69 | }
70 |
71 | ### recipeData:SetEquippedProfessionGearSet()
72 |
73 | Sets the recipeData's professionGearSet to the currently equipped profession gear for this recipe's profession.
74 | Automatically calls Update()
75 |
76 |
77 | ### Example
78 |
79 | An example that uses CraftSim's API to fetch a recipeData object, optimizes gear and reagents for profit and then prints the resulting profit
80 |
81 | local recipeData = CraftSimAPI:GetRecipeData( { recipeID = 367713 } )
82 | recipeData:OptimizeProfit()
83 | local averageProfit = recipeData:GetAverageProfit()
84 | print(averageProfit)
85 |
86 | ### More Functionality and Methods
87 | More can be found in the RecipeData class
--------------------------------------------------------------------------------
/Locals/Localization.lua:
--------------------------------------------------------------------------------
1 | ---@class CraftSim
2 | local CraftSim = select(2, ...)
3 |
4 | CraftSim.LOCAL = {}
5 | CraftSim.LOCAL.LOCAL_CLIENT = {}
6 | CraftSim.LOCAL.LOCAL_EN = {}
7 |
8 | function CraftSim.LOCAL:Init()
9 | local currentLocale = GetLocale()
10 | CraftSim.LOCAL.LOCAL_EN = CraftSim.LOCAL_EN:GetData() -- always load english locals for fallback translations
11 | if currentLocale == CraftSim.CONST.LOCALES.EN then
12 | CraftSim.LOCAL.LOCAL_CLIENT = CraftSim.LOCAL.LOCAL_EN
13 | elseif currentLocale == CraftSim.CONST.LOCALES.DE then
14 | CraftSim.LOCAL.LOCAL_CLIENT = CraftSim.LOCAL_DE:GetData()
15 | elseif currentLocale == CraftSim.CONST.LOCALES.IT then
16 | CraftSim.LOCAL.LOCAL_CLIENT = CraftSim.LOCAL_IT:GetData()
17 | elseif currentLocale == CraftSim.CONST.LOCALES.RU then
18 | CraftSim.LOCAL.LOCAL_CLIENT = CraftSim.LOCAL_RU:GetData()
19 | elseif currentLocale == CraftSim.CONST.LOCALES.PT then
20 | CraftSim.LOCAL.LOCAL_CLIENT = CraftSim.LOCAL_PT:GetData()
21 | elseif currentLocale == CraftSim.CONST.LOCALES.ES then
22 | CraftSim.LOCAL.LOCAL_CLIENT = CraftSim.LOCAL_ES:GetData()
23 | elseif currentLocale == CraftSim.CONST.LOCALES.FR then
24 | CraftSim.LOCAL.LOCAL_CLIENT = CraftSim.LOCAL_FR:GetData()
25 | elseif currentLocale == CraftSim.CONST.LOCALES.MX then
26 | CraftSim.LOCAL.LOCAL_CLIENT = CraftSim.LOCAL_MX:GetData()
27 | elseif currentLocale == CraftSim.CONST.LOCALES.KO then
28 | CraftSim.LOCAL.LOCAL_CLIENT = CraftSim.LOCAL_KO:GetData()
29 | elseif currentLocale == CraftSim.CONST.LOCALES.TW then
30 | CraftSim.LOCAL.LOCAL_CLIENT = CraftSim.LOCAL_TW:GetData()
31 | elseif currentLocale == CraftSim.CONST.LOCALES.CN then
32 | CraftSim.LOCAL.LOCAL_CLIENT = CraftSim.LOCAL_CN:GetData()
33 | else
34 | error("CraftSim Error: Client not supported: " .. tostring(currentLocale))
35 | end
36 | end
37 |
38 | ---@param ID CraftSim.LOCALIZATION_IDS
39 | function CraftSim.LOCAL:GetText(ID)
40 | local localizedText = CraftSim.LOCAL.LOCAL_CLIENT[ID]
41 |
42 | if not localizedText then
43 | local englishtext = CraftSim.LOCAL.LOCAL_EN[ID]
44 | return englishtext -- default to english
45 | else
46 | return localizedText
47 | end
48 | end
49 |
50 | function CraftSim.LOCAL:TranslateStatName(statName)
51 | -- translate the variable name to the display name
52 | if statName == "multicraft" then
53 | return CraftSim.LOCAL:GetText(CraftSim.CONST.TEXT.STAT_MULTICRAFT)
54 | elseif statName == "resourcefulness" then
55 | return CraftSim.LOCAL:GetText(CraftSim.CONST.TEXT.STAT_RESOURCEFULNESS)
56 | elseif statName == "craftingspeed" then
57 | return CraftSim.LOCAL:GetText(CraftSim.CONST.TEXT.STAT_CRAFTINGSPEED)
58 | elseif statName == "skill" then
59 | return CraftSim.LOCAL:GetText(CraftSim.CONST.TEXT.STAT_SKILL)
60 | elseif statName == "multicraftExtraItemsFactor" then
61 | return CraftSim.LOCAL:GetText(CraftSim.CONST.TEXT.STAT_MULTICRAFT_BONUS)
62 | elseif statName == "resourcefulnessExtraItemsFactor" then
63 | return CraftSim.LOCAL:GetText(CraftSim.CONST.TEXT.STAT_RESOURCEFULNESS_BONUS)
64 | elseif statName == "craftingspeedBonusFactor" then
65 | return CraftSim.LOCAL:GetText(CraftSim.CONST.TEXT.STAT_CRAFTINGSPEED_BONUS)
66 | elseif statName == "phialExperimentationChanceFactor" then
67 | return CraftSim.LOCAL:GetText(CraftSim.CONST.TEXT.STAT_PHIAL_EXPERIMENTATION)
68 | elseif statName == "potionExperimentationChanceFactor" then
69 | return CraftSim.LOCAL:GetText(CraftSim.CONST.TEXT.STAT_POTION_EXPERIMENTATION)
70 | end
71 | end
72 |
--------------------------------------------------------------------------------
/Modules/ItemCount/ItemCount.lua:
--------------------------------------------------------------------------------
1 | ---@class CraftSim
2 | local CraftSim = select(2, ...)
3 |
4 | local GUTIL = CraftSim.GUTIL
5 |
6 | local print = CraftSim.DEBUG:RegisterDebugID("Data.ItemCount")
7 |
8 | ---@class CraftSim.ITEM_COUNT : Frame
9 | CraftSim.ITEM_COUNT = GUTIL:CreateRegistreeForEvents({ "BAG_UPDATE_DELAYED", "BANKFRAME_OPENED" })
10 |
11 | ---@param crafterUID string
12 | ---@param itemID ItemInfo
13 | ---@param excludeWarbank? boolean
14 | ---@return number count
15 | ---@return ItemID? alternativeItemID
16 | ---@return number? alternativeCount
17 | function CraftSim.ITEM_COUNT:Get(crafterUID, itemID, excludeWarbank)
18 | local playerCrafterUID = CraftSim.UTIL:GetPlayerCrafterUID()
19 | crafterUID = crafterUID or playerCrafterUID
20 | local isPlayer = crafterUID == playerCrafterUID
21 |
22 | local alternativeItemID = CraftSim.CONST.REAGENT_ID_EXCEPTION_MAPPING[itemID]
23 |
24 | if isPlayer then
25 | -- always from api and then save
26 | self:UpdateAllCountsForItemID(itemID)
27 |
28 | local altCount = nil
29 | -- if player then return inclusive accountBankCount
30 | local itemCount = CraftSim.DB.ITEM_COUNT:Get(crafterUID, itemID, true, not excludeWarbank)
31 | if alternativeItemID then
32 | self:UpdateAllCountsForItemID(alternativeItemID)
33 | altCount = CraftSim.DB.ITEM_COUNT:Get(crafterUID, alternativeItemID, true, not excludeWarbank)
34 | end
35 | return itemCount, alternativeItemID, altCount
36 | end
37 |
38 | -- for alts do not include accountBank
39 | local count = CraftSim.DB.ITEM_COUNT:Get(crafterUID, itemID, true, false)
40 | local altCount = nil
41 | if alternativeItemID then
42 | altCount = CraftSim.DB.ITEM_COUNT:Get(crafterUID, alternativeItemID, true, false)
43 | end
44 | if not count then
45 | return 0 -- not cached yet
46 | else
47 | return count, alternativeItemID, altCount
48 | end
49 | end
50 |
51 | ---@param itemID ItemID
52 | function CraftSim.ITEM_COUNT:UpdateAllCountsForItemID(itemID)
53 | local crafterUID = CraftSim.UTIL:GetPlayerCrafterUID()
54 |
55 | local inventoryCount = C_Item.GetItemCount(itemID, false, false, false, false)
56 | local bankCount = math.max(0, C_Item.GetItemCount(itemID, true, false, true, false) - inventoryCount)
57 | local accountBankCount = math.max(0, C_Item.GetItemCount(itemID, false, false, false, true) - inventoryCount)
58 |
59 | CraftSim.DB.ITEM_COUNT:UpdateItemCounts(crafterUID, itemID, inventoryCount, bankCount, accountBankCount)
60 | end
61 |
62 | function CraftSim.ITEM_COUNT:BAG_UPDATE_DELAYED()
63 | CraftSim.ITEM_COUNT:UpdateItemCountForCharacter()
64 | end
65 |
66 | function CraftSim.ITEM_COUNT:BANKFRAME_OPENED()
67 | CraftSim.ITEM_COUNT:UpdateItemCountForCharacter()
68 | end
69 |
70 | --- loops all of a players inventory+bank bags and updates all tradegoods item count
71 | function CraftSim.ITEM_COUNT:UpdateItemCountForCharacter()
72 | local alreadyUpdated = {} -- small map to cache already updated IDs to not double update them
73 | print("Start Bag Update..")
74 | local function countBagItems(bagID)
75 | for slot = 1, C_Container.GetContainerNumSlots(bagID) do
76 | local itemID = C_Container.GetContainerItemID(bagID, slot)
77 |
78 | if itemID ~= nil then
79 | local itemInfoInstant = { C_Item.GetItemInfoInstant(itemID) }
80 | local itemClassID = itemInfoInstant[6]
81 | local itemIcon = itemInfoInstant[5]
82 | if Enum.ItemClass.Tradegoods == itemClassID then
83 | if not alreadyUpdated[itemID] then
84 | print("Updating Count: " .. GUTIL:IconToText(itemIcon, 20, 20))
85 | alreadyUpdated[itemID] = true
86 | self:UpdateAllCountsForItemID(itemID)
87 | end
88 | end
89 | end
90 | end
91 | end
92 | -- +6 to account for accountBank / warband bank
93 | for bagID = Enum.BagIndex.CharacterBankTab_1, Enum.BagIndex.CharacterBankTab_6 + 6 do
94 | countBagItems(bagID)
95 | end
96 | end
97 |
--------------------------------------------------------------------------------
/DB/itemRecipeDB.lua:
--------------------------------------------------------------------------------
1 | ---@class CraftSim
2 | local CraftSim = select(2, ...)
3 |
4 | local GUTIL = CraftSim.GUTIL
5 |
6 | ---@class CraftSim.DB
7 | CraftSim.DB = CraftSim.DB
8 |
9 | ---@class CraftSim.DB.ITEM_RECIPE : CraftSim.DB.Repository
10 | CraftSim.DB.ITEM_RECIPE = CraftSim.DB:RegisterRepository()
11 |
12 | local print = CraftSim.DEBUG:RegisterDebugID("Database.itemRecipeDB")
13 |
14 | ---@class CraftSim.ItemRecipeData
15 | ---@field recipeID RecipeID
16 | ---@field itemID ItemID
17 | ---@field qualityID QualityID
18 | ---@field crafters CrafterUID[]
19 |
20 | function CraftSim.DB.ITEM_RECIPE:Init()
21 | if not CraftSimDB.itemRecipeDB then
22 | ---@type CraftSimDB.Database
23 | CraftSimDB.itemRecipeDB = {
24 | version = 0,
25 | ---@type table
26 | data = {},
27 | }
28 | end
29 |
30 | CraftSimDB.itemRecipeDB.data = CraftSimDB.itemRecipeDB.data or {}
31 | end
32 |
33 | function CraftSim.DB.ITEM_RECIPE:Migrate()
34 | -- 0 -> 1
35 | if CraftSimDB.itemRecipeDB.version == 0 then
36 | local CraftSimRecipeDataCache = _G["CraftSimRecipeDataCache"]
37 | if CraftSimRecipeDataCache then
38 | CraftSimDB.itemRecipeDB.data = CraftSimRecipeDataCache["itemRecipeCache"] or {}
39 | end
40 | CraftSimDB.itemRecipeDB.version = 1
41 | end
42 |
43 | -- 1 -> 2 (16.1.3)
44 | if CraftSimDB.itemRecipeDB.version == 1 then
45 | -- remove any crafter entries with colored names...
46 | for _, data in pairs(CraftSimDB.itemRecipeDB.data or {}) do
47 | local correctedCrafterUIDs = {}
48 | for _, crafterUID in pairs(data.crafters) do
49 | if not string.find(crafterUID, '\124c') then
50 | tinsert(correctedCrafterUIDs, crafterUID)
51 | end
52 | end
53 | data.crafters = correctedCrafterUIDs
54 | end
55 |
56 | CraftSimDB.itemRecipeDB.version = 2
57 | end
58 |
59 | -- 2 -> 3 (16.1.5)
60 | if CraftSimDB.itemRecipeDB.version == 2 then
61 | -- restore data table if not existing
62 | CraftSimDB.itemCountDB.data = CraftSimDB.itemCountDB.data or {}
63 | CraftSimDB.itemRecipeDB.version = 3
64 | end
65 |
66 | -- TWW Refactor
67 | if CraftSimDB.itemRecipeDB.version == 3 then
68 | self:ClearAll()
69 | CraftSimDB.itemRecipeDB.version = 4
70 | end
71 | end
72 |
73 | function CraftSim.DB.ITEM_RECIPE:ClearAll()
74 | wipe(CraftSimDB.itemRecipeDB.data)
75 | end
76 |
77 | function CraftSim.DB.ITEM_RECIPE:CleanUp()
78 | local CraftSimRecipeDataCache = _G["CraftSimRecipeDataCache"]
79 | if CraftSimRecipeDataCache then
80 | if CraftSimRecipeDataCache["itemRecipeCache"] then
81 | CraftSimRecipeDataCache["itemRecipeCache"] = nil
82 | end
83 | end
84 | end
85 |
86 | ---@param itemID ItemID
87 | ---@return CraftSim.ItemRecipeData itemRecipeData
88 | function CraftSim.DB.ITEM_RECIPE:Get(itemID)
89 | return CraftSimDB.itemRecipeDB.data[itemID]
90 | end
91 |
92 | ---@return CraftSim.ItemRecipeData[]
93 | function CraftSim.DB.ITEM_RECIPE:GetAll()
94 | return CraftSimDB.itemRecipeDB.data
95 | end
96 |
97 | ---@param recipeID RecipeID
98 | ---@param qualityID QualityID
99 | ---@param itemID ItemID
100 | ---@param crafterUID CrafterUID
101 | function CraftSim.DB.ITEM_RECIPE:Add(recipeID, qualityID, itemID, crafterUID)
102 | ---@type CraftSim.ItemRecipeData
103 | local itemRecipeData = CraftSimDB.itemRecipeDB.data[itemID] or {
104 | recipeID = recipeID,
105 | qualityID = qualityID,
106 | itemID = itemID,
107 | crafters = {}
108 | }
109 |
110 | if not tContains(itemRecipeData.crafters, crafterUID) then
111 | tinsert(itemRecipeData.crafters, crafterUID)
112 |
113 | if #itemRecipeData.crafters == 1 then
114 | CraftSim.DB.RECIPE_SUB_CRAFTER:SetCrafter(recipeID, crafterUID)
115 | end
116 | end
117 |
118 | CraftSimDB.itemRecipeDB.data[itemID] = itemRecipeData
119 | end
120 |
--------------------------------------------------------------------------------
/Classes/OptionalReagent.lua:
--------------------------------------------------------------------------------
1 | ---@class CraftSim
2 | local CraftSim = select(2, ...)
3 |
4 | local GUTIL = CraftSim.GUTIL
5 |
6 |
7 | ---@class CraftSim.OptionalReagent : CraftSim.CraftSimObject
8 | CraftSim.OptionalReagent = CraftSim.CraftSimObject:extend()
9 |
10 | ---@param craftingReagent CraftingReagent
11 | function CraftSim.OptionalReagent:new(craftingReagent)
12 | self.item = Item:CreateFromItemID(craftingReagent.itemID)
13 | ---@type CraftSim.ProfessionStats
14 | self.professionStats = CraftSim.ProfessionStats()
15 | local reagentData = CraftSim.OPTIONAL_REAGENT_DATA[craftingReagent.itemID]
16 |
17 | if reagentData then
18 | self.qualityID = reagentData.qualityID
19 | self.expansionID = reagentData.expansionID
20 | self.name = reagentData.name
21 |
22 | ---@type table
23 | local stats = reagentData.stats or {}
24 |
25 | self.professionStats.recipeDifficulty.value = stats.increasedifficulty or 0
26 |
27 | self.professionStats.skill.value = stats.skill or 0
28 | self.professionStats.multicraft.value = stats.multicraft or 0
29 | self.professionStats.resourcefulness.value = stats.resourcefulness or 0
30 | self.professionStats.ingenuity.value = stats.ingenuity or 0
31 |
32 | if stats.reagentssavedfromresourcefulness then
33 | self.professionStats.resourcefulness:SetExtraValue(stats.reagentssavedfromresourcefulness / 100)
34 | end
35 |
36 | if stats.ingenuityrefundincrease then
37 | self.professionStats.ingenuity:SetExtraValue(stats.ingenuityrefundincrease / 100)
38 | end
39 |
40 | if stats.reduceconcentrationcost then
41 | self.professionStats.ingenuity:SetExtraValue(stats.reduceconcentrationcost / 100, 2)
42 | end
43 |
44 | if stats.craftingspeed then
45 | self.professionStats.craftingspeed:SetExtraValue(stats.craftingspeed / 100)
46 | end
47 |
48 | if stats.additionalitemscraftedwithmulticraft then
49 | self.professionStats.multicraft:SetExtraValue(stats.additionalitemscraftedwithmulticraft / 100)
50 | end
51 |
52 | -- ignore: modifyskillgain
53 | end
54 | end
55 |
56 | function CraftSim.OptionalReagent:Debug()
57 | return {
58 | self.item:GetItemLink() or self.item:GetItemID()
59 | }
60 | end
61 |
62 | function CraftSim.OptionalReagent:Copy()
63 | local copy = CraftSim.OptionalReagent({ itemID = self.item:GetItemID() })
64 | return copy
65 | end
66 |
67 | ---@class CraftSim.OptionalReagent.Serialized
68 | ---@field qualityID number
69 | ---@field itemID number
70 |
71 | function CraftSim.OptionalReagent:Serialize()
72 | local serialized = {}
73 | serialized.qualityID = self.qualityID
74 | serialized.itemID = self.item:GetItemID()
75 | return serialized
76 | end
77 |
78 | ---STATIC: Deserializes an optionalReagent
79 | ---@param serializedOptionalReagent CraftSim.OptionalReagent.Serialized
80 | ---@return CraftSim.OptionalReagent
81 | function CraftSim.OptionalReagent:Deserialize(serializedOptionalReagent)
82 | serializedOptionalReagent.itemID = tonumber(serializedOptionalReagent.itemID) or 0
83 | serializedOptionalReagent.qualityID = tonumber(serializedOptionalReagent.qualityID) or 0
84 | return CraftSim.OptionalReagent(serializedOptionalReagent) -- as it builds from itemID only its fine
85 | end
86 |
87 | function CraftSim.OptionalReagent:GetJSON(indent)
88 | indent = indent or 0
89 | local jb = CraftSim.JSONBuilder(indent)
90 | jb:Begin()
91 | jb:Add("professionStats", self.professionStats)
92 | jb:Add("qualityID", self.qualityID)
93 | jb:Add("itemID", self.item:GetItemID())
94 | jb:End()
95 | return jb.json
96 | end
97 |
98 | ---@param recipeData CraftSim.RecipeData
99 | function CraftSim.OptionalReagent:IsOrderReagentIn(recipeData)
100 | if not recipeData.orderData then return false end
101 |
102 | local itemID = self.item:GetItemID()
103 |
104 | local orderItemIDs = GUTIL:Map(recipeData.orderData.reagents or {}, function(reagentInfo)
105 | return reagentInfo.reagent.itemID
106 | end)
107 |
108 | return tContains(orderItemIDs, itemID)
109 | end
110 |
--------------------------------------------------------------------------------
/Modules/ConcentrationTracker/ConcentrationTracker.lua:
--------------------------------------------------------------------------------
1 | ---@class CraftSim
2 | local CraftSim = select(2, ...)
3 |
4 | local GUTIL = CraftSim.GUTIL
5 | local f = GUTIL:GetFormatter()
6 |
7 | ---@class CraftSim.CONCENTRATION_TRACKER
8 | CraftSim.CONCENTRATION_TRACKER = {}
9 |
10 | ---@type table
11 | CraftSim.CONCENTRATION_TRACKER.ConcentrationDataCache = {}
12 |
13 | ---@param crafterUID CrafterUID
14 | ---@param profession Enum.Profession
15 | function CraftSim.CONCENTRATION_TRACKER:BlacklistData(crafterUID, profession)
16 | local concentrationTrackerBlacklist = CraftSim.DB.OPTIONS:Get("CONCENTRATION_TRACKER_BLACKLIST")
17 | concentrationTrackerBlacklist[crafterUID] = concentrationTrackerBlacklist[crafterUID] or {}
18 | tinsert(concentrationTrackerBlacklist[crafterUID], profession)
19 | end
20 |
21 | function CraftSim.CONCENTRATION_TRACKER:ClearBlacklist()
22 | local concentrationTrackerBlacklist = CraftSim.DB.OPTIONS:Get("CONCENTRATION_TRACKER_BLACKLIST")
23 | wipe(concentrationTrackerBlacklist)
24 | end
25 |
26 | ---@return CraftSim.ConcentrationData?
27 | function CraftSim.CONCENTRATION_TRACKER:GetCurrentConcentrationData()
28 | local skillLineID = C_TradeSkillUI.GetProfessionChildSkillLineID()
29 |
30 | local expansionID = CraftSim.UTIL:GetExpansionIDBySkillLineID(skillLineID)
31 |
32 | local playerCrafterUID = CraftSim.UTIL:GetPlayerCrafterUID()
33 | local professionInfo = C_TradeSkillUI.GetProfessionInfoBySkillLineID(skillLineID)
34 | local profession = professionInfo and professionInfo.profession
35 |
36 | -- if not shown profession's expac dont show
37 | if not expansionID or expansionID < CraftSim.CONST.EXPANSION_IDS.DRAGONFLIGHT then return end
38 |
39 | local cached = CraftSim.CONCENTRATION_TRACKER.ConcentrationDataCache[skillLineID]
40 | if cached and cached.currencyID then
41 | cached:Update()
42 |
43 | -- update the saved db data always
44 | CraftSim.DB.CRAFTER:SaveCrafterConcentrationData(playerCrafterUID,
45 | profession,
46 | CraftSim.UTIL:GetExpansionIDBySkillLineID(skillLineID),
47 | cached)
48 |
49 | return cached
50 | end
51 |
52 | local currencyID = C_TradeSkillUI.GetConcentrationCurrencyID(skillLineID)
53 | local professionInfo = C_TradeSkillUI.GetProfessionInfoBySkillLineID(skillLineID)
54 | local professionID = professionInfo and professionInfo.profession
55 | if currencyID and skillLineID > 0 and C_ProfSpecs.SkillLineHasSpecialization(skillLineID)
56 | and not CraftSim.CONST.GATHERING_PROFESSIONS[professionID] then
57 | local concentrationData = CraftSim.ConcentrationData(currencyID)
58 | concentrationData:Update()
59 | -- save in crafterDB
60 | CraftSim.DB.CRAFTER:SaveCrafterConcentrationData(playerCrafterUID,
61 | profession,
62 | CraftSim.UTIL:GetExpansionIDBySkillLineID(skillLineID),
63 | concentrationData)
64 | CraftSim.CONCENTRATION_TRACKER.ConcentrationDataCache[skillLineID] = concentrationData
65 | return concentrationData
66 | end
67 |
68 | return nil
69 | end
70 |
71 | ---@param concentrationData CraftSim.ConcentrationData
72 | ---@return string formattedDate
73 | function CraftSim.CONCENTRATION_TRACKER:GetMaxFormatByFormatMode(concentrationData)
74 | local formatMode = CraftSim.DB.OPTIONS:Get("CONCENTRATION_TRACKER_FORMAT_MODE")
75 |
76 | if formatMode == CraftSim.CONCENTRATION_TRACKER.UI.FORMAT_MODE.HOURS_LEFT then
77 | local restTime = concentrationData:GetTimeUntilMax()
78 | local restTimeDate = date("!*t", restTime)
79 | local restHours = ((restTimeDate.day - 1) * 24) + restTimeDate.hour
80 | return f.bb(string.format("%dh", restHours))
81 | elseif formatMode == CraftSim.CONCENTRATION_TRACKER.UI.FORMAT_MODE.EUROPE_MAX_DATE then
82 | local maxDate = concentrationData:GetTimestampMax()
83 | local date = date("*t", maxDate) -- with local time support
84 |
85 | return f.bb(string.format("%02d.%02d %02d:%02d", date.day, date.month, date.hour, date
86 | .min))
87 | elseif formatMode == CraftSim.CONCENTRATION_TRACKER.UI.FORMAT_MODE.AMERICA_MAX_DATE then
88 | local maxDate = concentrationData:GetTimestampMax()
89 | local date = date("*t", maxDate) -- with local time support
90 |
91 | return f.bb(string.format("%02d/%02d %02d:%02d", date.month, date.day, date.hour, date
92 | .min))
93 | end
94 | end
95 |
--------------------------------------------------------------------------------
/Modules/AverageProfit/AverageProfit.lua:
--------------------------------------------------------------------------------
1 | ---@class CraftSim
2 | local CraftSim = select(2, ...)
3 |
4 | ---@class CraftSim.AVERAGEPROFIT
5 | CraftSim.AVERAGEPROFIT = {}
6 |
7 | ---@type GGUI.Frame
8 | CraftSim.AVERAGEPROFIT.frame = nil
9 | ---@type GGUI.Frame
10 | CraftSim.AVERAGEPROFIT.frameWO = nil
11 |
12 | local print = CraftSim.DEBUG:RegisterDebugID("Modules.AverageProfit")
13 |
14 | local statIncreaseFactor = 5
15 |
16 | function CraftSim.AVERAGEPROFIT:GetQualityThresholds(maxQuality, recipeDifficulty, breakPointOffset)
17 | local offset = breakPointOffset and 1 or 0
18 | if maxQuality == 1 then
19 | return {}
20 | elseif maxQuality == 3 then
21 | return { recipeDifficulty * 0.5 + offset, recipeDifficulty + offset }
22 | elseif maxQuality == 5 then
23 | return { recipeDifficulty * 0.2 + offset, recipeDifficulty * 0.5 + offset, recipeDifficulty * 0.8 + offset,
24 | recipeDifficulty + offset }
25 | end
26 | end
27 |
28 | ---@param recipeData CraftSim.RecipeData
29 | ---@param baseAverageProfit number
30 | function CraftSim.AVERAGEPROFIT:CalculateStatWeightByModifiedData(recipeData, baseAverageProfit)
31 | recipeData:Update()
32 | local meanProfitModified = CraftSim.CALC:GetAverageProfit(recipeData)
33 | local profitDiff = meanProfitModified - baseAverageProfit
34 | local statWeight = profitDiff / statIncreaseFactor
35 |
36 | return statWeight
37 | end
38 |
39 | ---@param recipeData CraftSim.RecipeData
40 | ---@param baseAverageProfit number
41 | ---@return number statWeight
42 | function CraftSim.AVERAGEPROFIT:GetMulticraftWeight(recipeData, baseAverageProfit)
43 | if not recipeData.supportsMulticraft then
44 | return 0
45 | end
46 | -- increase modifier
47 | recipeData.professionStatModifiers.multicraft:addValue(statIncreaseFactor)
48 | local statWeight = CraftSim.AVERAGEPROFIT:CalculateStatWeightByModifiedData(recipeData, baseAverageProfit)
49 | -- revert change (probably more performant than just to copy the whole thing)
50 | recipeData.professionStatModifiers.multicraft:subtractValue(statIncreaseFactor)
51 | recipeData:Update() -- needed to update professionStats after reverting - or else CraftSim.INIT.currentRecipeData is invalid
52 | return statWeight
53 | end
54 |
55 | ---@param recipeData CraftSim.RecipeData
56 | ---@param baseAverageProfit number
57 | ---@return number statWeight
58 | function CraftSim.AVERAGEPROFIT:GetResourcefulnessWeight(recipeData, baseAverageProfit)
59 | if not recipeData.supportsResourcefulness then
60 | return 0
61 | end
62 | -- increase modifier
63 | recipeData.professionStatModifiers.resourcefulness:addValue(statIncreaseFactor)
64 | local statWeight = CraftSim.AVERAGEPROFIT:CalculateStatWeightByModifiedData(recipeData, baseAverageProfit)
65 | -- revert change (probably more performant than just to copy the whole thing)
66 | recipeData.professionStatModifiers.resourcefulness:subtractValue(statIncreaseFactor)
67 | recipeData:Update() -- needed to update professionStats after reverting - or else CraftSim.INIT.currentRecipeData is invalid
68 | return statWeight
69 | end
70 |
71 | ---@param recipeData CraftSim.RecipeData
72 | ---@param skill number
73 | function CraftSim.AVERAGEPROFIT:GetExpectedQualityBySkill(recipeData, skill)
74 | local expectedQuality = 1
75 | local thresholds = CraftSim.AVERAGEPROFIT:GetQualityThresholds(recipeData.maxQuality,
76 | recipeData.professionStats.recipeDifficulty.value, CraftSim.DB.OPTIONS:Get("QUALITY_BREAKPOINT_OFFSET"))
77 |
78 | for _, threshold in pairs(thresholds) do
79 | if skill >= threshold then
80 | expectedQuality = expectedQuality + 1
81 | end
82 | end
83 |
84 | return expectedQuality
85 | end
86 |
87 | ---@param recipeData CraftSim.RecipeData
88 | ---@return CraftSim.Statweights statweightResult
89 | function CraftSim.AVERAGEPROFIT:CalculateStatWeights(recipeData)
90 | print("Get Average Profit", false, true)
91 | local averageProfit = CraftSim.CALC:GetAverageProfit(recipeData)
92 |
93 | print("calculate stat weights avg profit: " .. tostring(CraftSim.UTIL:FormatMoney(averageProfit, true)))
94 |
95 | local multicraftWeight = CraftSim.AVERAGEPROFIT:GetMulticraftWeight(recipeData, averageProfit)
96 | local resourcefulnessWeight = CraftSim.AVERAGEPROFIT:GetResourcefulnessWeight(recipeData, averageProfit)
97 | local concentrationValue = recipeData:GetConcentrationValue()
98 |
99 | return CraftSim.Statweights(averageProfit, multicraftWeight, resourcefulnessWeight, concentrationValue)
100 | end
101 |
--------------------------------------------------------------------------------
/Classes/ProfessionStat.lua:
--------------------------------------------------------------------------------
1 | ---@class CraftSim
2 | local CraftSim = select(2, ...)
3 |
4 | ---@class CraftSim.ProfessionStat : CraftSim.CraftSimObject
5 | ---@overload fun(name: string?, value: number?, percentMod: number?): CraftSim.ProfessionStat
6 | CraftSim.ProfessionStat = CraftSim.CraftSimObject:extend()
7 |
8 | local print = CraftSim.DEBUG:RegisterDebugID("Classes.ProfessionsStats.ProfessionStat")
9 |
10 | ---@param name string
11 | ---@param value number?
12 | ---@param percentMod number?
13 | function CraftSim.ProfessionStat:new(name, value, percentMod)
14 | self.name = name
15 | self.value = value or 0
16 | self.percentMod = percentMod or 0
17 | ---@type number[]
18 | self.extraValues = {} -- for special values like extra items from multicraft or concentration saved and so on
19 | end
20 |
21 | ---@param index? number default: 1
22 | ---@return number extraValue default: 0
23 | function CraftSim.ProfessionStat:GetExtraValue(index)
24 | return self.extraValues[index or 1] or 0
25 | end
26 |
27 | ---@param value number
28 | ---@param index number? default: 1
29 | function CraftSim.ProfessionStat:SetExtraValue(value, index)
30 | self.extraValues[index or 1] = value or 0
31 | end
32 |
33 | function CraftSim.ProfessionStat:GetPercent(decimal)
34 | if self.percentMod then
35 | if not decimal then
36 | return self.value * self.percentMod * 100
37 | else
38 | return self.value * self.percentMod
39 | end
40 | else
41 | error("CraftSim ProfessionStat: No Percent Mod set: " .. tostring(self.name))
42 | end
43 | end
44 |
45 | ---@param percent number as decimal e.g. 0.20
46 | function CraftSim.ProfessionStat:SetValueByPercent(percent)
47 | self.value = percent / self.percentMod
48 | end
49 |
50 | function CraftSim.ProfessionStat:Clear()
51 | self.value = 0
52 | wipe(self.extraValues)
53 | end
54 |
55 | ---@param value number
56 | function CraftSim.ProfessionStat:addValue(value)
57 | self.value = self.value + value
58 | end
59 |
60 | ---@param extraValue number
61 | ---@param index? number default: 1
62 | function CraftSim.ProfessionStat:addExtraValue(extraValue, index)
63 | index = index or 1
64 | self:SetExtraValue(self:GetExtraValue(index) + extraValue, index)
65 | end
66 |
67 | ---@param extraValue number
68 | ---@param index? number default: 1
69 | function CraftSim.ProfessionStat:subtractExtraValue(extraValue, index)
70 | index = index or 1
71 | self:SetExtraValue(self:GetExtraValue(index) - extraValue, index)
72 | end
73 |
74 | ---@param professionStat CraftSim.ProfessionStat
75 | function CraftSim.ProfessionStat:addExtraValues(professionStat)
76 | for index, extraValue in pairs(professionStat.extraValues) do
77 | self:addExtraValue(extraValue, index)
78 | end
79 | end
80 |
81 | ---@param value number
82 | function CraftSim.ProfessionStat:subtractValue(value)
83 | self.value = self.value - value
84 | end
85 |
86 | ---@param professionStat CraftSim.ProfessionStat
87 | function CraftSim.ProfessionStat:subtractExtraValues(professionStat)
88 | for index, extraValue in pairs(professionStat.extraValues) do
89 | self:subtractExtraValue(extraValue, index)
90 | end
91 | end
92 |
93 | function CraftSim.ProfessionStat:GetJSON(indent)
94 | indent = indent or 0
95 | local jb = CraftSim.JSONBuilder(indent)
96 | jb:Begin()
97 | jb:Add("name", self.name)
98 | jb:Add("value", self.value)
99 | jb:Add("percentMod", self.percentMod)
100 | jb:AddList("extraValues", self.extraValues, true)
101 | jb:End()
102 | return jb.json
103 | end
104 |
105 | ---@class CraftSim.ProfessionStat.Serialized
106 | ---@field name string
107 | ---@field value number
108 | ---@field percentMod number
109 | ---@field extraValues number[]
110 |
111 | ---@return CraftSim.ProfessionStat.Serialized
112 | function CraftSim.ProfessionStat:Serialize()
113 | ---@type CraftSim.ProfessionStat.Serialized
114 | local serializedData = {
115 | name = self.name,
116 | value = self.value,
117 | extraValues = self.extraValues,
118 | percentMod = self.percentMod,
119 | }
120 | return serializedData
121 | end
122 |
123 | ---@param serializedData CraftSim.ProfessionStat.Serialized
124 | function CraftSim.ProfessionStat:Deserialize(serializedData)
125 | local professionStat = CraftSim.ProfessionStat()
126 | professionStat.name = serializedData.name
127 | professionStat.value = serializedData.value
128 | professionStat.percentMod = serializedData.percentMod
129 | professionStat.extraValues = serializedData.extraValues or {}
130 |
131 | return professionStat
132 | end
133 |
--------------------------------------------------------------------------------
/Classes/Buff.lua:
--------------------------------------------------------------------------------
1 | ---@class CraftSim
2 | local CraftSim = select(2, ...)
3 |
4 | local GUTIL = CraftSim.GUTIL
5 |
6 | local print = CraftSim.DEBUG:RegisterDebugID("Classes.RecipeData.BuffData.Buff")
7 |
8 | ---@class CraftSim.Buff : CraftSim.CraftSimObject
9 | ---@overload fun(recipeData: CraftSim.RecipeData, buffID: CraftSim.BuffID, professionStats:CraftSim.ProfessionStats, qualityID: number?, valuePointData: CraftSim.Buff.ValuePointData?, displayBuffID: number?, customTooltip: string?, displayItemID: number?): CraftSim.Buff
10 | CraftSim.Buff = CraftSim.CraftSimObject:extend()
11 |
12 | ---@param recipeData CraftSim.RecipeData
13 | ---@param buffID CraftSim.BuffID
14 | ---@param professionStats CraftSim.ProfessionStats
15 | ---@param qualityID number?
16 | ---@param valuePointData CraftSim.Buff.ValuePointData?
17 | ---@param displayBuffID number? if the buff to display is a different one than the one to recognize the aura
18 | ---@param customTooltip string?
19 | function CraftSim.Buff:new(recipeData, buffID, professionStats, qualityID, valuePointData, displayBuffID, customTooltip,
20 | displayItemID)
21 | ---@type CraftSim.ProfessionStats
22 | self.professionStats = professionStats
23 | self.baseProfessionStats = professionStats:Copy()
24 | local spellInfo = C_Spell.GetSpellInfo(buffID)
25 | local qualityIcon = ""
26 | self.valuePointData = valuePointData
27 | self.qualityID = qualityID
28 | self.recipeData = recipeData
29 | if self.qualityID then
30 | qualityIcon = " " .. GUTIL:GetQualityIconString(self.qualityID, 20, 20)
31 | end
32 | self.name = spellInfo.name .. qualityIcon
33 | self.buffID = buffID
34 | self.displayBuffID = displayBuffID or buffID
35 | self.displayItemID = displayItemID
36 | self.active = false
37 | self.customTooltip = customTooltip
38 | self.showItemTooltip = false
39 | self.stacks = 1
40 | end
41 |
42 | ---@class CraftSim.Buff.ValuePointData
43 | ---@field index number
44 | ---@field value number
45 |
46 | function CraftSim.Buff:Update()
47 | --- check for current buff
48 | local auraData = C_UnitAuras.GetPlayerAuraBySpellID(self.buffID)
49 |
50 | if not auraData then
51 | self.active = false
52 | return
53 | end
54 |
55 | self.active = true
56 | self.stacks = math.max(1, auraData.applications)
57 |
58 | if self.valuePointData then
59 | self.active = (auraData.points[self.valuePointData.index] / self.stacks) == self.valuePointData.value
60 | end
61 |
62 | -- update stats (for stackable buffs)
63 | self.professionStats:Clear()
64 |
65 | for _ = 1, self.stacks do
66 | self.professionStats:add(self.baseProfessionStats)
67 | end
68 | end
69 |
70 | --- returns a unique id as string for this buff and its quality
71 | ---@return string uuid
72 | function CraftSim.Buff:GetUID()
73 | return (self.buffID or self.name) .. ":" .. (self.qualityID or 0)
74 | end
75 |
76 | function CraftSim.Buff:Debug()
77 | local debugLines = {
78 | "Name: " .. tostring(self.name),
79 | "Active: " .. tostring(self.active),
80 | "ProfessionStats: ",
81 | }
82 |
83 | local statLines = self.professionStats:Debug()
84 | statLines = CraftSim.GUTIL:Map(statLines, function(line) return "-" .. line end)
85 | debugLines = CraftSim.GUTIL:Concat({ debugLines, statLines })
86 |
87 | return debugLines
88 | end
89 |
90 | function CraftSim.Buff:GetJSON(indent)
91 | indent = indent or 0
92 | local jb = CraftSim.JSONBuilder(indent)
93 | jb:Begin()
94 | jb:Add("name", self.name)
95 | jb:Add("active", self.active)
96 | jb:Add("professionStats", self.professionStats)
97 | jb:End()
98 | return jb.json
99 | end
100 |
101 | -- bag buffs..
102 |
103 | ---@class CraftSim.BagBuff : CraftSim.Buff
104 | ---@overload fun(recipeData: CraftSim.RecipeData, bagItemID: ItemID, professionStats:CraftSim.ProfessionStats): CraftSim.Buff
105 | CraftSim.BagBuff = CraftSim.Buff:extend()
106 |
107 | ---@param recipeData CraftSim.RecipeData
108 | ---@param bagItemID ItemID
109 | ---@param professionStats CraftSim.ProfessionStats
110 | function CraftSim.BagBuff:new(recipeData, bagItemID, professionStats)
111 | self.professionStats = professionStats
112 | self.baseProfessionStats = professionStats:Copy()
113 | self.recipeData = recipeData
114 | self.displayItemID = bagItemID
115 | self.active = false
116 | self.stacks = 1
117 | self.showItemTooltip = true
118 | self.name = select(1, C_Item.GetItemInfo(bagItemID)) or "BagBuff"
119 | end
120 |
121 | function CraftSim.BagBuff:Update()
122 | self.active = CraftSim.UTIL:CheckIfBagIsEquipped(self.displayItemID)
123 | end
124 |
--------------------------------------------------------------------------------
/DB/customerHistoryDB.lua:
--------------------------------------------------------------------------------
1 | ---@class CraftSim
2 | local CraftSim = select(2, ...)
3 |
4 | local GUTIL = CraftSim.GUTIL
5 |
6 | ---@class CraftSim.DB
7 | CraftSim.DB = CraftSim.DB
8 |
9 | ---@class CraftSim.DB.CUSTOMER_HISTORY : CraftSim.DB.Repository
10 | CraftSim.DB.CUSTOMER_HISTORY = CraftSim.DB:RegisterRepository()
11 |
12 | local print = CraftSim.DEBUG:RegisterDebugID("Database.customerHistoryDB")
13 |
14 | ---@alias CustomerID string
15 |
16 | ---@class CraftSim.DB.CustomerHistory
17 | ---@field customer string
18 | ---@field realm string
19 | ---@field chatHistory CraftSim.DB.CustomerHistory.ChatMessage[]
20 | ---@field craftHistory CraftSim.DB.CustomerHistory.Craft[]
21 | ---@field totalTip number
22 | ---@field totalOrders number
23 | ---@field provisionAll number
24 | ---@field provisionSome number
25 | ---@field provisionNone number
26 | ---@field npc boolean
27 |
28 | ---@class CraftSim.DB.CustomerHistory.ChatMessage
29 | ---@field fromPlayer boolean
30 | ---@field content string
31 | ---@field timestamp number unix ts in seconds
32 |
33 | ---@class CraftSim.DB.CustomerHistory.Craft
34 | ---@field itemLink string
35 | ---@field tip number
36 | ---@field reagents CraftingOrderReagentInfo[]
37 | ---@field reagentState Enum.CraftingOrderReagentsType
38 | ---@field timestamp number unix ts in seconds
39 | ---@field customerNotes string
40 |
41 | function CraftSim.DB.CUSTOMER_HISTORY:Init()
42 | if not CraftSimDB.customerHistoryDB then
43 | ---@type CraftSimDB.Database
44 | CraftSimDB.customerHistoryDB = {
45 | version = 0,
46 | ---@type table
47 | data = {},
48 | }
49 | end
50 |
51 | CraftSimDB.customerHistoryDB.data = CraftSimDB.customerHistoryDB.data or {}
52 | end
53 |
54 | function CraftSim.DB.CUSTOMER_HISTORY:Migrate()
55 | -- 0 -> 1
56 | if CraftSimDB.customerHistoryDB.version == 0 then
57 | local CraftSimCustomerHistoryV2 = _G["CraftSimCustomerHistoryV2"]
58 | if CraftSimCustomerHistoryV2 then
59 | for _, data in pairs(CraftSimCustomerHistoryV2) do
60 | data["v"] = nil
61 | end
62 | CraftSimDB.customerHistoryDB.data = CraftSimCustomerHistoryV2
63 | end
64 | CraftSimDB.customerHistoryDB.version = 1
65 | end
66 | end
67 |
68 | function CraftSim.DB.CUSTOMER_HISTORY:ClearAll()
69 | wipe(CraftSimDB.customerHistoryDB.data)
70 | end
71 |
72 | function CraftSim.DB.CUSTOMER_HISTORY:CleanUp()
73 | if _G["CraftSimCustomerHistoryV2"] then
74 | _G["CraftSimCustomerHistoryV2"] = nil
75 | end
76 | end
77 |
78 | ---@return table
79 | function CraftSim.DB.CUSTOMER_HISTORY:GetAll()
80 | return CraftSimDB.customerHistoryDB.data
81 | end
82 |
83 | function CraftSim.DB.CUSTOMER_HISTORY:Count()
84 | return GUTIL:Count(CraftSimDB.customerHistoryDB.data)
85 | end
86 |
87 | ---@param customer string
88 | ---@param realm string
89 | ---@return CraftSim.DB.CustomerHistory
90 | function CraftSim.DB.CUSTOMER_HISTORY:Get(customer, realm)
91 | CraftSimDB.customerHistoryDB.data[customer .. "-" .. realm] = CraftSimDB.customerHistoryDB.data
92 | [customer .. "-" .. realm] or {
93 | chatHistory = {},
94 | craftHistory = {},
95 | customer = customer,
96 | realm = realm,
97 | totalTip = 0,
98 | totalOrders = 0,
99 | provisionAll = 0,
100 | provisionSome = 0,
101 | provisionNone = 0,
102 | }
103 | return CraftSimDB.customerHistoryDB.data[customer .. "-" .. realm]
104 | end
105 |
106 | ---@param customerHistory CraftSim.DB.CustomerHistory
107 | function CraftSim.DB.CUSTOMER_HISTORY:Save(customerHistory)
108 | local maxEntriesPerClient = CraftSim.DB.OPTIONS:Get("CUSTOMER_HISTORY_MAX_ENTRIES_PER_CLIENT")
109 | --- limit chat history to a certain amount of messages
110 | CraftSim.GUTIL:TrimTable(customerHistory.chatHistory, maxEntriesPerClient, true)
111 |
112 | CraftSimDB.customerHistoryDB.data[customerHistory.customer .. "-" .. customerHistory.realm] = customerHistory
113 | end
114 |
115 | ---@param customerHistory CraftSim.DB.CustomerHistory
116 | function CraftSim.DB.CUSTOMER_HISTORY:Delete(customerHistory)
117 | CraftSimDB.customerHistoryDB.data[customerHistory.customer .. "-" .. customerHistory.realm] = nil
118 | end
119 |
120 | ---@param minimumTip number
121 | function CraftSim.DB.CUSTOMER_HISTORY:PurgeCustomers(minimumTip)
122 | for customerID, customerHistory in pairs(CraftSimDB.customerHistoryDB.data) do
123 | if not customerHistory.totalTip or customerHistory.totalTip <= minimumTip then
124 | CraftSimDB.customerHistoryDB.data[customerID] = nil
125 | end
126 | end
127 | end
128 |
--------------------------------------------------------------------------------
/Classes/ConcentrationData.lua:
--------------------------------------------------------------------------------
1 | ---@class CraftSim
2 | local CraftSim = select(2, ...)
3 |
4 | local GUTIL = CraftSim.GUTIL
5 |
6 | ---@class CraftSim.ConcentrationData : CraftSim.CraftSimObject
7 | ---@overload fun(currencyID : number): CraftSim.ConcentrationData
8 | CraftSim.ConcentrationData = CraftSim.CraftSimObject:extend()
9 |
10 | local print = CraftSim.DEBUG:RegisterDebugID("Classes.ConcentrationData")
11 |
12 | ---@param currencyID number
13 | function CraftSim.ConcentrationData:new(currencyID)
14 | self.currencyID = currencyID
15 | self.lastUpdated = 0 -- seconds with ms precision, ( GetServerTime )
16 | self.amount = 0
17 | self.rechargingDurationMS = 0
18 | self.maxQuantity = 0
19 | end
20 |
21 | ---@return CraftSim.ConcentrationData
22 | function CraftSim.ConcentrationData:Copy()
23 | local copy = CraftSim.ConcentrationData(self.currencyID)
24 | copy.lastUpdated = self.lastUpdated
25 | copy.amount = self.amount
26 | copy.rechargingDurationMS = self.rechargingDurationMS
27 | copy.maxQuantity = self.maxQuantity
28 | return copy
29 | end
30 |
31 | function CraftSim.ConcentrationData:Update()
32 | print("Updating ConcentrationData")
33 | local currencyInfo = C_CurrencyInfo.GetCurrencyInfo(self.currencyID)
34 | if not currencyInfo then return end
35 | self.lastUpdated = GetServerTime() -- is in seconds
36 | self.amount = currencyInfo.quantity
37 | self.maxQuantity = currencyInfo.maxQuantity
38 | self.rechargingDurationMS = currencyInfo.rechargingCycleDurationMS
39 | end
40 |
41 | function CraftSim.ConcentrationData:GetCurrentAmount()
42 | local timeDiff = GetServerTime() - self.lastUpdated
43 | local fullCyclesCompletedSinceUpdate = timeDiff / (self.rechargingDurationMS / 1000)
44 | return math.min(self.maxQuantity, self.amount + fullCyclesCompletedSinceUpdate)
45 | end
46 |
47 | ---@param concentrationValue number
48 | ---@return number time in seconds with ms precision
49 | function CraftSim.ConcentrationData:GetTimeUntil(concentrationValue)
50 | local concentrationleft = math.max(0, concentrationValue - self:GetCurrentAmount())
51 |
52 | return concentrationleft * (self.rechargingDurationMS / 1000)
53 | end
54 |
55 | ---@return number time in seconds with ms precision
56 | function CraftSim.ConcentrationData:GetTimeUntilMax()
57 | if self.maxQuantity == 0 then
58 | return 0
59 | end
60 |
61 | return self:GetTimeUntil(self.maxQuantity)
62 | end
63 |
64 | ---@param concentrationValue number
65 | ---@return string formattedTimer
66 | ---@return boolean ready
67 | function CraftSim.ConcentrationData:GetFormattedTimerUntil(concentrationValue)
68 | if self:GetCurrentAmount() >= concentrationValue then
69 | return "00:00:00:00", true
70 | end
71 |
72 | local restTime = self:GetTimeUntil(concentrationValue)
73 | local restTimeDate = date("!*t", restTime)
74 |
75 | return string.format("%02d:%02d:%02d:%02d", restTimeDate.day - 1, restTimeDate.hour, restTimeDate.min,
76 | restTimeDate.sec),
77 | false
78 | end
79 |
80 | ---@return string formattedTimer
81 | ---@return boolean ready
82 | function CraftSim.ConcentrationData:GetFormattedTimerUntilMax()
83 | return self:GetFormattedTimerUntil(self.maxQuantity)
84 | end
85 |
86 | function CraftSim.ConcentrationData:GetTimestampMax()
87 | return GetServerTime() + self:GetTimeUntilMax()
88 | end
89 |
90 | function CraftSim.ConcentrationData:GetFormattedDateMax()
91 | local maxDate = self:GetTimestampMax()
92 |
93 | local date = date("*t", maxDate) -- with local time support
94 |
95 | return string.format("%02d.%02d %02d:%02d", date.day, date.month, date.hour, date.min),
96 | not self:OnCooldown()
97 | end
98 |
99 | function CraftSim.ConcentrationData:OnCooldown()
100 | return self:GetCurrentAmount() < self.maxQuantity
101 | end
102 |
103 | ---@class CraftSim.ConcentrationData.Serialized
104 | ---@field currencyID number
105 | ---@field lastUpdated number
106 | ---@field maxQuantity number
107 | ---@field amount number
108 | ---@field rechargeTimePerPoint number
109 |
110 | function CraftSim.ConcentrationData:Serialize()
111 | ---@type CraftSim.ConcentrationData.Serialized
112 | local serialized = {
113 | currencyID = self.currencyID,
114 | lastUpdated = self.lastUpdated,
115 | amount = self.amount,
116 | maxQuantity = self.maxQuantity,
117 | rechargeTimePerPoint = self.rechargingDurationMS,
118 | }
119 | return serialized
120 | end
121 |
122 | ---@param serialized CraftSim.ConcentrationData.Serialized
123 | ---@return CraftSim.ConcentrationData
124 | function CraftSim.ConcentrationData:Deserialize(serialized)
125 | local concentrationData = CraftSim.ConcentrationData(serialized.currencyID)
126 | concentrationData.lastUpdated = serialized.lastUpdated
127 | concentrationData.maxQuantity = serialized.maxQuantity
128 | concentrationData.amount = serialized.amount
129 | concentrationData.rechargingDurationMS = serialized.rechargeTimePerPoint
130 | return concentrationData
131 | end
132 |
--------------------------------------------------------------------------------
/Classes/ReagentOptimizationResult.lua:
--------------------------------------------------------------------------------
1 | ---@class CraftSim
2 | local CraftSim = select(2, ...)
3 |
4 | local GUTIL = CraftSim.GUTIL
5 |
6 | local print = CraftSim.DEBUG:RegisterDebugID("Classes.ReagentOptimizationResult")
7 |
8 | ---@class CraftSim.ReagentOptimizationResult : CraftSim.CraftSimObject
9 | CraftSim.ReagentOptimizationResult = CraftSim.CraftSimObject:extend()
10 |
11 | ---@param recipeData CraftSim.RecipeData
12 | ---@param knapsackResult table
13 | function CraftSim.ReagentOptimizationResult:new(recipeData, knapsackResult)
14 | self.recipeData = recipeData
15 |
16 | if knapsackResult then
17 | ---@type number
18 | self.qualityID = knapsackResult.qualityReached
19 | --self.craftingCosts = knapsackResult.minValue + recipeData.priceData.craftingCostsFixed
20 |
21 | local reagentItems = {}
22 | ---@type CraftSim.Reagent[]
23 | self.reagents = CraftSim.GUTIL:Map(recipeData.reagentData.requiredReagents, function(reagent)
24 | if reagent.hasQuality then
25 | local copy = reagent:Copy()
26 | copy:Clear()
27 |
28 | table.foreach(copy.items, function(_, reagentItem)
29 | table.insert(reagentItems, reagentItem)
30 | end)
31 |
32 | return copy
33 | end
34 | end)
35 |
36 | -- map knapsackResult to reagents
37 | for _, matAllocation in pairs(knapsackResult.allocations) do
38 | for _, allocation in pairs(matAllocation.allocations) do
39 | local itemID = allocation.itemID
40 | local quantity = allocation.allocations
41 |
42 | local reagentItem = CraftSim.GUTIL:Find(reagentItems,
43 | function(ri) return ri.item:GetItemID() == itemID end)
44 | reagentItem.quantity = quantity
45 | end
46 | end
47 | else
48 | self.qualityID = recipeData.maxQuality
49 | --self.craftingCosts = 0
50 | self.reagents = {}
51 | end
52 | end
53 |
54 | ---@return boolean hasItems
55 | function CraftSim.ReagentOptimizationResult:HasItems(crafterUID)
56 | for _, reagent in pairs(self.reagents) do
57 | local hasItems = reagent:HasItems(1, crafterUID)
58 |
59 | if not hasItems then
60 | return false
61 | end
62 | end
63 |
64 | return true
65 | end
66 |
67 | ---@return CraftSim.ReagentListItem[]
68 | function CraftSim.ReagentOptimizationResult:GetReagentItemList()
69 | local reagentItemList = {}
70 | for _, reagent in pairs(self.reagents) do
71 | if reagent.hasQuality then -- should here but why not check
72 | reagentItemList = CraftSim.GUTIL:Concat({ reagentItemList, reagent:GetReagentItemList() })
73 | end
74 | end
75 |
76 | return reagentItemList
77 | end
78 |
79 | function CraftSim.ReagentOptimizationResult:Debug()
80 | local debugLines = {
81 | "qualityID: " .. tostring(self.qualityID),
82 | "craftingCosts: " .. CraftSim.UTIL:FormatMoney(self.craftingCosts),
83 | }
84 |
85 | table.foreach(self.reagents, function(_, reagent)
86 | debugLines = CraftSim.GUTIL:Concat({ debugLines, reagent:Debug() })
87 | end)
88 |
89 | return debugLines
90 | end
91 |
92 | function CraftSim.ReagentOptimizationResult:IsAllocated(recipeData)
93 | return CraftSim.REAGENT_OPTIMIZATION:IsCurrentAllocation(recipeData, self)
94 | end
95 |
96 | function CraftSim.ReagentOptimizationResult:OptimizeQualityIDs(considerSubCrafts)
97 | --- if qualityIDs of a reagent share their price with a higher quality, use the higher one (relevant for selfcrafted items mostly)
98 |
99 | for _, reagent in ipairs(self.reagents) do
100 | local lastPrice = 0
101 | local lastQuality = 1
102 | local lastReagentItem = nil
103 | for q, reagentItem in ipairs(reagent.items) do
104 | local currentPrice = CraftSim.PRICE_SOURCE:GetMinBuyoutByItemID(reagentItem.item:GetItemID(), true, false,
105 | considerSubCrafts)
106 |
107 | if q > lastQuality then
108 | if currentPrice == lastPrice and lastReagentItem then
109 | reagentItem.quantity = reagentItem.quantity + lastReagentItem.quantity
110 | lastReagentItem.quantity = 0
111 | end
112 | end
113 |
114 | lastQuality = q
115 | lastPrice = currentPrice
116 | lastReagentItem = reagentItem
117 | end
118 | end
119 | end
120 |
121 | --- required costs only
122 | ---@return number totalCraftingCostsRequired
123 | function CraftSim.ReagentOptimizationResult:GetTotalReagentCost()
124 | local reagentPriceInfos = self.recipeData.priceData.reagentPriceInfos
125 | local reagentItems = self:GetReagentItemList()
126 |
127 | return GUTIL:Fold(reagentItems, 0, function(totalCost, nextReagentItem)
128 | local itemPriceInfo = reagentPriceInfos[nextReagentItem.itemID]
129 | return totalCost + itemPriceInfo.itemPrice
130 | end)
131 | end
132 |
--------------------------------------------------------------------------------
/Classes/PerkData.lua:
--------------------------------------------------------------------------------
1 | ---@class CraftSim
2 | local CraftSim = select(2, ...)
3 |
4 | local GUTIL = CraftSim.GUTIL
5 |
6 | local print = CraftSim.DEBUG:RegisterDebugID("Classes.RecipeData.SpecializationData.NodeData.PerkData")
7 |
8 |
9 | ---@class CraftSim.PerkData : CraftSim.CraftSimObject
10 | ---@overload fun(baseNode: CraftSim.NodeData?, perkID: number?, perkData: CraftSim.RawPerkData?) : CraftSim.PerkData
11 | CraftSim.PerkData = CraftSim.CraftSimObject:extend()
12 |
13 | ---@param baseNode CraftSim.NodeData
14 | ---@param perkID number
15 | ---@param perkData CraftSim.RawPerkData
16 | function CraftSim.PerkData:new(baseNode, perkID, perkData)
17 | if not baseNode then return end
18 |
19 | self.recipeData = baseNode.recipeData
20 | self.baseNode = baseNode
21 | self.perkID = perkID
22 |
23 | ---@type CraftSim.ProfessionStats
24 | self.professionStats = CraftSim.ProfessionStats()
25 |
26 | self.threshold = C_ProfSpecs.GetUnlockRankForPerk(perkID)
27 | self.active = false
28 | self.raw_stats = perkData.stats or {}
29 |
30 |
31 | for stat, amount in pairs(self.raw_stats) do
32 | -- skill
33 | -- multicraft
34 | -- resourcefulness
35 | -- ingenuity
36 | -- craftingspeed
37 | if self.professionStats[stat] then
38 | self.professionStats[stat].value = amount or 0
39 | end
40 | if stat == "ingenuityrefundincrease" then
41 | self.professionStats.ingenuity:SetExtraValue((stat == "ingenuityrefundincrease" and (amount / 100)))
42 | elseif stat == "reduceconcentrationcost" then
43 | self.professionStats.ingenuity:SetExtraValue((stat == "reduceconcentrationcost" and (amount / 100)), 2)
44 | elseif stat == "reagentssavedfromresourcefulness" then
45 | self.professionStats.resourcefulness:SetExtraValue((stat == "reagentssavedfromresourcefulness" and (amount / 100)))
46 | elseif stat == "additionalitemscraftedwithmulticraft" then
47 | self.professionStats.multicraft:SetExtraValue((stat == "additionalitemscraftedwithmulticraft" and (amount / 100)))
48 | end
49 | end
50 | end
51 |
52 | function CraftSim.PerkData:Update()
53 | self.active = self.baseNode.rank >= self.threshold
54 | end
55 |
56 | function CraftSim.PerkData:Debug()
57 | local debugLines = {
58 | "perkID: " .. tostring(self.perkID),
59 | "threshold: " .. tostring(self.threshold),
60 | }
61 | local statLines = self.professionStats:Debug()
62 | statLines = CraftSim.GUTIL:Map(statLines, function(line) return "-" .. line end)
63 | debugLines = CraftSim.GUTIL:Concat({ debugLines, statLines })
64 | return debugLines
65 | end
66 |
67 | function CraftSim.PerkData:GetJSON(indent)
68 | indent = indent or 0
69 | local jb = CraftSim.JSONBuilder(indent)
70 | jb:Begin()
71 | jb:Add("nodeID", self.nodeData.nodeID)
72 | jb:Add("threshold", self.threshold)
73 | jb:Add("professionStats", self.professionStats)
74 | jb:Add("equalsSkill", self.equalsSkill)
75 | jb:Add("equalsMulticraft", self.equalsMulticraft)
76 | jb:Add("equalsResourcefulness", self.equalsResourcefulness)
77 | jb:Add("equalsIngenuity", self.equalsIngenuity)
78 | jb:Add("equalsCraftingspeed", self.equalsCraftingspeed)
79 | jb:Add("equalsResourcefulnessExtraItemsFactor", self.equalsResourcefulnessExtraItemsFactor)
80 | jb:Add("equalsIngenuityExtraConcentrationFactor", self.equalsIngenuityExtraConcentrationFactor)
81 | jb:Add("equalsPhialExperimentationChanceFactor", self.equalsPhialExperimentationChanceFactor)
82 | jb:Add("equalsPotionExperimentationChanceFactor", self.equalsPotionExperimentationChanceFactor, true)
83 | jb:End()
84 | return jb.json
85 | end
86 |
87 | ---@class CraftSim.PerkData.Serialized
88 | ---@field active boolean
89 | ---@field perkID number
90 | ---@field threshold number
91 | ---@field professionStats CraftSim.ProfessionStats.Serialized
92 | ---@field unlocksReagentSlot boolean
93 | ---@field stat string
94 | ---@field stat_amount number
95 |
96 |
97 | ---@return CraftSim.PerkData.Serialized
98 | function CraftSim.PerkData:Serialize()
99 | ---@type CraftSim.PerkData.Serialized
100 | local serialized = {
101 | active = self.active,
102 | perkID = self.perkID,
103 | threshold = self.threshold,
104 | professionStats = self.professionStats:Serialize(),
105 | unlocksReagentSlot = self.unlocksReagentSlot,
106 | stat = self.stat,
107 | stat_amount = self.stat_amount,
108 | }
109 |
110 | return serialized
111 | end
112 |
113 | ---@param baseNode CraftSim.NodeData
114 | ---@param serializedData CraftSim.PerkData.Serialized
115 | ---@return CraftSim.PerkData
116 | function CraftSim.PerkData:Deserialize(baseNode, serializedData)
117 | local perkData = CraftSim.PerkData()
118 | perkData.baseNode = baseNode
119 | perkData.active = serializedData.active
120 | perkData.perkID = serializedData.perkID
121 | perkData.threshold = serializedData.threshold
122 | perkData.unlocksReagentSlot = self.unlocksReagentSlot
123 | perkData.stat = self.stat
124 | perkData.stat_amount = self.stat_amount
125 | return perkData
126 | end
127 |
--------------------------------------------------------------------------------
/Libs/AceEvent-3.0/AceEvent-3.0.lua:
--------------------------------------------------------------------------------
1 | --- AceEvent-3.0 provides event registration and secure dispatching.
2 | -- All dispatching is done using **CallbackHandler-1.0**. AceEvent is a simple wrapper around
3 | -- CallbackHandler, and dispatches all game events or addon message to the registrees.
4 | --
5 | -- **AceEvent-3.0** can be embeded into your addon, either explicitly by calling AceEvent:Embed(MyAddon) or by
6 | -- specifying it as an embeded library in your AceAddon. All functions will be available on your addon object
7 | -- and can be accessed directly, without having to explicitly call AceEvent itself.\\
8 | -- It is recommended to embed AceEvent, otherwise you'll have to specify a custom `self` on all calls you
9 | -- make into AceEvent.
10 | -- @class file
11 | -- @name AceEvent-3.0
12 | -- @release $Id: AceEvent-3.0.lua 1202 2019-05-15 23:11:22Z nevcairiel $
13 | local CallbackHandler = LibStub("CallbackHandler-1.0")
14 |
15 | local MAJOR, MINOR = "AceEvent-3.0", 4
16 | local AceEvent = LibStub:NewLibrary(MAJOR, MINOR)
17 |
18 | if not AceEvent then return end
19 |
20 | -- Lua APIs
21 | local pairs = pairs
22 |
23 | AceEvent.frame = AceEvent.frame or CreateFrame("Frame", "AceEvent30Frame") -- our event frame
24 | AceEvent.embeds = AceEvent.embeds or {} -- what objects embed this lib
25 |
26 | -- APIs and registry for blizzard events, using CallbackHandler lib
27 | if not AceEvent.events then
28 | AceEvent.events = CallbackHandler:New(AceEvent,
29 | "RegisterEvent", "UnregisterEvent", "UnregisterAllEvents")
30 | end
31 |
32 | function AceEvent.events:OnUsed(target, eventname)
33 | AceEvent.frame:RegisterEvent(eventname)
34 | end
35 |
36 | function AceEvent.events:OnUnused(target, eventname)
37 | AceEvent.frame:UnregisterEvent(eventname)
38 | end
39 |
40 | -- APIs and registry for IPC messages, using CallbackHandler lib
41 | if not AceEvent.messages then
42 | AceEvent.messages = CallbackHandler:New(AceEvent,
43 | "RegisterMessage", "UnregisterMessage", "UnregisterAllMessages"
44 | )
45 | AceEvent.SendMessage = AceEvent.messages.Fire
46 | end
47 |
48 | --- embedding and embed handling
49 | local mixins = {
50 | "RegisterEvent", "UnregisterEvent",
51 | "RegisterMessage", "UnregisterMessage",
52 | "SendMessage",
53 | "UnregisterAllEvents", "UnregisterAllMessages",
54 | }
55 |
56 | --- Register for a Blizzard Event.
57 | -- The callback will be called with the optional `arg` as the first argument (if supplied), and the event name as the second (or first, if no arg was supplied)
58 | -- Any arguments to the event will be passed on after that.
59 | -- @name AceEvent:RegisterEvent
60 | -- @class function
61 | -- @paramsig event[, callback [, arg]]
62 | -- @param event The event to register for
63 | -- @param callback The callback function to call when the event is triggered (funcref or method, defaults to a method with the event name)
64 | -- @param arg An optional argument to pass to the callback function
65 |
66 | --- Unregister an event.
67 | -- @name AceEvent:UnregisterEvent
68 | -- @class function
69 | -- @paramsig event
70 | -- @param event The event to unregister
71 |
72 | --- Register for a custom AceEvent-internal message.
73 | -- The callback will be called with the optional `arg` as the first argument (if supplied), and the event name as the second (or first, if no arg was supplied)
74 | -- Any arguments to the event will be passed on after that.
75 | -- @name AceEvent:RegisterMessage
76 | -- @class function
77 | -- @paramsig message[, callback [, arg]]
78 | -- @param message The message to register for
79 | -- @param callback The callback function to call when the message is triggered (funcref or method, defaults to a method with the event name)
80 | -- @param arg An optional argument to pass to the callback function
81 |
82 | --- Unregister a message
83 | -- @name AceEvent:UnregisterMessage
84 | -- @class function
85 | -- @paramsig message
86 | -- @param message The message to unregister
87 |
88 | --- Send a message over the AceEvent-3.0 internal message system to other addons registered for this message.
89 | -- @name AceEvent:SendMessage
90 | -- @class function
91 | -- @paramsig message, ...
92 | -- @param message The message to send
93 | -- @param ... Any arguments to the message
94 |
95 |
96 | -- Embeds AceEvent into the target object making the functions from the mixins list available on target:..
97 | -- @param target target object to embed AceEvent in
98 | function AceEvent:Embed(target)
99 | for k, v in pairs(mixins) do
100 | target[v] = self[v]
101 | end
102 | self.embeds[target] = true
103 | return target
104 | end
105 |
106 | -- AceEvent:OnEmbedDisable( target )
107 | -- target (object) - target object that is being disabled
108 | --
109 | -- Unregister all events messages etc when the target disables.
110 | -- this method should be called by the target manually or by an addon framework
111 | function AceEvent:OnEmbedDisable(target)
112 | target:UnregisterAllEvents()
113 | target:UnregisterAllMessages()
114 | end
115 |
116 | -- Script to fire blizzard events into the event listeners
117 | local events = AceEvent.events
118 | AceEvent.frame:SetScript("OnEvent", function(this, event, ...)
119 | events:Fire(event, ...)
120 | end)
121 |
122 | --- Finally: upgrade our old embeds
123 | for target, v in pairs(AceEvent.embeds) do
124 | AceEvent:Embed(target)
125 | end
126 |
--------------------------------------------------------------------------------
/CraftSim.toc:
--------------------------------------------------------------------------------
1 | ## Interface: 110207
2 | ## DefaultState: enabled
3 |
4 | ## Title: CraftSim
5 | ## Category: Professions
6 | ## Category-deDE: Berufe
7 | ## Notes: Calculates the average profit based on your profession stats and other tools for the war within gold making
8 | ## Author: genju
9 | ## Version: 20.3.4
10 | ## X-Curse-Project-ID: 705015
11 | ## X-Wago-ID: 0mNwaPKo
12 | ## X-WoWI-ID: 26519
13 | ## AddonCompartmentFunc: CraftSim_OnAddonCompartmentClick
14 | ## IconTexture: Interface\Icons\inv_misc_coin_02
15 | ## SavedVariables: CraftSimDB
16 | ## Dependencies: Blizzard_Professions
17 | ## OptionalDeps: Auctionator, TradeSkillMaster, RECrystallize, OribosExchange
18 |
19 | embeds.xml
20 |
21 | Init/GLibs.lua
22 |
23 | Util/Const.lua
24 |
25 | Modules/Debug/Debug.lua
26 | Modules/Debug/UI.lua
27 |
28 | Util/Util.lua
29 |
30 | DB/DB.lua
31 | DB/optionsDB.lua
32 | DB/itemCountDB.lua
33 | DB/craftQueueDB.lua
34 | DB/itemRecipeDB.lua
35 | DB/itemOptimizedCostsDB.lua
36 | DB/recipeSubCrafterDB.lua
37 | DB/multicraftPreloadDB.lua
38 | DB/customerHistoryDB.lua
39 | DB/crafterDB.lua
40 | DB/priceOverrideDB.lua
41 |
42 | Media/Media.lua
43 |
44 | Util/Frames.lua
45 | Util/Widgets.lua
46 | Util/Comm.lua
47 | Util/API.lua
48 |
49 | Init/Init.lua
50 |
51 | Pricing/ProfitCalculation.lua
52 | Pricing/PriceAPIs.lua
53 | Pricing/PriceSource.lua
54 |
55 | Modules/ItemCount/ItemCount.lua
56 |
57 | Modules/Explanations/Explanations.lua
58 | Modules/Explanations/UI.lua
59 |
60 | Modules/CraftQueue/CraftQueue.lua
61 | Modules/CraftQueue/UI.lua
62 |
63 | Modules/Cooldowns/Cooldowns.lua
64 | Modules/Cooldowns/UI.lua
65 |
66 | Modules/CustomerHistory/CustomerHistory.lua
67 | Modules/CustomerHistory/UI.lua
68 |
69 | Modules/Statistics/Statistics.lua
70 | Modules/Statistics/UI.lua
71 |
72 | Modules/CraftLog/CraftLog.lua
73 | Modules/CraftLog/UI.lua
74 |
75 | Modules/PriceOverride/PriceOverride.lua
76 | Modules/PriceOverride/UI.lua
77 |
78 | Modules/ControlPanel/ControlPanel.lua
79 | Modules/ControlPanel/UI.lua
80 |
81 | Modules/SpecializationInfo/SpecializationInfo.lua
82 | Modules/SpecializationInfo/UI.lua
83 |
84 | Modules/Options/Options.lua
85 |
86 | Modules/SimulationMode/SimulationMode.lua
87 | Modules/SimulationMode/UI.lua
88 |
89 | Modules/AverageProfit/AverageProfit.lua
90 | Modules/AverageProfit/UI.lua
91 |
92 | Modules/ReagentOptimization/ReagentOptimization.lua
93 | Modules/ReagentOptimization/UI.lua
94 |
95 | Modules/TopGear/TopGear.lua
96 | Modules/TopGear/UI.lua
97 |
98 | Modules/RecipeScan/RecipeScan.lua
99 | Modules/RecipeScan/UI.lua
100 |
101 | Modules/PriceDetails/PriceDetails.lua
102 | Modules/PriceDetails/UI.lua
103 |
104 | Modules/CostOptimization/CostOptimization.lua
105 | Modules/CostOptimization/UI.lua
106 |
107 | Modules/Supporters/Supporters.lua
108 | Modules/Supporters/UI.lua
109 |
110 | Modules/CraftBuffs/CraftBuffs.lua
111 | Modules/CraftBuffs/UI.lua
112 |
113 | Modules/ConcentrationTracker/ConcentrationTracker.lua
114 | Modules/ConcentrationTracker/UI.lua
115 |
116 | Locals/Localization.lua
117 | Locals/enUS.lua
118 | Locals/deDE.lua
119 | Locals/itIT.lua
120 | Locals/ruRU.lua
121 | Locals/ptBR.lua
122 | Locals/frFR.lua
123 | Locals/esES.lua
124 | Locals/esMX.lua
125 | Locals/koKR.lua
126 | Locals/zhTW.lua
127 | Locals/zhCN.lua
128 |
129 | Data/EnchantData.lua
130 | Data/ReagentWeightData.lua
131 | Data/ConcentrationCurveData.lua
132 | Data/OptionalReagentData.lua
133 | Data/News.lua
134 |
135 | Data/SpecializationData/Dragonflight/Alchemy.lua
136 | Data/SpecializationData/Dragonflight/Blacksmithing.lua
137 | Data/SpecializationData/Dragonflight/Enchanting.lua
138 | Data/SpecializationData/Dragonflight/Inscription.lua
139 | Data/SpecializationData/Dragonflight/Jewelcrafting.lua
140 | Data/SpecializationData/Dragonflight/Leatherworking.lua
141 | Data/SpecializationData/Dragonflight/Tailoring.lua
142 | Data/SpecializationData/Dragonflight/Engineering.lua
143 |
144 | Data/SpecializationData/The_War_Within/Alchemy.lua
145 | Data/SpecializationData/The_War_Within/Blacksmithing.lua
146 | Data/SpecializationData/The_War_Within/Enchanting.lua
147 | Data/SpecializationData/The_War_Within/Inscription.lua
148 | Data/SpecializationData/The_War_Within/Jewelcrafting.lua
149 | Data/SpecializationData/The_War_Within/Leatherworking.lua
150 | Data/SpecializationData/The_War_Within/Tailoring.lua
151 | Data/SpecializationData/The_War_Within/Engineering.lua
152 | # needs to be last
153 | Data/SpecializationData/SpecializationData.lua
154 |
155 | Classes/CraftSimObject.lua
156 | Classes/OnCraftData.lua
157 | Classes/CooldownData.lua
158 | Classes/ProfessionData.lua
159 | Classes/ConcentrationData.lua
160 | Classes/RecipeData.lua
161 | Classes/PriceData.lua
162 | Classes/ReagentData.lua
163 | Classes/Reagent.lua
164 | Classes/ReagentItem.lua
165 | Classes/ReagentListItem.lua
166 | Classes/ProfessionStats.lua
167 | Classes/ProfessionStat.lua
168 | Classes/ProfessionGearSet.lua
169 | Classes/ProfessionGear.lua
170 | Classes/ResultData.lua
171 | Classes/OptionalReagentSlot.lua
172 | Classes/OptionalReagent.lua
173 | Classes/SalvageReagentSlot.lua
174 | Classes/SpecializationData.lua
175 | Classes/NodeData.lua
176 | Classes/PerkData.lua
177 | Classes/Statweights.lua
178 | Classes/ReagentOptimizationResult.lua
179 | Classes/TopGearResult.lua
180 | Classes/CraftResult.lua
181 | Classes/CraftResultItem.lua
182 | Classes/CraftResultReagent.lua
183 | Classes/CraftSessionData.lua
184 | Classes/CraftRecipeData.lua
185 | Classes/JSONBuilder.lua
186 | Classes/BuffData.lua
187 | Classes/Buff.lua
188 | Classes/CraftQueue.lua
189 | Classes/CraftQueueItem.lua
--------------------------------------------------------------------------------
/DB/itemOptimizedCostsDB.lua:
--------------------------------------------------------------------------------
1 | ---@class CraftSim
2 | local CraftSim = select(2, ...)
3 |
4 | local GUTIL = CraftSim.GUTIL
5 |
6 | ---@class CraftSim.DB
7 | CraftSim.DB = CraftSim.DB
8 |
9 | ---@class CraftSim.DB.ITEM_OPTIMIZED_COSTS : CraftSim.DB.Repository
10 | CraftSim.DB.ITEM_OPTIMIZED_COSTS = CraftSim.DB:RegisterRepository()
11 |
12 | ---@class CraftSim.ExpectedCraftingCostsData
13 | ---@field qualityID QualityID
14 | ---@field crafter CrafterUID
15 | ---@field expectedCostsPerItem number
16 | ---@field expectedYieldPerCraft number
17 | ---@field profession Enum.Profession
18 | ---@field concentration boolean
19 | ---@field concentrationCost number
20 |
21 | local print = CraftSim.DEBUG:RegisterDebugID("Database.itemOptimizedCostsDB")
22 |
23 | function CraftSim.DB.ITEM_OPTIMIZED_COSTS:Init()
24 | if not CraftSimDB.itemOptimizedCostsDB then
25 | ---@type CraftSimDB.Database
26 | CraftSimDB.itemOptimizedCostsDB = {
27 | version = 0,
28 | ---@type table>
29 | data = {},
30 | }
31 | end
32 |
33 | CraftSimDB.itemOptimizedCostsDB.data = CraftSimDB.itemOptimizedCostsDB.data or {}
34 | end
35 |
36 | function CraftSim.DB.ITEM_OPTIMIZED_COSTS:Migrate()
37 | -- 0 -> 1
38 | if CraftSimDB.itemOptimizedCostsDB.version == 0 then
39 | local CraftSimRecipeDataCache = _G["CraftSimRecipeDataCache"]
40 | if CraftSimRecipeDataCache then
41 | CraftSimDB.itemOptimizedCostsDB.data = CraftSimRecipeDataCache["itemOptimizedCostsDataCache"] or {}
42 | end
43 | CraftSimDB.itemOptimizedCostsDB.version = 1
44 | end
45 |
46 | -- 1 -> 2 (16.1.2 -> 16.1.3)
47 | if CraftSimDB.itemOptimizedCostsDB.version == 1 then
48 | -- remove any crafter entries with colored names...
49 | for _, data in pairs(CraftSimDB.itemOptimizedCostsDB.data or {}) do
50 | for crafterUID, _ in pairs(data) do
51 | if string.find(crafterUID, '\124c') then
52 | data[crafterUID] = nil
53 | end
54 | end
55 | end
56 |
57 | CraftSimDB.itemOptimizedCostsDB.version = 2
58 | end
59 |
60 | -- 2 -> 3 (17.0.0 - TWW)
61 | if CraftSimDB.itemOptimizedCostsDB.version == 2 then
62 | -- clear the db for a reset
63 | self:ClearAll()
64 | CraftSimDB.itemOptimizedCostsDB.version = 3
65 | end
66 |
67 | -- 3 -> 4 (TWW SubRecipe Rework)
68 | if CraftSimDB.itemOptimizedCostsDB.version == 3 then
69 | -- clear the db for a reset
70 | self:ClearAll()
71 | CraftSimDB.itemOptimizedCostsDB.version = 4
72 | end
73 | end
74 |
75 | function CraftSim.DB.ITEM_OPTIMIZED_COSTS:ClearAll()
76 | wipe(CraftSimDB.itemOptimizedCostsDB.data)
77 | end
78 |
79 | function CraftSim.DB.ITEM_OPTIMIZED_COSTS:CleanUp()
80 | local CraftSimRecipeDataCache = _G["CraftSimRecipeDataCache"]
81 | if CraftSimRecipeDataCache and CraftSimRecipeDataCache["itemOptimizedCostsDataCache"] then
82 | CraftSimRecipeDataCache["itemOptimizedCostsDataCache"] = nil
83 | end
84 | end
85 |
86 | ---@param itemID ItemID
87 | ---@param crafterUID CrafterUID
88 | ---@return CraftSim.ExpectedCraftingCostsData?
89 | function CraftSim.DB.ITEM_OPTIMIZED_COSTS:Get(itemID, crafterUID)
90 | CraftSimDB.itemOptimizedCostsDB.data[itemID] = CraftSimDB.itemOptimizedCostsDB.data[itemID] or {}
91 |
92 | return CraftSimDB.itemOptimizedCostsDB.data[itemID][crafterUID]
93 | end
94 |
95 | ---@param recipeData CraftSim.RecipeData
96 | function CraftSim.DB.ITEM_OPTIMIZED_COSTS:Add(recipeData)
97 | -- cache the results if not gear and if its learned only
98 | if not recipeData.isGear and recipeData.learned then
99 | -- only if reachable
100 | for qualityID, item in ipairs(recipeData.resultData.itemsByQuality) do
101 | local reachable = qualityID <= recipeData.resultData.expectedQualityConcentration
102 | if reachable then
103 | print("Caching Optimized Costs Data for: " .. recipeData.recipeName .. " q" .. qualityID)
104 | local itemID = item:GetItemID()
105 | CraftSimDB.itemOptimizedCostsDB.data[itemID] = CraftSimDB.itemOptimizedCostsDB.data[itemID] or {}
106 |
107 | local concentrationAvailable = recipeData.concentrationCost > 0
108 | local concentration = qualityID == recipeData.resultData.expectedQualityConcentration and
109 | concentrationAvailable
110 |
111 | -- Ensure expectedCostsPerItem is not nil to prevent GUTIL:Round errors
112 | local expectedCostsPerItem = recipeData.priceData.expectedCostsPerItem or 0
113 |
114 | ---@type CraftSim.ExpectedCraftingCostsData
115 | CraftSimDB.itemOptimizedCostsDB.data[itemID][recipeData:GetCrafterUID()] = {
116 | crafter = recipeData:GetCrafterUID(),
117 | qualityID = qualityID,
118 | expectedCostsPerItem = expectedCostsPerItem,
119 | expectedYieldPerCraft = recipeData.resultData.expectedYieldPerCraft,
120 | concentration = concentration,
121 | concentrationCost = recipeData.concentrationCost,
122 | profession = recipeData.professionData.professionInfo.profession,
123 | }
124 | end
125 | end
126 | end
127 | end
128 |
--------------------------------------------------------------------------------
/Modules/Supporters/UI.lua:
--------------------------------------------------------------------------------
1 | ---@class CraftSim
2 | local CraftSim = select(2, ...)
3 |
4 | local GUTIL = CraftSim.GUTIL
5 |
6 | local f = GUTIL:GetFormatter()
7 |
8 | ---@class CraftSim.SUPPORTERS
9 | CraftSim.SUPPORTERS = CraftSim.SUPPORTERS
10 |
11 | ---@class CraftSim.SUPPORTERS.UI
12 | CraftSim.SUPPORTERS.UI = {}
13 |
14 | function CraftSim.SUPPORTERS.UI:Init()
15 | local sizeX = 600
16 | local sizeY = 500
17 |
18 | local frameLevel = CraftSim.UTIL:NextFrameLevel()
19 |
20 | local frame = CraftSim.GGUI.Frame({
21 | parent = ProfessionsFrame,
22 | anchorParent = UIParent,
23 | sizeX = sizeX,
24 | sizeY = sizeY,
25 | frameID = CraftSim.CONST.FRAMES.SUPPORTERS,
26 | title = CraftSim.LOCAL:GetText(CraftSim.CONST.TEXT.CONTROL_PANEL_SUPPORTERS_BUTTON),
27 | collapseable = true,
28 | closeable = true,
29 | moveable = true,
30 | backdropOptions = CraftSim.CONST.DEFAULT_BACKDROP_OPTIONS,
31 | frameTable = CraftSim.INIT.FRAMES,
32 | frameConfigTable = CraftSim.DB.OPTIONS:Get("GGUI_CONFIG"),
33 | frameStrata = CraftSim.CONST.MODULES_FRAME_STRATA,
34 | raiseOnInteraction = true,
35 | frameLevel = frameLevel
36 | })
37 |
38 | local function createContent(frame)
39 | frame:Hide()
40 | frame.content.description = CraftSim.GGUI.Text({
41 | parent = frame.content,
42 | anchorParent = frame.content,
43 | anchorA = "TOP",
44 | anchorB = "TOP",
45 | offsetY = -40,
46 | text =
47 | CraftSim.LOCAL:GetText(CraftSim.CONST.TEXT.SUPPORTERS_DESCRIPTION)
48 | })
49 |
50 | frame.content.donateBox = CraftSim.FRAME:CreateInput(
51 | nil, frame.content, frame.content.description.frame, "TOP", "BOTTOM", 0, -40, 250, 30,
52 | CraftSim.CONST.DISCORD_INVITE_URL, function()
53 | -- do not let the player remove the link
54 | frame.content.donateBox:SetText(CraftSim.CONST.DISCORD_INVITE_URL)
55 | end)
56 | frame.content.donateBox:SetScale(0.75)
57 | frame.content.donateBoxLabel = CraftSim.FRAME:CreateText(
58 | f.patreon(CraftSim.LOCAL:GetText(CraftSim.CONST.TEXT.SUPPORTERS_DESCRIPTION_2)), frame.content,
59 | frame.content.donateBox, "BOTTOM", "TOP", 0, 0, 1)
60 |
61 | frame.content.supportersList = CraftSim.GGUI.FrameList({
62 | parent = frame.content,
63 | anchorParent = frame.content.donateBox,
64 | offsetY = -30,
65 | anchorA = "TOP",
66 | anchorB = "BOTTOM",
67 | sizeY = 350,
68 | rowHeight = 60,
69 | showBorder = true,
70 | columnOptions = {
71 | {
72 | label = CraftSim.LOCAL:GetText(CraftSim.CONST.TEXT.SUPPORTERS_DATE),
73 | width = 100,
74 | },
75 | {
76 | label = CraftSim.LOCAL:GetText(CraftSim.CONST.TEXT.SUPPORTERS_SUPPORTER),
77 | width = 100,
78 | },
79 | {
80 | label = CraftSim.LOCAL:GetText(CraftSim.CONST.TEXT.SUPPORTERS_MESSAGE),
81 | width = 300,
82 | },
83 | },
84 | rowConstructor = function(columns)
85 | local dateColumn = columns[1]
86 | local nameColumn = columns[2]
87 | local messageColumn = columns[3]
88 |
89 | ---@type GGUI.Text | GGUI.Widget
90 | dateColumn.text = CraftSim.GGUI.Text({
91 | parent = dateColumn,
92 | anchorParent = dateColumn,
93 | text = "",
94 | justifyOptions = { type = "H", align = "LEFT" },
95 | fixedWidth = dateColumn:GetWidth(),
96 | })
97 | ---@type GGUI.Text | GGUI.Widget
98 | nameColumn.text = CraftSim.GGUI.Text({
99 | parent = nameColumn,
100 | anchorParent = nameColumn,
101 | text = "",
102 | justifyOptions = { type = "H", align = "LEFT" },
103 | fixedWidth = nameColumn:GetWidth(),
104 | })
105 | ---@type GGUI.Text | GGUI.Widget
106 | messageColumn.text = CraftSim.GGUI.Text({
107 | parent = messageColumn,
108 | anchorParent = messageColumn,
109 | text = "",
110 | justifyOptions = { type = "H", align = "LEFT" },
111 | fixedWidth = messageColumn:GetWidth(),
112 | })
113 | end
114 | })
115 |
116 | table.foreach(CraftSim.SUPPORTERS:GetList(), function(_, supporter)
117 | frame.content.supportersList:Add(function(row)
118 | local dateColumn = row.columns[1]
119 | local nameColumn = row.columns[2]
120 | local messageColumn = row.columns[3]
121 |
122 | dateColumn.text:SetText(supporter.date)
123 | nameColumn.text:SetText(supporter.name)
124 | messageColumn.text:SetText(supporter.message)
125 | end)
126 | end)
127 |
128 | frame.content.supportersList:UpdateDisplay()
129 | end
130 |
131 | createContent(frame)
132 | end
133 |
--------------------------------------------------------------------------------
/DB/ItemCountDB.lua:
--------------------------------------------------------------------------------
1 | ---@class CraftSim
2 | local CraftSim = select(2, ...)
3 |
4 | local GUTIL = CraftSim.GUTIL
5 |
6 | local print = CraftSim.DEBUG:RegisterDebugID("Database.ItemCountDB")
7 |
8 | ---@class CraftSim.DB
9 | CraftSim.DB = CraftSim.DB
10 |
11 |
12 | ---@class CraftSim.DB.ITEM_COUNT.CharacterItemCountData
13 | ---@field bank table
14 | ---@field inventory table
15 |
16 | ---@class CraftSim.DB.ITEM_COUNT : CraftSim.DB.Repository
17 | CraftSim.DB.ITEM_COUNT = CraftSim.DB:RegisterRepository()
18 |
19 | function CraftSim.DB.ITEM_COUNT:Init()
20 | if not CraftSimDB.itemCountDB then
21 | ---@type CraftSimDB.Database
22 | CraftSimDB.itemCountDB = {
23 | data = {
24 | ---@type table
25 | accountBank = {},
26 | ---@type table
27 | characters = {}
28 | },
29 | version = 0,
30 | }
31 | end
32 |
33 | CraftSimDB.itemCountDB.data = CraftSimDB.itemCountDB.data or {}
34 | end
35 |
36 | function CraftSim.DB.ITEM_COUNT:Migrate()
37 | -- 0 -> 1
38 | if CraftSimDB.itemCountDB.version == 0 then
39 | CraftSimDB.itemCountDB.data = CraftSimItemCountCache or {}
40 | CraftSimDB.itemCountDB.version = 1
41 | end
42 |
43 | -- 1 -> 2 (16.1.2 -> 16.1.3)
44 | if CraftSimDB.itemCountDB.version == 1 then
45 | -- remove any crafter entries with colored names...
46 | for crafterUID, _ in pairs(CraftSimDB.itemCountDB.data or {}) do
47 | if string.find(crafterUID, '\124c') then
48 | CraftSimDB.itemCountDB.data[crafterUID] = nil
49 | end
50 | end
51 |
52 | CraftSimDB.itemCountDB.version = 2
53 | end
54 |
55 | -- 2 -> 3 rebuild
56 | if CraftSimDB.itemCountDB.version == 2 then
57 | self:ClearAll()
58 | CraftSimDB.itemCountDB.data = {
59 | accountBank = {},
60 | characters = {}
61 | }
62 | CraftSimDB.itemCountDB.version = 3
63 | end
64 | end
65 |
66 | function CraftSim.DB.ITEM_COUNT:CleanUp()
67 | if _G["CraftSimItemCountCache"] then
68 | -- remove it
69 | _G["CraftSimItemCountCache"] = nil
70 | end
71 | end
72 |
73 | function CraftSim.DB.ITEM_COUNT:ClearAll()
74 | wipe(CraftSimDB.itemCountDB.data)
75 | end
76 |
77 | ---@param crafterUID CrafterUID
78 | ---@param itemID number
79 | ---@param includeBank? boolean -- reagentBank + bank
80 | ---@param includeAccountBank? boolean
81 | ---@return number itemCount
82 | function CraftSim.DB.ITEM_COUNT:Get(crafterUID, itemID, includeBank, includeAccountBank)
83 | CraftSimDB.itemCountDB.data.characters = CraftSimDB.itemCountDB.data.characters or {}
84 | CraftSimDB.itemCountDB.data.characters[crafterUID] = CraftSimDB.itemCountDB.data.characters[crafterUID] or {
85 | bank = {},
86 | inventory = {}
87 | }
88 | local itemCount = CraftSimDB.itemCountDB.data.characters[crafterUID].inventory[itemID] or 0
89 |
90 | if includeBank then
91 | itemCount = itemCount + (CraftSimDB.itemCountDB.data.characters[crafterUID].bank[itemID] or 0)
92 | end
93 |
94 | if includeAccountBank then
95 | itemCount = itemCount + self:GetAccountBankCount(itemID)
96 | end
97 |
98 | return itemCount
99 | end
100 |
101 | ---@param crafterUID CrafterUID
102 | ---@param itemID number
103 | ---@param count number
104 | function CraftSim.DB.ITEM_COUNT:SaveInventoryCount(crafterUID, itemID, count)
105 | CraftSimDB.itemCountDB.data.characters = CraftSimDB.itemCountDB.data.characters or {}
106 | CraftSimDB.itemCountDB.data.characters[crafterUID] = CraftSimDB.itemCountDB.data.characters[crafterUID] or {
107 | bank = {},
108 | inventory = {}
109 | }
110 | CraftSimDB.itemCountDB.data.characters[crafterUID].inventory[itemID] = count
111 | end
112 |
113 | ---@param crafterUID CrafterUID
114 | ---@param itemID number
115 | ---@param count number
116 | function CraftSim.DB.ITEM_COUNT:SaveBankCount(crafterUID, itemID, count)
117 | CraftSimDB.itemCountDB.data.characters = CraftSimDB.itemCountDB.data.characters or {}
118 | CraftSimDB.itemCountDB.data.characters[crafterUID] = CraftSimDB.itemCountDB.data.characters[crafterUID] or {
119 | bank = {},
120 | inventory = {}
121 | }
122 | CraftSimDB.itemCountDB.data.characters[crafterUID].bank[itemID] = count
123 | end
124 |
125 | ---@param itemID number
126 | ---@param count number
127 | function CraftSim.DB.ITEM_COUNT:SaveAccountBankCount(itemID, count)
128 | CraftSimDB.itemCountDB.data.accountBank = CraftSimDB.itemCountDB.data.accountBank or {}
129 | CraftSimDB.itemCountDB.data.accountBank[itemID] = count
130 | end
131 |
132 | ---@param crafterUID CrafterUID
133 | ---@param itemID number
134 | ---@param inventory number
135 | ---@param bank number
136 | ---@param accountBank number
137 | function CraftSim.DB.ITEM_COUNT:UpdateItemCounts(crafterUID, itemID, inventory, bank, accountBank)
138 | self:SaveInventoryCount(crafterUID, itemID, inventory)
139 | self:SaveBankCount(crafterUID, itemID, bank)
140 | self:SaveAccountBankCount(itemID, accountBank)
141 | end
142 |
143 | ---@param itemID number
144 | ---@return number count
145 | function CraftSim.DB.ITEM_COUNT:GetAccountBankCount(itemID)
146 | CraftSimDB.itemCountDB.data.accountBank = CraftSimDB.itemCountDB.data.accountBank or {}
147 | return CraftSimDB.itemCountDB.data.accountBank[itemID] or 0
148 | end
149 |
--------------------------------------------------------------------------------
/Classes/ReagentItem.lua:
--------------------------------------------------------------------------------
1 | ---@class CraftSim
2 | local CraftSim = select(2, ...)
3 |
4 | local GUTIL = CraftSim.GUTIL
5 |
6 | ---@class CraftSim.ReagentItem : CraftSim.CraftSimObject
7 | CraftSim.ReagentItem = CraftSim.CraftSimObject:extend()
8 |
9 | local print = CraftSim.DEBUG:RegisterDebugID("Classes.RecipeData.ReagentData.Reagent.ReagentItem")
10 |
11 | ---@param originalItemID ItemID
12 | ---@param qualityID QualityID?
13 | function CraftSim.ReagentItem:new(originalItemID, qualityID)
14 | -- consider possible exception mappings
15 | local alternativeItemID = CraftSim.CONST.REAGENT_ID_EXCEPTION_MAPPING[originalItemID]
16 | local itemID = alternativeItemID or originalItemID
17 |
18 | self.qualityID = qualityID
19 | --- how much of that reagentItem has been allocated for this recipe
20 | self.quantity = 0
21 | self.item = Item:CreateFromItemID(itemID)
22 | if alternativeItemID then
23 | self.originalItem = Item:CreateFromItemID(originalItemID)
24 | end
25 | end
26 |
27 | ---@return CraftSim.ReagentListItem
28 | function CraftSim.ReagentItem:GetAsReagentListItem()
29 | return {
30 | itemID = self.item:GetItemID(),
31 | quantity = self.quantity,
32 | }
33 | end
34 |
35 | function CraftSim.ReagentItem:Copy()
36 | local copy = nil
37 | if self.originalItem then
38 | copy = CraftSim.ReagentItem(self.originalItem:GetItemID(), self.qualityID)
39 | else
40 | copy = CraftSim.ReagentItem(self.item:GetItemID(), self.qualityID)
41 | end
42 | copy.quantity = self.quantity
43 |
44 | return copy
45 | end
46 |
47 | function CraftSim.ReagentItem:Debug()
48 | return {
49 | tostring(((self.item and (self.item:GetItemLink() or self.item:GetItemID())) or "None") .. " x " .. self
50 | .quantity),
51 | }
52 | end
53 |
54 | function CraftSim.ReagentItem:Clear()
55 | self.quantity = 0
56 | end
57 |
58 | --- returns wether the player has enough of the given required item's allocations (times the multiplier) for crafting
59 | ---@param multiplier number? default: 1
60 | ---@param crafterUID string
61 | function CraftSim.ReagentItem:HasItem(multiplier, crafterUID)
62 | multiplier = multiplier or 1
63 | if not self.item then
64 | return false
65 | end
66 | -- only count the item actually used in the recipe (originalItem if we have one)
67 | -- in the case of e.g. rimefin tuna we want to count the non frosted one only (will be the original)
68 | local itemID = (self.originalItem and self.originalItem:GetItemID()) or self.item:GetItemID()
69 | local itemCount = CraftSim.CRAFTQ:GetItemCountFromCraftQueueCache(crafterUID, itemID)
70 | return itemCount >= (self.quantity * multiplier)
71 | end
72 |
73 | ---@class CraftSim.ReagentItem.Serialized
74 | ---@field qualityID number
75 | ---@field quantity number
76 | ---@field itemID number
77 | ---@field originalItemID number
78 |
79 | function CraftSim.ReagentItem:Serialize()
80 | local serizalized = {}
81 | serizalized.qualityID = self.qualityID
82 | serizalized.quantity = self.quantity
83 | serizalized.itemID = self.item:GetItemID()
84 | serizalized.originalItemID = self.originalItem and self.originalItem:GetItemID()
85 | return serizalized
86 | end
87 |
88 | --- STATIC
89 | ---@param serializedReagentItem CraftSim.ReagentItem.Serialized
90 | function CraftSim.ReagentItem:Deserialize(serializedReagentItem)
91 | local deserialized = CraftSim.ReagentItem(tonumber(serializedReagentItem.itemID),
92 | tonumber(serializedReagentItem.qualityID))
93 | deserialized.quantity = tonumber(serializedReagentItem.quantity)
94 | return deserialized
95 | end
96 |
97 | function CraftSim.ReagentItem:GetJSON(indent)
98 | indent = indent or 0
99 | local jb = CraftSim.JSONBuilder(indent)
100 | jb:Begin()
101 | jb:Add("qualityID", self.qualityID)
102 | jb:Add("quantity", self.quantity)
103 | jb:Add("itemID", self.item:GetItemID(), true)
104 | jb:End()
105 | return jb.json
106 | end
107 |
108 | ---@param recipeData CraftSim.RecipeData
109 | ---@return boolean
110 | function CraftSim.ReagentItem:IsOrderReagentIn(recipeData)
111 | if not recipeData.orderData then return false end
112 |
113 | local orderItemIDs = GUTIL:Map(recipeData.orderData.reagents or {}, function(reagentInfo)
114 | return reagentInfo.reagent.itemID
115 | end)
116 |
117 | return tContains(orderItemIDs, self.item:GetItemID())
118 | end
119 |
120 | ---@deprecated
121 | ---@param recipeData CraftSim.RecipeData
122 | function CraftSim.ReagentItem:GetSkillContributionPerItem(recipeData)
123 | if self.qualityID <= 1 then
124 | return 0
125 | end
126 |
127 | local reagentWeight = CraftSim.REAGENT_OPTIMIZATION:GetReagentWeightByID(self.item:GetItemID())
128 | local weightList = {}
129 | for _, reagent in ipairs(recipeData.reagentData.requiredReagents) do
130 | if reagent.hasQuality then
131 | tinsert(weightList, CraftSim.REAGENT_OPTIMIZATION:GetReagentWeightByID(reagent.items[1].item:GetItemID()))
132 | end
133 | end
134 |
135 | local weightGCD = GUTIL:Fold(weightList, 0, function(a, b)
136 | return CraftSim.REAGENT_OPTIMIZATION:GetGCD(a, b)
137 | end)
138 |
139 | if weightGCD == 0 then
140 | weightGCD = 1
141 | end
142 |
143 | local relativeWeight = reagentWeight / weightGCD
144 |
145 | local reagentSkillContributionFactor = relativeWeight * (self.qualityID - 1)
146 |
147 | local skillContribution = recipeData.reagentsMaxSkillContribution * reagentSkillContributionFactor
148 |
149 | -- quality contribution Q1 = 0
150 | -- quality contribution Q2 = relative weight
151 | -- quality contribution Q3 = relative weight * 2
152 |
153 | return skillContribution
154 | end
155 |
--------------------------------------------------------------------------------
/Modules/Debug/Debug.lua:
--------------------------------------------------------------------------------
1 | ---@class CraftSim
2 | local CraftSim = select(2, ...)
3 |
4 | ---@class CraftSim.DEBUG
5 | CraftSim.DEBUG = {}
6 |
7 | ---@type table
8 | CraftSim.DEBUG.profilings = {}
9 | CraftSim.DEBUG.isMute = false
10 | CraftSim.DEBUG.registeredDebugIDs = {}
11 |
12 | ---@class CraftSim.DEBUG.FRAME
13 | CraftSim.DEBUG.frame = nil
14 |
15 | local GUTIL = CraftSim.GUTIL
16 |
17 | local systemPrint = print
18 |
19 | ---@param debugID string Format: Category.(...).ID
20 | ---@return fun(text: string, recursiveTablePrint: boolean?, printLabel: boolean?, intent: number?)
21 | function CraftSim.DEBUG:RegisterDebugID(debugID)
22 | -- check for each subID
23 | local splitIDs = strsplittable(".", debugID)
24 | local fullID = ""
25 | for i, splitID in ipairs(splitIDs) do
26 | if i == 1 then
27 | fullID = splitID
28 | else
29 | fullID = string.format("%s.%s", fullID, splitID)
30 | end
31 | if not tContains(self.registeredDebugIDs, fullID) then
32 | tinsert(self.registeredDebugIDs, fullID)
33 | end
34 | end
35 | local function print(text, recursive, l, level)
36 | if CraftSim.DEBUG and CraftSim.DEBUG.frame then
37 | CraftSim.DEBUG:print(text, debugID, recursive, l, level)
38 | else
39 | systemPrint(text)
40 | end
41 | end
42 |
43 | return print
44 | end
45 |
46 | ---@return string[]
47 | function CraftSim.DEBUG:GetRegisteredDebugIDs()
48 | return self.registeredDebugIDs
49 | end
50 |
51 | function CraftSim.DEBUG:SystemPrint(text)
52 | print(text)
53 | end
54 |
55 | ---@param t table
56 | ---@param label string?
57 | ---@param openDevTool boolean?
58 | function CraftSim.DEBUG:InspectTable(t, label, openDevTool)
59 | if DevTool then
60 | if openDevTool then
61 | DevTool.MainWindow:Show()
62 | end
63 | DevTool:AddData(t, label)
64 | end
65 | end
66 |
67 | function CraftSim.DEBUG:print(debugOutput, debugID, recursive, printLabel, level)
68 | local debugIDsDB = CraftSim.DB.OPTIONS:Get("DEBUG_IDS")
69 | if debugIDsDB[debugID] and not CraftSim.DEBUG.isMute then
70 | if type(debugOutput) == "table" then
71 | CraftSim.DEBUG:PrintTable(debugOutput, debugID, recursive, level)
72 | else
73 | local debugFrame = CraftSim.GGUI:GetFrame(CraftSim.INIT.FRAMES, CraftSim.CONST.FRAMES.DEBUG)
74 | debugFrame.addDebug(debugOutput, debugID, printLabel)
75 | end
76 | end
77 | end
78 |
79 | -- for debug purposes
80 | function CraftSim.DEBUG:PrintTable(t, debugID, recursive, level)
81 | level = level or 0
82 | local levelString = ""
83 | for i = 1, level, 1 do
84 | levelString = levelString .. "-"
85 | end
86 |
87 | if t.Debug then
88 | for _, line in pairs(t:Debug()) do
89 | CraftSim.DEBUG:print(levelString .. tostring(line), debugID, false)
90 | end
91 | return
92 | end
93 |
94 | for k, v in pairs(t) do
95 | if type(v) == 'function' then
96 | CraftSim.DEBUG:print(levelString .. tostring(k) .. ": function", debugID, false)
97 | elseif not recursive or type(v) ~= "table" then
98 | CraftSim.DEBUG:print(levelString .. tostring(k) .. ": " .. tostring(v), debugID, false)
99 | elseif type(v) == "table" then
100 | CraftSim.DEBUG:print(levelString .. tostring(k) .. ": ", debugID, false)
101 | CraftSim.DEBUG:PrintTable(v, debugID, recursive, level + 1)
102 | end
103 | end
104 | end
105 |
106 | function CraftSim.DEBUG:ProfilingUpdate(label)
107 | local print = CraftSim.DEBUG:RegisterDebugID("Profiling")
108 | local time = debugprofilestop()
109 | local diff = time - CraftSim.DEBUG.profilings[label]
110 | print(label .. ": " .. CraftSim.GUTIL:Round(diff) .. " ms (u)")
111 | end
112 |
113 | ---@param label string
114 | function CraftSim.DEBUG:StartProfiling(label)
115 | local time = debugprofilestop();
116 | CraftSim.DEBUG.profilings[label] = time
117 | end
118 |
119 | ---@param label string
120 | ---@return number milliseconds since StartProfiling was called
121 | function CraftSim.DEBUG:StopProfiling(label)
122 | local startTime = CraftSim.DEBUG.profilings[label]
123 | if not startTime then
124 | print("Util Profiling Label not found on Stop: " .. tostring(label))
125 | return 0
126 | end
127 | local time = debugprofilestop()
128 | local diff = CraftSim.GUTIL:Round(time - startTime)
129 | CraftSim.DEBUG.profilings[label] = nil
130 | CraftSim.DEBUG:print(label .. ": " .. diff .. " ms", "Profiling")
131 | return diff
132 | end
133 |
134 | ---@deprecated
135 | function CraftSim.DEBUG:GetCacheGlobalsList()
136 | return {
137 | }
138 | end
139 |
140 | function CraftSim.DEBUG:ShowOutdatedSpecNodes()
141 | local specializationData = CraftSim.INIT.currentRecipeData.specializationData
142 | if not specializationData then return end
143 |
144 | local sortedNodes = GUTIL:Sort(specializationData.nodeData, function(a, b)
145 | if a.name > b.name then
146 | return true
147 | elseif a.name < b.name then
148 | return false
149 | end
150 |
151 | return a.nodeID < b.nodeID
152 | end)
153 |
154 | ---@type CraftSim.NodeData[]
155 | local outliers = {}
156 |
157 | for i = 1, #sortedNodes do
158 | local nodeData = sortedNodes[i]
159 | local nextData = sortedNodes[i + 1]
160 | if nodeData and nextData then
161 | if nodeData.name == nextData.name then
162 | tinsert(outliers, nodeData)
163 | end
164 | end
165 | end
166 |
167 | if #outliers == 0 then return end
168 |
169 | local currentName = outliers[1].name
170 | local text = "## " .. currentName .. "\n"
171 |
172 | for _, nodeData in ipairs(outliers) do
173 | if currentName ~= nodeData.name then
174 | text = text .. "\n## " .. nodeData.name .. "\n"
175 | currentName = nodeData.name
176 | end
177 | text = text .. nodeData.nodeID .. ", "
178 | end
179 |
180 | CraftSim.UTIL:ShowTextCopyBox(text)
181 | end
182 |
--------------------------------------------------------------------------------
/Data/SpecializationData/SpecializationData.lua:
--------------------------------------------------------------------------------
1 | ---@class CraftSim
2 | local CraftSim = select(2, ...)
3 |
4 | local GUTIL = CraftSim.GUTIL
5 |
6 | ---@class CraftSim.SPECIALIZATION_DATA
7 | CraftSim.SPECIALIZATION_DATA = CraftSim.SPECIALIZATION_DATA
8 |
9 | ---@class CraftSim.RawPerkData
10 | ---@field nodeID number
11 | ---@field maxRank number
12 | ---@field stats? table statname -> amount
13 |
14 | ---@class CraftSim.RawNodeData
15 | ---@field recipeMapping table
16 | ---@field nodeData table
17 |
18 |
19 | local print = CraftSim.DEBUG:RegisterDebugID("Data.SpecializationData")
20 |
21 | ---@type table>
22 | CraftSim.SPECIALIZATION_DATA.NODE_DATA = {
23 | [CraftSim.CONST.EXPANSION_IDS.DRAGONFLIGHT] = {
24 | [Enum.Profession.Blacksmithing] = CraftSim.SPECIALIZATION_DATA.DRAGONFLIGHT.BLACKSMITHING_DATA,
25 | [Enum.Profession.Alchemy] = CraftSim.SPECIALIZATION_DATA.DRAGONFLIGHT.ALCHEMY_DATA,
26 | [Enum.Profession.Leatherworking] = CraftSim.SPECIALIZATION_DATA.DRAGONFLIGHT.LEATHERWORKING_DATA,
27 | [Enum.Profession.Jewelcrafting] = CraftSim.SPECIALIZATION_DATA.DRAGONFLIGHT.JEWELCRAFTING_DATA,
28 | [Enum.Profession.Enchanting] = CraftSim.SPECIALIZATION_DATA.DRAGONFLIGHT.ENCHANTING_DATA,
29 | [Enum.Profession.Tailoring] = CraftSim.SPECIALIZATION_DATA.DRAGONFLIGHT.TAILORING_DATA,
30 | [Enum.Profession.Inscription] = CraftSim.SPECIALIZATION_DATA.DRAGONFLIGHT.INSCRIPTION_DATA,
31 | [Enum.Profession.Engineering] = CraftSim.SPECIALIZATION_DATA.DRAGONFLIGHT.ENGINEERING_DATA
32 | },
33 | [CraftSim.CONST.EXPANSION_IDS.THE_WAR_WITHIN] = {
34 | [Enum.Profession.Blacksmithing] = CraftSim.SPECIALIZATION_DATA.THE_WAR_WITHIN.BLACKSMITHING_DATA,
35 | [Enum.Profession.Alchemy] = CraftSim.SPECIALIZATION_DATA.THE_WAR_WITHIN.ALCHEMY_DATA,
36 | [Enum.Profession.Leatherworking] = CraftSim.SPECIALIZATION_DATA.THE_WAR_WITHIN.LEATHERWORKING_DATA,
37 | [Enum.Profession.Jewelcrafting] = CraftSim.SPECIALIZATION_DATA.THE_WAR_WITHIN.JEWELCRAFTING_DATA,
38 | [Enum.Profession.Enchanting] = CraftSim.SPECIALIZATION_DATA.THE_WAR_WITHIN.ENCHANTING_DATA,
39 | [Enum.Profession.Tailoring] = CraftSim.SPECIALIZATION_DATA.THE_WAR_WITHIN.TAILORING_DATA,
40 | [Enum.Profession.Inscription] = CraftSim.SPECIALIZATION_DATA.THE_WAR_WITHIN.INSCRIPTION_DATA,
41 | [Enum.Profession.Engineering] = CraftSim.SPECIALIZATION_DATA.THE_WAR_WITHIN.ENGINEERING_DATA
42 | },
43 | }
44 |
45 | ---@type table>
46 | CraftSim.SPECIALIZATION_DATA.BASE_NODES = {
47 | [CraftSim.CONST.EXPANSION_IDS.DRAGONFLIGHT] = {
48 | [Enum.Profession.Blacksmithing] = { "ARMOR_SMITHING_1", "WEAPON_SMITHING_1", "SPECIALITY_SMITHING_1", "HAMMER_CONTROL_1" },
49 | [Enum.Profession.Alchemy] = { "POTION_MASTERY_1", "PHIAL_MASTERY_1", "ALCHEMICAL_THEORY_1" },
50 | [Enum.Profession.Leatherworking] = { "LEATHERWORKING_DISCIPLINE_1", "LEATHER_ARMOR_CRAFTING_1", "MAIL_ARMOR_CRAFTING_1", "PRIMORDIAL_LEATHERWORKING_1" },
51 | [Enum.Profession.Jewelcrafting] = { "TOOLSET_MASTERY_1", "FACETING_1", "SETTING_1", "ENTERPRISING_1" },
52 | [Enum.Profession.Enchanting] = { "ENCHANTMENT_1", "INSIGHT_OF_THE_BLUE_1", "RODS_RUNES_AND_RUSES_1" },
53 | [Enum.Profession.Tailoring] = { "TAILORING_MASTERY_1", "TEXTILES_1", "DRACONIC_NEEDLEWORK_1", "GARMENTCRAFTING_1" },
54 | [Enum.Profession.Inscription] = { "RUNE_MASTERY_1", "ARCHIVING_1", "RUNEBINDING_1" },
55 | [Enum.Profession.Engineering] = { "OPTIMIZED_EFFICIENCY_1", "EXPLOSIVES_1", "FUNCTION_OVER_FORM_1", "MECHANICAL_MIND_1" },
56 | },
57 | [CraftSim.CONST.EXPANSION_IDS.THE_WAR_WITHIN] = {
58 | [Enum.Profession.Blacksmithing] = { "EVER_BURNING_FORGE_1", "MEANS_OF_PRODUCTION_1", "WEAPON_SMITHING_1", "ARMOR_SMITHING_1" },
59 | [Enum.Profession.Alchemy] = { "ALCHEMICAL_MASTERY_1", "FANTASTIC_FLASKS_1", "POTENT_POTIONS_1", "THAUMATURGY_1" },
60 | [Enum.Profession.Enchanting] = { "SUPPLEMENTARY_SHATTERING_1", "DESIGNATED_DISENCHANTER_1", "EVERLASTING_ENCHANTMENTS_1", "EPHEMERALS_ENRICHMENTS_AND_EQUIPMENT_1" },
61 | [Enum.Profession.Engineering] = { "ENGINEERED_EQUIPMENT_1", "DEVICES_1", "INVENTING_1" },
62 | [Enum.Profession.Inscription] = { "PURSUIT_OF_KNOWLEDGE_1", "PURSUIT_OF_PERFECTION_1", "CAREFUL_CARVINGS_1", "ARCHIVAL_ADDITIONS_1" },
63 | [Enum.Profession.Leatherworking] = { "LEARNED_LEATHERWORKER_1", "LUXURIOUS_LEATHERS_1", "CONCRETE_CHITIN_1", "FLAWLESS_FORTRES_1" },
64 | [Enum.Profession.Tailoring] = { "THREADS_OF_DEVOTION_1", "FROM_DAWN_UNTIL_DUSK_1", "QUALITY_FABRIC_1", "TEXTILE_TREASURES_1" },
65 | [Enum.Profession.Jewelcrafting] = { "GEMCUTTING_1", "JEWELRY_CRAFTING_1", "SHAPING_1" },
66 | },
67 | }
68 |
69 | -- used for e.g. craft buffs to determine trait dependend stats
70 | ---@param recipeData CraftSim.RecipeData
71 | ---@param nodeID number
72 | ---@param expansionID CraftSim.EXPANSION_IDS
73 | ---@param professionID Enum.Profession
74 | function CraftSim.SPECIALIZATION_DATA:GetStaticNodeData(recipeData, nodeID, expansionID, professionID)
75 | local RawNodeDataList = CraftSim.SPECIALIZATION_DATA.NODE_DATA[expansionID][professionID].nodeData
76 | local rawBaseNodeData = RawNodeDataList[nodeID]
77 | local perkMap = {}
78 | for perkID, rawPerkData in pairs(RawNodeDataList) do
79 | if rawPerkData.nodeID == nodeID and rawPerkData.maxRank == 1 then
80 | perkMap[perkID] = rawPerkData
81 | end
82 | end
83 |
84 | if recipeData:IsCrafter() then
85 | local nodeData = CraftSim.NodeData(recipeData, rawBaseNodeData, perkMap)
86 | nodeData:UpdateRank()
87 | nodeData:Update()
88 |
89 | return nodeData
90 | else
91 | local crafterUID = recipeData:GetCrafterUID()
92 | local cachedSpecData = CraftSim.DB.CRAFTER:GetSpecializationData(crafterUID, recipeData)
93 |
94 | if not cachedSpecData then return end
95 |
96 | local nodeData = GUTIL:Find(cachedSpecData.nodeData, function(nData)
97 | return nData.nodeID == nodeID
98 | end)
99 |
100 | return nodeData
101 | end
102 | end
103 |
104 | ---@param recipeData CraftSim.RecipeData
105 | ---@param nodeID number
106 | ---@return boolean affected
107 | function CraftSim.SPECIALIZATION_DATA:IsRecipeDataAffectedByNodeID(recipeData, nodeID)
108 | local recipePerks = self.NODE_DATA[recipeData.professionData.expansionID]
109 | [recipeData.professionData.professionInfo.profession].recipeMapping
110 |
111 | if not recipePerks then return false end
112 |
113 | return tContains(recipePerks[recipeData.recipeID] or {}, nodeID)
114 | end
115 |
--------------------------------------------------------------------------------