EvenLess wrote: ↑Fri Aug 04, 2023 11:42 pm
I have added a LOT of items to the Item Spawner. Primarily
Legendary and
Very Rare, and some
Rare and
Uncommon. I have sorted and color-coded them.
I have found 4 paths with UUIDs.
- Gustav\Public\Gustav\Stats\Generated\Data
- Gustav\Public\GustavDev\Stats\Generated\Data
- Shared\Public\Shared\Stats\Generated\Data
- Shared\Public\SharedDev\Stats\Generated\Data
It looks to be the RootTemplate UUID that is used (not the ValueUUID).
As
CKeylos already pointed out, there's a guide on how to extract the .PAK-files to read the item tables, which was essentially what I used.
<edit count=2>
Just to be easier to find, here is my summary:
- Download and extract the latest version of Norbyte's ExportTool [Link].
- Download and extract the latest version of ShinyHobo's BG3-Modders-Multitool [Link].
I extracted the BG3-Modders-Multitool to the base directory of Norbyte's ExportTool, as the Multitool requires a file from there (which is added by clicking the asterisk in the lower right hand corner after opening the Multitool).
</edit>
Fixed issue. Split items into 3 files.
Added an update version of the old one. It is based on Zanzer's "bg3.CT v4.1.1.3624901 (2)" with
dilde's spells added as well.
Disclaimer!
Zanzer deserves all the credit here. I only used his work. And I honestly do not really understand what is happening in the LUA/assembler code.
<edit count=1>
BG3 did crash several times when I tested the various UUIDs. However, that did not always mean the UUID did not work, as when I tried again (sometimes after several crashes) they did work. Just something to keep in mind.
</edit>
<edit count=2>
It seems I forgot to enable the "hide children" again, after moving my additions to Zanzers. However, I dropped this approach for a method that would be easier to maintain. I have removed the previous cheat table and added the one that contains
ALL 2711 items. The items where a rarity was found, also have that added. I have also added a CSV file containing all the same items that you can use as you wish.
YOU MUST FIRST LOAD Zanzer's Cheat Table and Activate Console Commands, then Register Commands, before being able to use the Item Spawner.
Then from the already opened Cheat Engine, with Zanzer's bg3.CT loaded, open my bg3_items.CT and merge.
First I wrote a PowerShell script to extract all the items in an easily manageable format.
Code: Select all
# Get the path for the My Documents folder.
$DocumentsFolder = [System.Environment]::GetFolderPath('MyDocuments')
# The default location where Cheat Engine saves cheat tables.
$CheatTablesFolder = Join-Path -Path $DocumentsFolder -ChildPath 'My Cheat Tables'
$ItemsCsvFile = 'bg3_items.csv'
$ItemsCsvPath = Join-Path -Path $CheatTablesFolder -ChildPath $ItemsCsvFile
$ItemsCtFile = 'bg3_armor.CT'
$ItemsCtPath = Join-Path -Path $CheatTablesFolder -ChildPath $ItemsCtFile
# Base-path of the unpacked data/.pak-files.
$BasePath = 'C:\Games\BG3-Tools\UnpackedData'
# Get tools to extract with here:
# https://github.com/Norbyte/lslib/releases/latest
# https://github.com/ShinyHobo/BG3-Modders-Multitool/releases/latest
# Sub-paths to the armor, object, and weapon .txt-files.
$ArmorFiles = @(
'Shared\Public\Shared\Stats\Generated\Data\Armor.txt'
,'Shared\Public\SharedDev\Stats\Generated\Data\Armor.txt'
,'Gustav\Public\Gustav\Stats\Generated\Data\Armor.txt'
,'Gustav\Public\GustavDev\Stats\Generated\Data\Armor.txt'
)
$WeaponFiles = @(
'Shared\Public\Shared\Stats\Generated\Data\Weapon.txt'
,'Shared\Public\SharedDev\Stats\Generated\Data\Weapon.txt'
,'Gustav\Public\Gustav\Stats\Generated\Data\Weapon.txt'
,'Gustav\Public\GustavDev\Stats\Generated\Data\Weapon.txt'
)
$ObjectFiles = @(
'Shared\Public\Shared\Stats\Generated\Data\Object.txt'
,'Shared\Public\SharedDev\Stats\Generated\Data\Object.txt'
,'Gustav\Public\Gustav\Stats\Generated\Data\Object.txt'
,'Gustav\Public\GustavDev\Stats\Generated\Data\Object.txt'
)
# Combine to one.
#$Files = $ArmorFiles + $WeaponFiles + $ObjectFiles
$Files = $ArmorFiles + $WeaponFiles + $ObjectFiles
$RarityColor = @{
'RARITY_UNKNOWN' = 'C0C0C0'
'Uncommon' = '00FF00'
'Rare' = 'FFFF00'
'VeryRare' = 'FF00FF'
'Legendary' = '4080FF'
}
$CheatTableHead = @"
<?xml version="1.0" encoding="utf-8"?>
<CheatTable CheatEngineTableVersion="45">
<CheatEntries>
<CheatEntry>
<ID>@@CE_ID@@</ID>
<Description>"Item Spawner"</Description>
<Options moHideChildren="1"/>
<GroupHeader>1</GroupHeader>
<CheatEntries>
"@
$CheatTableFoot = @"
</CheatEntries>
</CheatEntry>
</CheatEntries>
<UserdefinedSymbols>
<SymbolEntry>
<Name>playerCharactersPtr</Name>
<Address>1D4526F0000</Address>
</SymbolEntry>
</UserdefinedSymbols>
<DisassemblerComments>
<DisassemblerComment>
<Address>"bg3.exe"+25C0F20</Address>
<Comment>Zanzer</Comment>
</DisassemblerComment>
</DisassemblerComments>
</CheatTable>
"@
$CheatEntryTemplate = @"
<CheatEntry>
<ID>@@CE_ID@@</ID>
<Description>"@@ITEM_NAME@@"</Description>
<Color>@@RARITY_COLOR@@</Color>
<VariableType>Auto Assembler Script</VariableType>
<AssemblerScript Async="1">[ENABLE]
{`$lua}
if syntaxcheck then return end
local uuid = "@@ITEM_UUID@@"
local cmdCall = getAddress("cmdCall")
local cmdAddr = getAddress("cmdAddr")
local cmdArgs = getAddress("cmdArgs")
local cmdStr1 = getAddress("cmdStr1")
PrepareCall("GetHostCharacter")
executeCodeEx(0, nil, cmdCall)
writePointer(cmdArgs + 0x18, readPointer(cmdArgs + 0x08))
PrepareCall("CreateAtObject")
writePointer(cmdArgs + 0x08, cmdStr1)
writeString(cmdStr1, uuid)
writeBytes(cmdStr1 + #uuid, 0)
writeQword(cmdArgs + 0x28, 0)
writeQword(cmdArgs + 0x38, 0)
writeQword(cmdArgs + 0x48, 0)
writeQword(cmdArgs + 0x58, 0)
executeCodeEx(0, nil, cmdCall)
{`$asm}
assert(true)
[DISABLE]
</AssemblerScript>
</CheatEntry>
"@
# Regular Expression to check if the UUID looks right.
$RegexUUID = [regex]'^[a-z0-9]{8}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{12}$'
# Create an empty array to store all the items.
$Items = ''
# Create an empty string variable to store the content of the files.
$Content = ''
# Loop through the files and read their contents into one big string.
foreach ($File in $Files) {
# Combine base-path and sub-path to the full path.
$FullPath = Join-Path -Path $BasePath -ChildPath $File
$Content += Get-Content -Raw -Path $FullPath
}
# Split the content string into an array of lines.
$Line = $Content -split '\n'
# Create an empty array to store the item objects in.
$Items = @()
# Ensure the Item variable is empty for the first iteration.
Clear-Variable -Name Item -ErrorAction SilentlyContinue
# Loop through all the lines.
for ($l = 0; $l -lt $Line.Count; $l++) {
# Check if the current line is the start of a new item entry.
if ($Line[$l] -match '^new entry "(?<Name>\w+)"') {
# Store the items "name" in a new variable, so it does not get overwritten by following mathes.
$ItemName = $Matches.Name
# Check if we already have an item object, and if that item object contains a valid UUID.
if ($Item -and $Item.UUID -match $RegexUUID) {
# Store the previous item object in the array.
$Items += New-Object -TypeName psobject -Property $Item
}
# Create a fresh hashtable and populate it with the default values.
$Item = [ordered]@{
Name = $ItemName
UUID = $null
Type = 'TYPE_UNKNOWN'
Rarity = 'RARITY_UNKNOWN'
}
}
else {
# Not a new item entry, so look for the current item entrys data.
# Check if the current line is the item type.
if ($Line[$l] -match 'type "(?<Type>\w+)"') {
# Update the hashtable with the found value.
$Item.Type = $Matches.Type
}
# Check if the current line is the item rarity.
if ($Line[$l] -match '^data "Rarity" "(?<Rarity>\w+)"') {
# Update the hashtable with the found value.
$Item.Rarity = $Matches.Rarity
}
# Check if the current line is the item UUID.
if ($Line[$l] -match '^data "RootTemplate" "(?<UUID>[a-f0-9-]+)"') {
# Update the hashtable with the found value.
$Item.UUID = $Matches.UUID
}
}
}
# Export the items to a the items CSV-file. Using semi-colon (;) as delimiter, simply because the CSV file will automatically be shown in colums, in spreadsheet programs.
$Items | Sort-Object -Property Name | Export-Csv -Force -NoTypeInformation -Encoding Default -Delimiter ';' -Path $ItemsCsvPath
# Build the Cheat Table.
foreach ($t in ($Items | Select-Object -ExpandProperty Type -Unique)) {
$CtFile = "bg3_$($t.ToLower()).CT"
$CtPath = Join-Path -Path $CheatTablesFolder -ChildPath $CtFile
$CheatID = 1
$CheatTableHead.Replace('@@CE_ID@@', $CheatID) | Out-File -Force -Encoding default -FilePath $CtPath
foreach ($i in ($Items | Where-Object { $_.Type -eq $t} | Sort-Object -Property Name)) {
$CheatID++
$CheatEntryTemplate.Replace('@@CE_ID@@', $CheatID).Replace('@@ITEM_NAME@@', $i.Name).Replace('@@RARITY_COLOR@@', $RarityColor."$($i.Rarity)").Replace('@@ITEM_UUID@@', $i.UUID) | Out-File -Append -Encoding default -FilePath $CtPath
}
$CheatTableFoot | Out-File -Append -Encoding default -FilePath $CtPath
}
</edit>
<edit>
Issue with the bg_items.CT was a mixture of me forgetting to escape $lua and $asm in the table, which caused PowerShell to interpret them as variables rather than literal tekst. Apparently the CharacterPtr in the original, needs to be added at the bottom of mine as well, for it to work I would have thought it just was inherited from the first loaded. I don't know LUA or Assembler, so I'm just trying my way
</edit>