- Documentation
- Locus
- C++ Developer API
C++ Developer API
Use the native Developer API from an Editor-only C++ plugin or tool. Add the
Locus module to the consuming editor module’s dependencies, include Locus.h
for acquisition, and include Developer/LocusDeveloperApi.h for requests and
results.
Lifetime and async contract
Section titled “Lifetime and async contract”GetLocusDeveloperApi() returns the active FLocusDeveloperApi, or nullptr
outside the initialized Locus Editor lifetime.
- Acquire and submit on the Game Thread.
- Do not retain the API pointer across subsystem or module shutdown.
- Every completion runs exactly once on the Game Thread.
- Accepted work completes on a later tick of Locus’s existing executor.
- Admission failure can complete inline before submission returns.
- Prepare callback-owned state before submitting.
- Cancellation is cooperative. It can prevent queued work, but cannot interrupt repository work or retroactively cancel a committed mutation.
- Do not add blocking waits, sleeps, Game Thread pumping, or
Future.Get().
The returned FLocusDeveloperRequestHandle exposes request identity and
thread-safe cooperative Cancel().
Create a Document
Section titled “Create a Document”#include "Locus.h"#include "Developer/LocusDeveloperApi.h"
void CreateCombatDocument(){ FLocusDeveloperApi* Locus = GetLocusDeveloperApi(); if (Locus == nullptr) { return; }
FLocusDeveloperCreateDocumentRequest Request; Request.Path = TEXT("Design/Combat.md"); Request.Markdown = TEXT("# Combat\n"); Request.PresentationRoot = ELocusDeveloperDocumentPresentationRoot::LocusDocuments;
FLocusDeveloperRequestHandle Handle = Locus->CreateDocument( MoveTemp(Request), [](TLocusDeveloperResult<FLocusDeveloperDocumentSnapshot> Result) { if (!Result.IsSuccess()) { UE_LOG(LogTemp, Error, TEXT("Locus: %s"), *Result.Error.Message); return; }
const FLocusDeveloperDocumentSnapshot& Document = Result.Value.GetValue(); UE_LOG(LogTemp, Display, TEXT("Created %s"), *Document.Identity.RelativePath); });
// Retain Handle only if this tool needs to offer cancellation.}The input path is relative to the selected concrete presentation root. The
returned identity remains the authoritative ProjectDocuments-relative path.
Get, then update
Section titled “Get, then update”Do not hide revision handling. Use the revision from the read result as the mutation precondition:
FLocusDeveloperGetDocumentRequest GetRequest;GetRequest.Identity.RelativePath = TEXT("Design/Combat.md");
Locus->GetDocument( MoveTemp(GetRequest), [Locus](TLocusDeveloperResult<FLocusDeveloperDocumentSnapshot> GetResult) { if (!GetResult.IsSuccess()) { return; }
const FLocusDeveloperDocumentSnapshot& Current = GetResult.Value.GetValue(); FLocusDeveloperUpdateDocumentRequest UpdateRequest; UpdateRequest.Identity = Current.Identity; UpdateRequest.ExpectedRevision = Current.Revision; UpdateRequest.Markdown = Current.Markdown + TEXT("\n## Abilities\n");
Locus->UpdateDocument( MoveTemp(UpdateRequest), [](TLocusDeveloperResult<FLocusDeveloperDocumentSnapshot> Result) { if (Result.Error.Code == ELocusDeveloperErrorCode::StaleRevision) { // Reread before reconsidering the mutation. } }); });Explicit Note scope
Section titled “Explicit Note scope”FLocusDeveloperCreateNoteRequest Request;Request.Scope = ELocusDeveloperScope::Private;Request.Title = TEXT("Local investigation");Request.Body = TEXT("Not shared with the project repository.");Request.Tags = {TEXT("investigation")};
FLocusDeveloperRequestHandle Handle = Locus->CreateNote( MoveTemp(Request), [](TLocusDeveloperResult<FLocusDeveloperNoteSnapshot> Result) { if (Result.IsSuccess()) { const FLocusDeveloperNoteIdentifier Identity = Result.Value->Identity; // GUID + Private scope } });Scope filters are equally explicit. All includes Private content; request
Shared when a tool must not include it.
Basic Pin creation
Section titled “Basic Pin creation”FLocusDeveloperCreatePinRequest Request;Request.Scope = ELocusDeveloperScope::Shared;Request.WorldAssetPath = TEXT("/Game/Maps/Main.Main");Request.WorldLabel = TEXT("Main");Request.Location = FVector(120.0, 40.0, 180.0);Request.Title = TEXT("Check encounter cover");Request.PinType = ELocusDeveloperPinType::Issue;
FLocusDeveloperRequestHandle Handle = Locus->CreatePin( MoveTemp(Request), [](TLocusDeveloperResult<FLocusDeveloperPinSnapshot> Result) { if (!Result.IsSuccess()) { UE_LOG(LogTemp, Warning, TEXT("Pin create failed: %s"), LexToString(Result.Error.Code)); } });Pin creation requires a supported saved project-owned world. Metadata updates preserve position, world, anchor, view, and scope.
See the Developer API overview for the operation matrix, identity contract, error taxonomy, revisions, and operation status.