The idea of this tool is to decode all customizable text dat's, similar to PolUtils, but output directly to a database. Customizations can be made at the database level, and then the tool will read the database and pack new customized .dat files.
There's been a good amount of progress on this tool. Binary data structure is built for all items and their components (job, slot, strings, graphics, etc.) - the bindata gem makes it easy to read and then write the objects back in the same structure. Binary data structure still needs to be created for other components (quests, missions, key items, abilities, status, titles, uhh npc lists, maybe dialog tables? and prob other stuff too!)
The database component is a WIP. I have it writing everything out to a database and it's working, though I haven't committed all those changes yet. Still need to write the last component of reading the database and writing out the file. (Hopefully in one of the coming weekends - and then it'll just be polish to turn it into a usable tool without having to do inline edits.
It's possible to do in-line changes with the tool, which allows for some "easy" changes.
Example (yes, could probably just do the byte rotation on the item being modified rather than the entire array, it's meant as an example rather than an actual solution)
Code:
#Example usage...
# ARMOR
file = File.new("armor.DAT","rb")
a = []
# go through all bytes and rotate right 5 bytes
file.each_byte do |x|
a << x.ror(5)
end
num_items = a.length/0xc00
# read item into ffxi_armor
num_items.times do |item_no|
#item_no = 47
item = FFXI_Weapon.read(a[0xc00*(item_no)...0xc00*(item_no+1)].pack("C*"))
insert_weapon(item)
end
# update description
item.strings.description.assign "This is a custom description\nBoo-ya!\n\n:)"
# put item back into array
a[0xc00*(item_no)...0xc00*(item_no+1)] = item.to_binary_s.unpack("C*")
#rotate all items left 5
a.each_with_index do |x,i|
a[i] = x.rol(5)
end
# write back to a file
out = File.open("109.DAT","w+b")
out.write(a.pack("C*"))
out.close
# WEAPON EXAMPLE
file = File.new("weapon.DAT","rb")
w = []
# go through all bytes and rotate right 5 bytes
file.each_byte do |x|
w << x.ror(5)
end
# read item into ffxi_weapon
item_no = 4301 #Excalibur, ID 20685 - starting ID 16384 = 4031
item = FFXI_Weapon.read(w[0xc00*(item_no)...0xc00*(item_no+1)].pack("C*"))
#set blu job bit
item.jobs.blu = 1
item.graphics.ffxi_icon.assign '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'
item.strings.description.assign "Julian rulez"
item.strings.set_name 'Excaliboo'
item.strings.set_singular 'Excaliboo'
item.strings.set_plural 'Excaliboo'
# put item back into array
w[0xc00*(item_no)...0xc00*(item_no+1)] = item.to_binary_s.unpack("C*")
#rotate all items left 5
w.each_with_index do |x,i|
w[i] = x.rol(5)
end
# write back to a file
out = File.open("108.DAT","w+b")
out.write(w.pack("C*"))
out.close
Screenshots
Edited strings, job, and icon
Messing with JP characters
Github:
https://github.com/JulianoW/DatFFXITool