Skip to content

Custom Assets can't use inherited types as parameters. #2713

@Doprez

Description

@Doprez

Is your feature request related to a problem? Please describe.
I was trying to use a custom asset that used a base type called BaseItem as the parameter but it threw errors on compilation.

Describe the solution you'd like
It would be a massive time saver to remove the boilerplate of creating individual items when the base type could be used. Below is what I was trying to do:

[DataContract]
[AssetDescription(FileExtension, AllowArchetype = false)]
[AssetContentType(typeof(ResourceItem))]
[AssetFormatVersion(nameof(Definitiions), CurrentVersion, "1.0.0.0")]
public class ResourceItemAsset : Asset
{
    private const string CurrentVersion = "1.0.0.0";
    public const string FileExtension = $".{nameof(ResourceItem)}";

    public BaseItem Item { get; set; }
}

/// <summary> Compiler which transforms your <see cref="ResourceItemAsset"/> into <see cref="ResourceItem"/> when building your game </summary>
[AssetCompiler(typeof(ResourceItemAsset), typeof(AssetCompilationContext))]
public sealed class ResourceItemCompiler : AssetCompilerBase
{
    protected override void Prepare(AssetCompilerContext context, AssetItem assetItem, string targetUrlInStorage, AssetCompilerResult result)
    {
        var asset = (ResourceItemAsset)assetItem.Asset;

        // you can have many build steps, each one is running an AssetCommand
        result.BuildSteps = new AssetBuildStep(assetItem);
        result.BuildSteps.Add(new ResourceItemDesignToRuntimeCommand(targetUrlInStorage, asset, assetItem.Package));
    }

    /// <summary>
    /// An <see cref="AssetCommand"/> that converts design time asset into runtime asset.
    /// </summary>
    public class ResourceItemDesignToRuntimeCommand(string url, ResourceItemAsset parameters, IAssetFinder assetFinder)
        : AssetCommand<ResourceItemAsset>(url, parameters, assetFinder)
    {
        protected override Task<ResultStatus> DoCommandOverride(ICommandContext commandContext)
        {
            var assetManager = new ContentManager(MicrothreadLocalDatabases.ProviderService);

            assetManager.Save(Url, Parameters.Item);

            commandContext.Logger.Info($"Saved {nameof(ResourceItem)}: {Url}");

            return Task.FromResult(ResultStatus.Successful);
        }
    }
}

BaseType:

[DataContract(Inherited = true)]
public abstract class BaseItem
{
    /// <summary>
    /// The unique identifier for the item.
    /// </summary>
    [DataMemberIgnore]
    public Guid Id { get; set; } = Guid.NewGuid();

    /// <summary>
    /// The Name for the item.
    /// </summary>
    public string Name { get; set; }

    /// <summary>
    /// The description of the item.
    /// </summary>
    public string Description { get; set; }

    /// <summary>
    /// Used to determine the base trading value of an item.
    /// </summary>
    public int Value { get; set; }

    /// <summary>
    /// The weight of the item, used for inventory management and affecting the movement stats of the holder.
    /// </summary>
    public int Weight { get; set; }
}

One of the inheritted types:

[ContentSerializer(typeof(DataContentSerializerWithReuse<ConsumableItem>))]
[ReferenceSerializer, DataSerializerGlobal(typeof(ReferenceSerializer<ConsumableItem>), Profile = "Content")]
public class ConsumableItem : BaseItem
{
}

Describe alternatives you've considered
The alternative is just to create an asset for each individual Item type.

Additional context
This architecture works within a Component type in a scene of GameStudio but the AssetCompiler seem to be the blocker for here for custom assets.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions