Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 1 addition & 19 deletions DragaliaAPI/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -13,28 +13,10 @@
</ItemGroup>
<PropertyGroup>
<MasterAssetResources>$(MSBuildThisFileDirectory)DragaliaAPI.Shared/Resources/</MasterAssetResources>
<ApiOutputDirectory>$(MSBuildThisFileDirectory)DragaliaAPI\bin\$(Configuration)\$(TargetFramework)\</ApiOutputDirectory>
<BuildToolsVerbose>false</BuildToolsVerbose>
</PropertyGroup>
<Target
Name="CopyApiMsgpackFiles"
AfterTargets="Build"
Condition="$(DependsOnApiMsgpackFiles) == 'true'"
>
<ItemGroup>
<MasterAssetMsgpackFiles Include="$(ApiOutputDirectory)Resources\**\*.msgpack" />
</ItemGroup>
<Copy
SourceFiles="@(MasterAssetMsgpackFiles)"
DestinationFolder="$(OutDir)Resources\%(RecursiveDir)"
/>
<ItemGroup>
<FileWrites Include="@(MasterAssetMessagePackFiles-&gt;'$(OutDir)Resources\%(RecursiveDir)%(Filename).msgpack')" />
</ItemGroup>
</Target>

<PropertyGroup Condition="'$(GITHUB_ACTIONS)' == 'true'">
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<!-- NuGet security vulnerabilities -->
<WarningsNotAsErrors>NU1902;NU1903;NU1904</WarningsNotAsErrors>
</PropertyGroup>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
<PropertyGroup>
<UseMicrosoftTestingPlatformRunner>true</UseMicrosoftTestingPlatformRunner>
<OutputType>Exe</OutputType>
<DependsOnApiMsgpackFiles>true</DependsOnApiMsgpackFiles>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="FluentAssertions" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
<PropertyGroup>
<UseMicrosoftTestingPlatformRunner>true</UseMicrosoftTestingPlatformRunner>
<OutputType>Exe</OutputType>
<DependsOnApiMsgpackFiles>true</DependsOnApiMsgpackFiles>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,49 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Build-time master asset conversion. Imported by DragaliaAPI.csproj.

Converts the master data JSON files under $(MasterAssetResources) (defined in Directory.Build.props)
into binary MessagePack files using the DragaliaAPI.MasterAssetConverter tool. The tool itself is
built first because DragaliaAPI.csproj declares a ProjectReference (with ReferenceOutputAssembly=false)
to it, and ResolveProjectReferences runs before the targets in this file.

How it fits into the build (see README.md in this directory for the full picture):

1. ConvertMasterAssets runs early in DragaliaAPI's build and writes .msgpack files into
obj/ ($(IntermediateOutputPath)masterassets/). It is incremental: MSBuild compares JSON
timestamps against the corresponding .msgpack outputs and only passes out-of-date files
to the tool ("partial incremental build").

2. IncludeMasterAssetOutputs registers the generated files as Content items with
CopyToOutputDirectory, just before AssignTargetPaths (the start of the SDK's content
pipeline). From there the standard build machinery takes over:
- copies them to $(OutDir)Resources/ for DragaliaAPI itself,
- flows them transitively to the output directory of every project that references
DragaliaAPI (e.g. the test projects) — no manual copy targets needed,
- includes them in `dotnet publish` output,
- tracks them for Clean/IncrementalClean via FileWrites.
-->
<Project>
<PropertyGroup>
<_InvokeConverterCommand>"$(MSBuildThisFileDirectory)bin/$(Configuration)/DragaliaAPI.MasterAssetConverter"</_InvokeConverterCommand>
<!-- For Docker builds, where we pass /p:UseAppHost=false -->
<_InvokeConverterCommand Condition="$(UseAppHost) == 'false'"
>dotnet "$(MSBuildThisFileDirectory)bin/$(Configuration)/DragaliaAPI.MasterAssetConverter.dll"</_InvokeConverterCommand
>
<MasterAssetConverterOutputImportance>low</MasterAssetConverterOutputImportance>
<MasterAssetConverterOutputImportance Condition="$(BuildToolsVerbose) == 'true'"
>high</MasterAssetConverterOutputImportance
>
</PropertyGroup>
<!--
$(IntermediateOutputPath) is only defined once the SDK's .targets are imported, which happens
after this file — so the paths below live in targets (execution time) rather than in a
top-level PropertyGroup/ItemGroup (evaluation time).
-->
<Target Name="_PrepareForMasterAssetConverter">
<PropertyGroup>
<_MasterAssetOutputDirectory>$(IntermediateOutputPath)masterassets/</_MasterAssetOutputDirectory>
</PropertyGroup>
<ItemGroup>
<_MasterAssetJsonFiles
Visible="false"
Expand All @@ -16,31 +52,46 @@
/>
</ItemGroup>
</Target>
<!-- Hook into build before CopyFilesToOutputDirectory so that we update FileWrites before FileListAbsolute.txt gets written -->
<Target
Name="MasterAssetConverter"
Name="ConvertMasterAssets"
DependsOnTargets="_PrepareForMasterAssetConverter"
BeforeTargets="CopyFilesToOutputDirectory"
Condition="'$(DesignTimeBuild)' != 'true'"
Inputs="@(_MasterAssetJsonFiles)"
Outputs="@(_MasterAssetJsonFiles-&gt;'$(OutDir)Resources/%(RecursiveDir)%(Filename).msgpack')"
Outputs="@(_MasterAssetJsonFiles-&gt;'$(_MasterAssetOutputDirectory)%(RecursiveDir)%(Filename).msgpack')"
>
<Exec
Command="$(_InvokeConverterCommand) &quot;$(OutDir)Resources&quot; &quot;$(MasterAssetResources)&quot; @(_MasterAssetJsonFiles-&gt;'&quot;%(FullPath)&quot;', ' ')"
ConsoleToMSBuild="true"
Command="$(_InvokeConverterCommand) &quot;$(_MasterAssetOutputDirectory)&quot; &quot;$(MasterAssetResources)&quot; @(_MasterAssetJsonFiles-&gt;'&quot;%(FullPath)&quot;', ' ')"
StandardOutputImportance="$(MasterAssetConverterOutputImportance)"
/>
<ItemGroup>
<MasterAssetMessagePackFiles Include="$(OutDir)Resources/**/*.msgpack" />
<FileWrites Include="@(MasterAssetMessagePackFiles)" />
</ItemGroup>
</Target>
<!--
Hands the generated files to the SDK's content pipeline. This target must run on every
build (it has no Inputs/Outputs) because ItemGroups inside a skipped target do not execute.
-->
<Target
Name="CopyMsgpackToPublish"
AfterTargets="Publish"
DependsOnTargets="MasterAssetConverter"
Name="IncludeMasterAssetOutputs"
DependsOnTargets="ConvertMasterAssets"
BeforeTargets="AssignTargetPaths"
Condition="'$(DesignTimeBuild)' != 'true'"
>
<Copy
SourceFiles="@(MasterAssetMessagePackFiles)"
DestinationFolder="$(PublishDir)Resources/%(RecursiveDir)"
/>
<ItemGroup>
<_MasterAssetMsgpackFiles
Visible="false"
Include="$(_MasterAssetOutputDirectory)/**/*.msgpack"
/>
</ItemGroup>
<!--
The metadata references below must be qualified (%(_MasterAssetMsgpackFiles.*)): unqualified
%(RecursiveDir) inside a target batches over pre-existing Content items instead (MSB4120).
-->
<ItemGroup>
<Content
Include="@(_MasterAssetMsgpackFiles)"
TargetPath="Resources/%(_MasterAssetMsgpackFiles.RecursiveDir)%(_MasterAssetMsgpackFiles.Filename)%(_MasterAssetMsgpackFiles.Extension)"
CopyToOutputDirectory="PreserveNewest"
Visible="false"
/>
<FileWrites Include="@(_MasterAssetMsgpackFiles)" />
</ItemGroup>
</Target>
</Project>
64 changes: 64 additions & 0 deletions DragaliaAPI/DragaliaAPI.MasterAssetConverter/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# Master asset build pipeline

Two custom tools run during the build to produce the master data ("master asset") files that
DragaliaAPI loads at runtime. Both run at the **start** of the build, before the .NET SDK's
content-copy pipeline, so their outputs are handled by standard build machinery from then on.

```
DragaliaAPI.MissionDesigner (runs as part of its own Build)
[ContainsMissionList] C# DSL ──► DragaliaAPI.Shared/Resources/Missions/MissionProgressionInfo.json
(written into the source tree, checked into git)
DragaliaAPI.Shared/Resources/**/*.json (all master data, including the file above)
DragaliaAPI.MasterAssetConverter (runs early in DragaliaAPI's build, BeforeTargets=AssignTargetPaths)
JSON ──► obj/<cfg>/<tfm>/masterassets/**/*.msgpack
registered as Content items with CopyToOutputDirectory=PreserveNewest
┌───────────────────────────────────────┼──────────────────────────────────┐
▼ ▼ ▼
DragaliaAPI/bin/.../Resources/ test project bin/.../Resources/ publish/Resources/
(own output) (flows transitively to anything (`dotnet publish`,
referencing DragaliaAPI.csproj — used by Docker)
no opt-in property needed)
```

## Ordering

- `DragaliaAPI.csproj` has `ProjectReference`s (with `ReferenceOutputAssembly="false"`) to both
tool projects, so MSBuild builds them — and, for MissionDesigner, runs it — before DragaliaAPI's
own targets execute.
- Inside DragaliaAPI's build, conversion is hooked `BeforeTargets="AssignTargetPaths"`: after
`ResolveProjectReferences` (tools exist), before the content pipeline (outputs get picked up).

## Incrementality

- **MasterAssetConverter** (`MasterAssetConverter.targets`): declares each `.json` as an input and
the corresponding `obj/.../masterassets/*.msgpack` as an output. On a warm build the target is
skipped; when some JSON files change, MSBuild passes only those files to the tool (partial
incremental build).
- **MissionDesigner** (`MissionDesigner.targets`): inputs are the freshly built designer assembly
(a proxy for the C# mission DSL) and `MissionNormalData.json`; output is
`MissionProgressionInfo.json`. The tool only reruns when the DSL or that file changed.

## Things that fall out of using the content pipeline (no extra code needed)

- Test projects get `Resources/**/*.msgpack` in their output directory simply by referencing
`DragaliaAPI.csproj` (transitive content copy). The old `DependsOnApiMsgpackFiles` opt-in
property and manual copy target are gone.
- `dotnet publish` includes the files automatically.
- `Clean` removes the generated files from both `obj/` and `bin/` (via `FileWrites`), but never
touches `MissionProgressionInfo.json` — that is a checked-in source file.

## Invoking the converter manually

```
MasterAssetConverter <outputDir> <resourcesPath> <jsonFile1> [<jsonFile2> ...]
```

For each JSON file it finds the matching `[GenerateMasterAsset<T>]` (or `[ExtendMasterAsset]`)
attribute on the `MasterAsset` class in DragaliaAPI.Shared, deserializes the JSON, and writes a
MessagePack binary to `<outputDir>/<relative-path>.msgpack`.
20 changes: 18 additions & 2 deletions DragaliaAPI/DragaliaAPI.MissionDesigner/MissionDesigner.targets
Original file line number Diff line number Diff line change
@@ -1,16 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Build-time mission data generation. Imported by DragaliaAPI.MissionDesigner.csproj itself, so
building this project also runs the tool.

Ordering: DragaliaAPI.csproj has a ProjectReference (ReferenceOutputAssembly=false) to this
project, so this runs before DragaliaAPI's MasterAssetConverter targets see the JSON.

The target is incremental: the freshly built assembly ($(TargetPath)) stands in for all DSL
code, so the tool only reruns when the mission DSL (or MissionNormalData.json, used to resolve
prerequisite chains) has changed. The output is deliberately NOT added to FileWrites — it is a
checked-in source file and must survive Clean.
-->
<Project>
<PropertyGroup>
<_InvokeMissionDesignerCommand>"$(MSBuildThisFileDirectory)bin/$(Configuration)/DragaliaAPI.MissionDesigner"</_InvokeMissionDesignerCommand>
<!-- For Docker builds, where we pass /p:UseAppHost=false -->
<_InvokeMissionDesignerCommand Condition="$(UseAppHost) == 'false'"
>dotnet "$(MSBuildThisFileDirectory)bin/$(Configuration)/DragaliaAPI.MissionDesigner.dll"</_InvokeMissionDesignerCommand
>
<MissionDesignerOutputImportance>low</MissionDesignerOutputImportance>
<MissionDesignerOutputImportance Condition="$(BuildToolsVerbose) == 'true'"
>high</MissionDesignerOutputImportance
>
</PropertyGroup>
<Target Name="MissionDesigner" AfterTargets="Build">
<Target Name="MissionDesigner" AfterTargets="Build" Condition="'$(DesignTimeBuild)' != 'true'">
<Exec
Command="$(_InvokeMissionDesignerCommand) &quot;$(MasterAssetResources)&quot;"
ConsoleToMSBuild="true"
StandardOutputImportance="$(MissionDesignerOutputImportance)"
/>
</Target>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
<PropertyGroup>
<UseMicrosoftTestingPlatformRunner>true</UseMicrosoftTestingPlatformRunner>
<OutputType>Exe</OutputType>
<DependsOnApiMsgpackFiles>true</DependsOnApiMsgpackFiles>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="FluentAssertions" />
Expand Down
1 change: 0 additions & 1 deletion DragaliaAPI/DragaliaAPI.Test/DragaliaAPI.Test.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
<PropertyGroup>
<UseMicrosoftTestingPlatformRunner>true</UseMicrosoftTestingPlatformRunner>
<OutputType>Exe</OutputType>
<DependsOnApiMsgpackFiles>true</DependsOnApiMsgpackFiles>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="FluentAssertions" />
Expand Down
2 changes: 0 additions & 2 deletions PhotonStateManager/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,5 @@

<PropertyGroup Condition="'$(GITHUB_ACTIONS)' == 'true'">
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<!-- NuGet security vulnerabilities -->
<WarningsNotAsErrors>NU1902;NU1903;NU1904</WarningsNotAsErrors>
</PropertyGroup>
</Project>