FAQ

Get answers to frequently asked questions

When first starting to develop games with SnapNet, there are a number of common questions that arise. Below, you’ll find answers, suggestions, best practices, and links back to relevant sections of the manual.

When referencing SnapNet from another module you probably need to add both SnapNet and SnapNetCore to the module’s PublicDependencyModuleNames in its Build.cs file.

Why can’t the client connect to the server?

The first thing to check when a client fails to connect to a server is the protocol ID. In order for a client to successfully connect to a server, their protocol IDs must match. When starting a server and/or connecting a client, you will find the calculated protocol ID in the log if the LogSnapNet channel’s verbosity is set to at least Log (the default). It will look something like the following:

LogSnapNet: Server protocol ID: 5232212708314382574
LogSnapNet: Client protocol ID: 5232212708314382574

If these values differ, you’ll need to track down why the server and client are calculating different protocol IDs. If you set the verbosity of the LogSnapNet channel to Verbose, all of the individual hashes that are combined to calculate the final protocol ID will be emitted to the log preceding the final protocol ID. You can do this by opening up your project’s DefaultEngine.ini and adding the following:

[Core.Log]
LogSnapNet=Verbose

With verbose logging enabled, you’ll see additional log output like the following:

LogSnapNet: Verbose: Initializing protocol ID hash with protocol version: 0
LogSnapNet: Verbose: Hashing SnapNet version string: SnapNet 4.0.0
LogSnapNet: Verbose: Hashing debug flags: 0
...
LogSnapNet: Verbose: Hashing tick rate: 60
LogSnapNet: Verbose: Hashing ticks per server send: 1
LogSnapNet: Verbose: Hashing entity type 0 name: SnapNetShooterGamePlayerEntity
LogSnapNet: Verbose: Hashing entity type 0 hash: 15685460533315906747
LogSnapNet: Verbose: Hashing entity type 1 name: SnapNetShooterGameWeaponEntity
LogSnapNet: Verbose: Hashing entity type 1 hash: 18029571621401775322
...
LogSnapNet: Client protocol ID: 5232212708314382574

The client and server verbose log output must match in number, order, and value or the resulting protocol IDs will differ. Possible reasons for mismatches include using different SnapNet settings, registering a different set of entities/events/maps/messages or in a different order, registering a different set of properties e.g., wrapping property declarations in preprocessor macros, or initializing properties with different encodings/settings.

If the logging above matches in structure but hashes for individual entity/event/message types diverge, you can investigate which properties are causing a mismatch but setting the logging to VeryVerbose:

[Core.Log]
LogSnapNet=VeryVerbose

With VeryVerbose logging enabled, you’ll see additional logging per entity/event/message type at registration time, preceding the Verbose logging above:

LogSnapNet: VeryVerbose: Hashed SnapNetShooterGamePlayerEntity.Deaths._MaxValue: 8375868524575217002
LogSnapNet: VeryVerbose: Hashed SnapNetShooterGamePlayerEntity.Deaths._MinValue: 5420699180036177763
LogSnapNet: VeryVerbose: Hashed SnapNetShooterGamePlayerEntity.Deaths._Name: 1817155986731518756
LogSnapNet: VeryVerbose: Hashed SnapNetShooterGamePlayerEntity.Deaths._Relevance: 3605868431624384871
LogSnapNet: VeryVerbose: Hashed SnapNetShooterGamePlayerEntity.Kills._MaxValue: 14028891120961271687
LogSnapNet: VeryVerbose: Hashed SnapNetShooterGamePlayerEntity.Kills._MinValue: 4770916291385656300
LogSnapNet: VeryVerbose: Hashed SnapNetShooterGamePlayerEntity.Kills._Name: 5090450615168420395
LogSnapNet: VeryVerbose: Hashed SnapNetShooterGamePlayerEntity.Kills._Relevance: 8236510484452517420
LogSnapNet: VeryVerbose: Hashed SnapNetShooterGamePlayerEntity.Bot._Name: 11731604355936491239
LogSnapNet: VeryVerbose: Hashed SnapNetShooterGamePlayerEntity.Bot._Relevance: 13375914340458549372
LogSnapNet: VeryVerbose: Hashed SnapNetShooterGamePlayerEntity.Ping._MaxValue: 18204606836786808986
LogSnapNet: VeryVerbose: Hashed SnapNetShooterGamePlayerEntity.Ping._MinValue: 8661614488122355350
LogSnapNet: VeryVerbose: Hashed SnapNetShooterGamePlayerEntity.Ping._Name: 14437973815144756951
LogSnapNet: VeryVerbose: Hashed SnapNetShooterGamePlayerEntity.Ping._Relevance: 14357984232060455598
LogSnapNet: VeryVerbose: Hashed SnapNetShooterGamePlayerEntity.DisplayName._StringPoolName: 16698284944954779127
LogSnapNet: VeryVerbose: Hashed SnapNetShooterGamePlayerEntity.DisplayName._StringPoolRequired: 108462721505713204
LogSnapNet: VeryVerbose: Hashed SnapNetShooterGamePlayerEntity.DisplayName._Name: 4735986664715944153
LogSnapNet: VeryVerbose: Hashed SnapNetShooterGamePlayerEntity.DisplayName._Relevance: 8225325260715419570
LogSnapNet: VeryVerbose: Hashed SnapNetShooterGamePlayerEntity._Name: 10944729350853005858
LogSnapNet: VeryVerbose: Hashed SnapNetShooterGamePlayerEntity._Relevance: 11878144263409193481
LogSnapNet: VeryVerbose: Hashed SnapNetShooterGamePlayerEntity._Baseline: 6892532240027663735

Like the other log output, these items must match in number, order, and value between client and server or the resulting protocol IDs will differ. Property names prefixed with an underscore indicate internal settings/values that contribute to the hash but are not actual fields marked UPROPERTY.

Why isn’t my property’s value being replicated to the client?

If the value of a property on the client never updates to match the server’s value, you can take the following steps.

1. Verify that it is a UPROPERTY

Only properties annotated with the UPROPERTY macro will be replicated to clients.

2. Verify that it is contained within a supported data structure

The property must be a direct member of the entity/component/event/message itself or within a struct that is annotated as a UPROPERTY on the entity/component/event/message. TMaps are not supported. TArrays or fixed-size arrays of structs are supported but not arrays of individual SnapNet properties. This is because most SnapNet properties need to be initialized via their constructor and so they must be contained within a struct and configured appropriately via that struct’s default constructor e.g.:

USTRUCT()
struct FMyPercentageInt
{
    GENERATED_BODY()

    FMyPercentageInt()
        : Value( 0, 100 )
    {
    }

    UPROPERTY()
    FSnapNetPropertyInt32 Value;
};

UCLASS()
class UMyEvent : public USnapNetEvent
{
    GENERATED_BODY()

public:
    UPROPERTY()
    TArray<FMyPercentageInt> Percentages_VALID; // This is valid and will be replicated

    UPROPERTY()
    TArray<FSnapNetPropertyInt32> Percentages_INVALID; // This is invalid and will not be replicated

    FMyPercentageInt Percentages_NO_UPROPERTY; // This is not marked UPROPERTY and so will not be replicated
};

3. Check the property’s relevance

If the property’s relevance is misconfigured, the server may not consider it relevant to the client and will not send any updates. Check the documentation on property relevance for more information.

4. Check the log for any warnings or errors

If the property is misconfigured or the value set is outside of its representable range SnapNet will emit warnings to the log. Make sure that that the property isn’t failing to replicate due to its configured encoding.