Call a Server Function Library
Server Objects run on ck-exec.
A Server Function Library has no instance to pick and no values to read, so a game does not acquire it and hold it as it does a Server Object. It calls a function by naming the definition: CallLibraryFunction, a static function of UCrowdyServerObjectLibrary in CrowdyServerObjectLibrary.h, in the CrowdyExec module.
Call one
The chest on the north road hands out a trinket when the local player walks into it. LootRollerDefinition is the CSO_LootRoller asset from Make a Server Function Library, picked in the chest's Details panel, and RollLoot takes the structs below:
// Chest.h
USTRUCT(BlueprintType)
struct FLootRollInputs
{
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite) int64 Seed = 0;
UPROPERTY(EditAnywhere, BlueprintReadWrite, meta = (ClampMin = 0, ClampMax = 4)) int32 Tier = 1;
};
USTRUCT(BlueprintType)
struct FLootRollOutputs
{
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite) FString Item;
};
virtual void NotifyActorBeginOverlap(AActor* OtherActor) override;
UPROPERTY(EditAnywhere, Category = "Crowdy")
TObjectPtr<UCrowdyServerObjectDefinition> LootRollerDefinition;
// Chest.cpp
#include "LanternPlayer.h"
void AChest::NotifyActorBeginOverlap(AActor* OtherActor)
{
Super::NotifyActorBeginOverlap(OtherActor);
const ALanternPlayer* Player = Cast<ALanternPlayer>(OtherActor);
if (!Player || !Player->CrowdyEntity->IsLocallyOwned())
{
return;
}
FLootRollInputs Inputs;
Inputs.Seed = 7;
Inputs.Tier = 1;
UCrowdyServerObjectLibrary::CallLibraryFunction(this, LootRollerDefinition, TEXT("RollLoot"), FInstancedStruct::Make(Inputs), [](const FCrowdyServerCallResult& Result)
{
if (!Result.IsSuccess())
{
UE_LOG(LogTemp, Warning, TEXT("The chest rolled nothing: %s"), *Result.Reason);
return;
}
const FLootRollOutputs* Reply = Result.Reply.GetPtr<FLootRollOutputs>();
if (Reply)
{
UE_LOG(LogTemp, Log, TEXT("The chest holds %s"), *Reply->Item);
}
});
}
Walk into the chest and the log reads The chest holds SilverRing:t1. The library keeps nothing, so the same Seed and Tier give the same item every time.
CallLibraryFunction(WorldContext, Definition, Function, Inputs, OnDone, TimeoutSeconds) takes:
- WorldContext: any object in the game's world, such as the actor.
- Definition: the library's definition asset.
- Function: the function's Name on the definition,
RollLoothere. - Inputs: an
FInstancedStructholding the function's Input Struct, made withFInstancedStruct::Make. For a function with no inputs, pass an emptyFInstancedStruct(). - OnDone: runs once with an
FCrowdyServerCallResult, on the game thread. It holds theOutcome, theReplyon success, aReasonfor anything but success, andbRetryable, as for a call to a Server Object. - TimeoutSeconds: optional. A limit of its own for this call that can only shorten the wait, as in Give up sooner.
A function whose inputs are added in the asset takes an FInstancedPropertyBag, the second overload. MakeParams of the library's Server Object hands you a copy with the default values; set the ones you want by name. The subsystem gives you that object for an empty Instance Id, and CallLibraryFunction shares it:
// Chest.cpp
UCrowdyServerObjectSubsystem* Objects = GetGameInstance()->GetSubsystem<UCrowdyServerObjectSubsystem>();
FString Error;
UCrowdyServerObject* Library = Objects->Acquire(LootRollerDefinition, FString(), this, Error);
if (Library)
{
FInstancedPropertyBag Inputs = Library->MakeParams(TEXT("RollLoot"));
Inputs.SetValueInt64(TEXT("Seed"), 7);
Inputs.SetValueInt32(TEXT("Tier"), 1);
UCrowdyServerObjectLibrary::CallLibraryFunction(this, LootRollerDefinition, TEXT("RollLoot"), Inputs, [](const FCrowdyServerCallResult& Result)
{
const TValueOrError<FString, EPropertyBagResult> Item = CrowdyExec::ToList(Result.Reply).GetValueString(TEXT("Item"));
UE_CLOG(Result.IsSuccess() && Item.HasValue(), LogTemp, Log, TEXT("The chest holds %s"), *Item.GetValue());
});
}
The reply reads by name through CrowdyExec::ToList from CrowdyExecCodec.h, as on Call one with inputs added in the asset.
How it is held and answered
-
The world holds the library. The first call to a library connects it, and the game instance's
UCrowdyServerObjectSubsystemkeeps it, as its own owner, until the subsystem shuts down. There is nothing to release, and calls to the same library share one connection. CallingAcquireyourself works too and is ready as soon as the connection opens, butCallLibraryFunctionneeds none of it. -
OnDone runs exactly once. A call that cannot be sent completes at once, inside
CallLibraryFunction, soOnDonecan run before it returns. Only a game instance shutdown skips it, for calls still waiting; sign-out completes them asCanceled. -
A refusal is an outcome, not a crash:
Cause Outcome Reason names A null definition, or a definition that is not a Server Function Library BadRequestthe asset, "... is not a Server Function Library" A function the definition does not have BadRequestthe type and the function No world, or a world with no game instance Unavailablethat it needs a world with a game instance Definition->IsFunctionLibrary()tells you whether an asset picked at run time is a library before you call it, andDefinition->Kindis theECrowdyServerObjectKindbehind it.Every other outcome is a call's, listed on Troubleshooting:
Deniedfor a function that is Server Only or Developers Only,ServerErrorfor an input outside its Value Range,Timeout,Pausedand the rest. -
Calls run side by side. Two calls that are sent together are two independent calls, and the server may answer them on different instances, in either order. A library has no state to link them.
-
The first call after the library has been idle can take over a second. Your
OnDonesimply runs later. A call that goes on past the project's Server Object Call Timeout, 20 seconds unless you changed it, ends asTimeout. -
Capture your actor weakly, as on Call one:
OnDonecan run after the actor that made the call is gone. The chest's lambda touches nothing of the actor, so it captures nothing.
Related
- Call a Server Function Library, from Blueprint: the Call node, which needs no Target
- Call its functions: the previous page, a call to a Server Object
- Make a Server Function Library: the asset, Kind and Scaling
- Loot for the Hollow Giant: the loot roller, the chest and the boss
- Troubleshooting: every outcome