Skip to content

Latest commit

 

History

History
93 lines (67 loc) · 3.9 KB

README.md

File metadata and controls

93 lines (67 loc) · 3.9 KB

Xande

Xande is a (WIP) C# library meant to be used in Dalamud plugins for interacting with FINAL FANTASY XIV models. It is able to parse Havok files (.hkx, .xml) using functions in the client, and perform model exports (imports WIP).

Xande was made possible thanks to:

Installation & Usage

Right now, Xande must be referenced as a Git submodule:

git submodule add https://github.com/xivdev/Xande.git

Then reference Xande.csproj in your plugin.


Xande functions by calling functions of the Havok SDK that were bundled with the FFXIV client. Because of this, right now, it is only possible to use in the context of a Dalamud plugin.

To convert a .sklb file into an .xml file (and vice versa):

// Obtain a byte array, either through the filesystem or through Lumina
var sklbData = File.ReadAllBytes("skl_c0101b0001.sklb");
// Parse the .sklb to obtain the .hkx
var readStream = new MemoryStream(sklbData);
var sklb = SklbFile.FromStream(readStream);

// Do the thing
var converter = new HavokConverter();
var xml = converter.HkxToXml(sklb.HkxData);

// Convert the .xml back into a .hkx
var hkx = converter.XmlToHkx(xml);
// Replace the .sklb's .hkx with the new one
sklb.ReplaceHkxData(hkx);

// Write the new .sklb to disk
var writeStream = new MemoryStream();
sklb.Write(writeStream);
File.WriteAllBytes("skl_c0101b0001.sklb", writeStream.ToArray());

To export a model:

var havokConverter = new HavokConverter();
var luminaManager = new LuminaManager(DataManager.GameData);
var modelConverter = new ModelConverter(luminaManager);

// outputDir can be any directory that exists and is writable, temp paths are used for demonstration
var outputDir = Path.Combine(Path.GetTempPath(), "XandeModelExport");
Directory.CreateDirectory(outputDir);

// This is Grebuloff
var mdlPaths = new string[] { "chara/monster/m0405/obj/body/b0002/model/m0405b0002.mdl" };
var sklbPaths = new string[] { "chara/monster/m0405/skeleton/base/b0001/skl_m0405b0001.sklb" };

var skeletons = sklbPaths.Select(path => {
    var file = luminaManager.GetFile<FileResource>(path);
    var sklb = SklbFile.FromStream(file.Reader.BaseStream);
    var xmlStr = havokConverter.HkxToXml(sklb.HkxData);
    return new HavokXml(xmlStr);
}).ToArray();

modelConverter.ExportModel(outputDir, mdlPaths, skeletons);

Multiple models can be supplied to export them into one scene. When exporting a full body character, pass the deform parameter representing the race code of the character.

Skeleton paths can be automatically resolved with the SklbResolver class. Note that the skeleton array order is important (base skeletons must come first, and skeletons that depend on other skeletons must come after the dependencies).

Safety

Xande tries to do its best to wrap Havok for you, but at its core, it is a library in another game's address space calling random functions.

When contributing Havok code, please make sure to check for null pointers and failed hkResults.

Havok functions are not thread-safe, so you should use HavokConverter on the Framework thread (see Framework.RunOnFrameworkThread and Framework.RunOnTick). Model exports are thread-safe.