Skip to content

Commit

Permalink
feat: Custom assets
Browse files Browse the repository at this point in the history
  • Loading branch information
Eideren authored and VaclavElias committed Dec 6, 2024
1 parent a9c1982 commit c196c88
Show file tree
Hide file tree
Showing 6 changed files with 193 additions and 2 deletions.
179 changes: 179 additions & 0 deletions en/manual/scripts/custom-assets.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
# Creating Custom Assets

Stride supports the creation of custom asset types that can be referenced in your scenes as well as reference other assets.
To do so, you must add a reference to the `Stride.Core.Assets` package in your game's `.csproj`:
Here's how it looks like in a default game project:
```xml
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>net8.0-windows</TargetFrameworks>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Stride.Engine" Version="4.2.0.1" />
<PackageReference Include="Stride.Video" Version="4.2.0.1" />
<PackageReference Include="Stride.Physics" Version="4.2.0.1" />
<PackageReference Include="Stride.Navigation" Version="4.2.0.1" />
<PackageReference Include="Stride.Particles" Version="4.2.0.1" />
<PackageReference Include="Stride.UI" Version="4.2.0.1" />
<PackageReference Include="Stride.Core.Assets.CompilerApp" Version="4.2.0.1" IncludeAssets="build;buildTransitive" />

<PackageReference Include="Stride.Core.Assets" Version="4.2.0.1" />
</ItemGroup>
</Project>
```
>[!Warning]
> Make sure that the version specified for `Stride.Core.Assets` matches the other package's versions.
Inside the same project, create a new csharp file and replace its content with the following:
```cs
using System.Collections.Generic;
using System.Threading.Tasks;
using Stride.Core;
using Stride.Core.Assets;
using Stride.Core.Assets.Compiler;
using Stride.Core.BuildEngine;
using Stride.Core.Serialization;
using Stride.Core.Serialization.Contents;
using Stride.Engine;

namespace YOUR_GAME_NAMESPACE;

/// <summary>
/// Runtime representation of the asset, this is the actual class you would use in your scripts
/// </summary>
[DataContract]
[ContentSerializer(typeof(DataContentSerializerWithReuse<YOUR_CLASS>))]
[ReferenceSerializer, DataSerializerGlobal(typeof(ReferenceSerializer<YOUR_CLASS>), Profile = "Content")]
public class YOUR_CLASS
{
// Replace this with whatever you would want this asset to hold at runtime
public List<Prefab> PrefabCollection { get; set; } = new();
}

/// <summary>
/// Design time and file representation of <see cref="YOUR_CLASS"/>, you can add content here that won't be included in the build
/// </summary>
[AssetDescription(FileExtension, AllowArchetype = false)]
[AssetContentType(typeof(YOUR_CLASS))]
[AssetFormatVersion(nameof(YOUR_GAME_NAMESPACE), CurrentVersion, "1.0.0.0")]
public sealed class YOUR_CLASS_ASSET : Asset
{
private const string CurrentVersion = "1.0.0.0";
public const string FileExtension = ".blks";

// Replace this with whatever you would want this asset to have while inside the gamestudio
public List<Prefab> PrefabCollection { get; set; } = new();
}

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

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

public override IEnumerable<ObjectUrl> GetInputFiles(AssetItem assetItem)
{
// Yield asset items you are dependent on to include them in the build
var asset = (YOUR_CLASS_ASSET)assetItem.Asset;
foreach (var block in asset.PrefabCollection)
{
var url = AttachedReferenceManager.GetUrl(block);

if (!string.IsNullOrEmpty(url))
{
yield return new ObjectUrl(UrlType.Content, url);
}
}
}

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

var runtimeObject = new YOUR_CLASS{ PrefabCollection = Parameters.PrefabCollection };
assetManager.Save(Url, runtimeObject);

commandContext.Logger.Info($"Saving {nameof(YOUR_CLASS)}: {runtimeObject.PrefabCollection}");

return Task.FromResult(ResultStatus.Successful);
}
}
}
```
This takes care of the support for this asset, you could create a `*.blks` file inside your `Assets` directory and fill in the content manually, but might as well do it through the editor ...

## Adding a section for the Add asset menu inside the editor

Create a new directory named `Templates` within your Game's directory, this directory will be used to store your templates.
Inside of that directory, create a new file named after your new asset with the `.sdtpl` extension.

![Template directory example](media/template-directory-example.png)

Open the file and paste the following into it
```
!TemplateAssetFactory
Id: 21CC3354-9F0B-4D1F-8242-62D56454B27C
AssetTypeName: YOUR_CLASS_ASSET
Name: THE NAME IN THE EDITOR
Scope: Asset
Description: A DESCRIPTIVE DESCRIPTION OF YOUR ASSET
Group: WHERE THIS WOULD BE CLASSIFIED UNDER IN THE EDITOR
DefaultOutputName: THE DEFAULT FILE NAME
```
Edit the different fields appropriately,
- `Id` must be unique ! There are a couple of services online to generate one if you need to, search for `generate guid online`
- `AssetTypeName` must match the name of the class that inherits from `Asset` (the namespace can be omitted)

Now you have to edit your `*.sdpkg` to include this new template, to do so you just have to add the following lines below your `TemplateFolders:`
```
TemplateFolders:
- Path: !dir Templates
Group: Assets
Files:
- !file Templates/YOUR_TEMPLATE.sdtpl
```
Here's how it looks like when included into a default game `*.sdpkg`:
```
!Package
SerializedVersion: {Assets: 3.1.0.0}
Meta:
Name: MyGame21
Version: 1.0.0
Authors: []
Owners: []
Dependencies: null
AssetFolders:
- Path: !dir Assets
- Path: !dir Effects
ResourceFolders:
- !dir Resources
OutputGroupDirectories: {}
ExplicitFolders: []
Bundles: []
TemplateFolders:
- Path: !dir Templates
Group: Assets
Files:
- !file Templates/YOUR_TEMPLATE.sdtpl
RootAssets: []
```

And you're finally done, have fun !

![Result](media/template-result.png)
3 changes: 2 additions & 1 deletion en/manual/scripts/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,5 @@ You can still use standard C# classes in Stride, but these aren't called scripts
* [Debugging](debugging.md)
* [Preprocessor variables](preprocessor-variables.md)
* [Create a model from code](create-a-model-from-code.md)
* [Create Gizmos for you components](gizmos.md)
* [Create Gizmos for your components](gizmos.md)
* [Create Custom Assets](custom-assets.md)
3 changes: 3 additions & 0 deletions en/manual/scripts/media/template-directory-example.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions en/manual/scripts/media/template-result.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions en/manual/stride-for-unity-developers/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,9 @@ The editor opens in a new tab. You can arrange the tabs how you like, or float t

>[!Note]
>When you modify resource files outside Game Studio, the corresponding assets update automatically in Game Studio.
### Scriptable Objects
See the [Custom Assets](../scripts/custom-assets.md) page.

### Import assets

Expand Down
4 changes: 3 additions & 1 deletion en/manual/toc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -498,8 +498,10 @@ items:
href: scripts/preprocessor-variables.md
- name: Create a model from code
href: scripts/create-a-model-from-code.md
- name: Create Gizmos for you components
- name: Create Gizmos for your components
href: scripts/gizmos.md
- name: Create Custom Assets
href: scripts/custom-assets.md

- name: Sprites
href: sprites/index.md
Expand Down

0 comments on commit c196c88

Please sign in to comment.