Skip to content
Eliot edited this page Aug 5, 2022 · 3 revisions

Loading an Unreal Package

    var package = UnrealLoader.LoadPackage(@"C:\Path\Package.upk", System.IO.FileAccess.Read);
    Console.WriteLine($"Version: {package.Summary.Version}");

Loading objects

Loading a package does not come with loaded objects by default, to do so we can call a helper method to initialize all objects:

    // Initializes the registered classes, constructs and deserializes(loads) the package objects.
    package.InitializePackage();

    // Now we can iterate all loaded objects, but beware! This includes fake-import objects.
    foreach (var obj in package.Objects)
    {
        Console.WriteLine($"Name: {obj.Name}");
        Console.WriteLine($"Class: {obj.Class?.Name}");
        Console.WriteLine($"Outer: {obj.Outer}");
    }

Implementing a custom class

By default the call to InitializePackage() class will register all compile-time defined UnrealClasses, but say we want to add support for an UnrealClass ourselves, then we'll have to register the specialized type before we initialize the package.

    var package = UnrealLoader.LoadPackage(@"C:\Path\Package.upk", System.IO.FileAccess.Read);
    if (package != null)
    {
        package.AddClassType("UTexture2D", typeof(UTexture2D));
        package.InitializePackage();
    }

The class:

    // An implementation for the UTexture2D class introduced in Unreal Engine 3.
    // This class's implementation is fictional and does not represent the actual object's format.
    // This is only to be used as an example.
    public class UTexture2D : UObject
    {
        public int SomeInteger;

        /** 
         * When a package is being initialized (i.e. InitializePackage()) each object will be constructed and begin its deserialization process.
         * In this function we can handle the deserialization of the particular object. 
         * A class-wide _Buffer property is accessible within this method, giving you access to the entire object's stream.
         */
        protected override void Deserialize()
        {
            // All UnrealClasses inherit the UObject's format, this may contain data like ScriptProperties(read DefaultProperties).
            base.Deserialize();

            // Here we can handle the format that could be specific to UTexture2D.
            SomeInteger = _Buffer.ReadInt32();

            // Record the field information.
            // This is a helper function to record the data that we just read, this data can then be displayed in the "Hex Viewer" in UE Explorer.
            Record(nameof(SomeInteger), SomeInteger);
        }

        /** This function is how UE Explorer grabs the text-output of an object. */
        public override string Decompile()
        {
            return $"Sucessfully decompiled! \n\r We got some non exciting data: {SomeInteger}";
        }
    }

Extending the library classes

Say we instead want to implement a custom UnrealClass as part of the library itself, thanks to C# attributes we can do so easily by adding the UnrealRegisterClass attribute to the class's declaration.

Like so:

    [UnrealRegisterClass]
    public class UTexture2D : UObject
    {
    }

Just make sure that the class (.cs) file is part of the UELib solution!

Retrieving an object

Assuming we have a loaded package with the particular object of our type.

    var myTextureObj = package.FindObject<UTexture2D>("Name of the texture object");
    if(myTextureObj != null)
    {
        // Ensure that the object has been loaded by invoking the deserialization process.
        myTextureObj.BeginDeserializing();

        var output = myTextureObj.Decompile();
        Console.WriteLine(output);
        Console.WriteLine($"SomeInteger: {myTextureObj.SomeInteger}");
    }