Importing Projects
How a StoryFlow build directory becomes Unity assets: where the import lives, what each run actually writes, how failures are reported and what a player build needs.
The Import Menu
The package adds exactly two menu items, both under Tools > StoryFlow:
- Tools > StoryFlow > Import Project - opens the import window for a one-off import from a build directory on disk.
- Tools > StoryFlow > Live Sync - opens the Live Sync window, which imports automatically whenever the StoryFlow Editor pushes a change.
Moved in 1.2.2
On plugin 1.2.1 and older these two items sat in a top-level StoryFlow menu. That menu no longer exists. The Add Component category is unchanged and is still called StoryFlow.
The import window has two fields and one button:
| Field | Default | Description |
|---|---|---|
| Build Directory | empty | The folder exported by the StoryFlow Editor, the one containing project.json. Use Browse... to pick it. The window warns inline if the selected folder has no project.json in it. |
| Output Path | Assets/StoryFlow | Where the imported assets are placed. Scripts, characters, media and the project asset all go under this path, preserving the folder structure from the editor. |
Import Project runs the import and fills the status box underneath with the project title, the script, character and global variable counts, the per-file counts and the output path. When something could not be written the box turns into an error and lists the files that are still stale.
Incremental Import
An import writes only what changed. Every script, character and project asset carries a hash of the source it was last built from, and is re-serialized only when that hash no longer matches. Media is compared by length and then by content before anything is copied.
Concretely, a file is rewritten when:
- Its source JSON changed. For the project asset that means any of
project.json,global-variables.jsonorcharacters.json. - What the asset ended up holding changed. The hash certifies the output as well as the input, so a script whose resolved media changed is rewritten even when its own JSON is byte-identical.
- A referenced asset's GUID changed. References are certified by GUID as well as by path, so deleting the imported media folder in the Project window and syncing again rebuilds the references instead of reading as "nothing changed".
- The last write failed. The hash is recorded only after the save reaches disk, so a refused file is retried on the next import rather than skipped forever.
A media file referenced by several scripts is settled once per import rather than once per reference, and an unchanged image generates no copy, no ForceUpdate reimport, no texture recompression and no version control traffic.
The first import after upgrading rewrites everything once
Assets imported by an earlier plugin version carry no recorded source hash, so the first import or live sync after installing 1.2.2 writes every script, character and project asset once and records their hashes. Under version control that is one diff per asset, in a single batch. Unchanged media is still compared by content and is not recopied. Every import after that only touches what actually changed.
Per-File Reporting
The importer never aborts on a single unwritable file. Each media copy and each asset save is attempted on its own, a file that cannot be written is skipped and the rest of the import goes through. Every caller checks the outcome before claiming success, so the Live Sync log, the import window's status box and the Re-Import dialog all report counts rather than an unqualified "complete", and the Console carries one error naming every file the run could not write.
Failures name the likely cause alongside the framework's own message. The three the importer calls out are a file that is read-only or checked in, a full path that is too long for the operating system and a file that is open in another application. Counts are per file, so a locked texture pulled in by three scripts is reported once.
StoryFlowImportReport
The overload described under Editor Scripting returns a StoryFlowImportReport describing the run:
| Member | Type | Description |
|---|---|---|
MediaWritten | int | Media files copied into the project this run. |
MediaUpToDate | int | Media files whose destination already held identical bytes. |
MediaFailed | int | Media files that could not be written. |
AssetsWritten | int | Assets serialized to disk this run. |
AssetsUpToDate | int | Assets whose serialized data had not changed since the last import. |
AssetsFailed | int | Assets that could not be written. |
WrittenCount | int | Media and assets written, combined. |
UpToDateCount | int | Media and assets already up to date, combined. |
FailedCount | int | Media and assets that failed, combined. |
HasFailures | bool | True when FailedCount is greater than zero. Check this before telling anyone the import succeeded. |
Failures | IReadOnlyList<Failure> | One entry per failed file, in the order they failed. |
Summarize() | string | The one-line form every caller appends to its own message, for example 12 written, 40 up to date, 2 failed. |
Each Failure carries Path, Reason and Kind. Kind is a FailureKind, one of:
Media- a media file that could not be copied into the project.Asset- an asset that could not be serialized to disk.InvalidPath- a path the importer refused to act on at all. An exported asset path containing a..segment would put a raw file copy outside the output folder, so it is refused, reported by name and the rest of the import continues. ThePathof such a failure is the exported relative path from the source JSON, not a location in the Unity project.
var project = StoryFlowImporter.ImportProject(buildDirectory, "Assets/StoryFlow", out var report);
if (report.HasFailures)
{
Debug.LogError($"Import incomplete ({report.Summarize()})");
foreach (var failure in report.Failures)
Debug.LogError($" [{failure.Kind}] {failure.Path}: {failure.Reason}");
} Version Control
Unity checks out anything it writes through the AssetDatabase, but media files are copied in directly and bypass that, so the checkout has to be asked for explicitly. With a provider such as Perforce or Plastic configured and connected:
- An existing media file is checked out with
AssetDatabase.MakeEditablebefore it is overwritten. - An asset is made writable before it is marked dirty. That order matters: an object left dirty behind a refusal would be written by the next flush that comes along, including editor shutdown, and the write would strip the read-only attribute on the way past.
- A refused checkout fails that one file with a message saying so, and the file is retried on the next import.
- A media file the import created is marked for add afterwards, so it does not sit unversioned next to versioned siblings. A failed add is only a warning, never an import failure.
No provider configured
With no provider active, the importer refuses a read-only file rather than clearing the attribute. A read-only file in a Unity project is nearly always owned by a version control system Unity is not driving, including a provider that is configured but offline, and overwriting it loses the change at the next sync or revert. Check the file out or clear the attribute yourself, then import again.
Because unchanged media is compared by content before any of this happens, a routine import generates no checkout traffic at all.
Forcing a Full Rewrite
The skip check compares against what the last import recorded, so it cannot see an asset that was hand-edited, corrupted or partially deleted afterwards. When you need the Unity side rebuilt from source regardless, select the imported Project asset and use the Inspector:
- Select the project asset (by default
Assets/StoryFlow/Project.asset). - Under Actions, expand the Re-Import from Source foldout.
- Set Build Directory to your exported build folder, using Browse... if you like.
- Click Re-Import.
This rewrites every asset and media file past the skip checks and re-records the hashes, so the next ordinary import goes back to skipping. If any file could not be written, a dialog lists them.
This is the only forced path
Live Sync, its Request Sync button, the import window and the postprocessor that re-imports when StoryFlow JSON inside your Assets folder changes all stay incremental. Re-Import from Source is the one place that forces a full rewrite.
Editor Scripting
StoryFlowImporter lives in the StoryFlow.Editor assembly, so it can only be called from editor code. Reference StoryFlow.Editor from an editor-only assembly definition, never from runtime code.
// Unchanged since earlier versions
public static StoryFlowProjectAsset ImportProject(
string buildDirectory, string outputPath);
// Added in 1.2.2: reports per-file outcomes, and can force a full rewrite
public static StoryFlowProjectAsset ImportProject(
string buildDirectory, string outputPath,
out StoryFlowImportReport report, bool force = false); buildDirectory is an absolute path to the StoryFlow Editor's build output, the folder containing project.json. outputPath is a Unity-relative path such as Assets/StoryFlow. Both overloads return the created or updated StoryFlowProjectAsset.
Leave force at its default for routine importing. Passing true rewrites everything, which is what the Re-Import button does and is only worth the cost when the imported assets themselves need repairing.
using StoryFlow.Editor;
using UnityEditor;
using UnityEngine;
public static class MyBuildPipeline
{
[MenuItem("Tools/My Game/Sync Story")]
public static void SyncStory()
{
var project = StoryFlowImporter.ImportProject(
"C:/stories/my-game/build", "Assets/StoryFlow", out var report);
if (report.HasFailures)
Debug.LogError($"[MyGame] Story import incomplete: {report.Summarize()}");
else
Debug.Log($"[MyGame] Story import OK: {project.Title} ({report.Summarize()})");
}
} Settings and Player Builds
An imported project asset sitting in a plain folder with nothing referencing it is stripped from player builds, which used to surface as no StoryFlow project found in a shipped game even though play mode worked. The settings asset is what anchors it.
StoryFlowSettings lives at Assets/Resources/StoryFlowSettings.asset. Being inside a Resources folder, it ships in every build, and its Default Project reference pulls the project and all of its scripts, characters and media in with it. There is no Assets > Create entry for it. It appears either when you open Edit > Project Settings > StoryFlow or when you import a project, both of which create it if it is missing.
Every import and live sync then settles the assignment:
- If Default Project is unassigned, it is pointed at the project that was just imported.
- If it already points at a different project, that choice is left alone and a warning tells you to update it in Edit > Project Settings > StoryFlow if the new project should be the default.
- If the settings asset is not inside a
Resourcesfolder, a warning says player builds cannot load it there and suggests moving it toAssets/Resources/StoryFlowSettings.asset.
The build check
A build preprocess check runs when you build a player. If the Unity project contains StoryFlow project assets but none is anchored for the player, meaning no settings asset in Resources with a project assigned and no project asset inside a Resources folder, it logs a warning naming the fix. It only warns and never fails the build, because a scene reference also works and cannot be verified cheaply.
Upgrading from 1.2.1 or older
Import or sync once after upgrading. That single run creates the settings asset, assigns the project and records the source hashes, and from then on builds find the project and imports go back to writing only what changed.