-
Notifications
You must be signed in to change notification settings - Fork 102
Getting Started: Assets file writing
Any code shown here is subject to change. Make sure to read Getting Started: Assets file reading
first.
There are many different ways to modify an assets file. We'll start with modifying a field of a single asset. Let's say we have a GameObject like this:
GameObject Base
vector m_Component
Array Array (2 items)
int size = 2
[0]
ComponentPair data
PPtr<Component> component
int m_FileID = 0
SInt64 m_PathID = 123
[1]
ComponentPair data
PPtr<Component> component
int m_FileID = 0
SInt64 m_PathID = 234
unsigned int m_Layer = 0
string m_Name = "Example GameObject"
UInt16 m_Tag = 0
bool m_IsActive = true
We'll start off simple with a single field change. We can change m_Name
like so:
var goBase = manager.GetBaseField(afileInst, goInfo);
goBase["m_Name"].AsString = "New GameObject Name";
That's all it takes to replace a field. Again, make sure you use the correct AsXXX property for the type.
Now it's time to save the asset and then the assets file. To do this, we first add an AssetsReplacer
to the info. This tells AssetsTools.NET how to modify the asset. In our case, we can use SetNewData
as a quick way to apply an AssetsReplacerFromMemory
for base fields. Another replacer you could use is the AssetsRemover
which removes the asset from the file.
var goBase = manager.GetBaseField(afileInst, goInfo);
goBase["m_Name"].AsString = "New GameObject Name";
goInfo.SetNewData(goBase);
Alternatively, you can manually use a replacer.
goInfo.Replacer = new ContentReplacerFromBuffer(goBase.WriteToByteArray());
Internally, SetNewData
creates a ContentReplacerFromBuffer
like the second method. It serializes the base field back to a byte array and tells AssetsTools.NET to replace the entire asset with the byte array on write. You should only pass the base field into replacers, don't pass any children fields into replacers. Passing the base field will handle any children fields for you.
Now we can save the assets file with changes.
using (AssetsFileWriter writer = new AssetsFileWriter("sharedassets0.assets.mod"))
{
afile.Write(writer);
}
Make sure that you save with a different filename than the file currently open. AssetsTools.NET copies unmodified assets from the original file and writing is not possible when the original file is already open for reading.
Adding new array items can be made easy with ValueBuilder
. Here's an example of adding new components to the m_Component
array.
var m_Component = goBase["m_Component.Array"];
// create the new array item with the type of this array
var newArrayItem = ValueBuilder.DefaultValueFieldFromArrayTemplate(m_Component);
// fill in the fields
newArrayItem["component.m_FileID"].AsInt = 0;
newArrayItem["component.m_PathID"].AsLong = 345;
// add new item into m_Component
m_Component.Children.Add(newArrayItem);
It is not mandatory to set every field of an object created with ValueBuilder
. ValueBuilder
initializes all fields to 0 or empty string depending on the type. In the above example, we could delete the line setting m_FileID
and it would work the same.
Adding new assets is roughly the same. ValueBuilder
can also create entire new assets instead of just array items. A shortcut with ValueBuilder is manager.CreateValueBaseField
which lets you skip making the template field.
var textAssetClassId = (int)AssetClassID.TextAsset;
var newPathId = 12345L; // can be anything as long as it hasn't been used yet
var newBaseField = manager.CreateValueBaseField(afileInst, textAssetClassId);
// set fields
newBaseField["m_Name"].AsString = "interesting textasset";
newBaseField["m_Script"].AsString = "interesting text";
// make new info
var newInfo = AssetFileInfo.Create(afile, newPathId, textAssetClassId);
newInfo.SetNewData(newBaseField);
// add it to the assets file
afile.Metadata.AddAssetInfo(newInfo);
MonoBehaviours are a complicated issue. Because of this, they have their own section here: Adding new MonoBehaviours