结构体同步

UE可以同步结构体变量,如果server上有个结构体A,声明如下:

struct FA
{
	UPROPERTY(NotReplicated)
	int b;

	int c;
	
	UPROPERTY(EditAnywhere)
	int d;
}

上面结构中只有d会同步给客户端。如果数组元素中的d发生变化,但b,c属性依赖d的话,就可能出现b,c缓存的老的d对应的值。比如d 为道具ID,b为根据ID查找的Name,但Name会缓存。一帧内删增道具,会误判为d属性变化。进而Name和ID出现不对应的情况。

UE 编译

UE的编译需要VS,目前最新的VS2022-17.10版本会打不开sln。使用17.08可以打开。
https://aka.ms/vs/17/release.ltsc.17.8/vs_professional.exe
.NET Framework 4.7.2 Developer Pack

Visual Studio 2022 发行历史记录 | Microsoft Learn

导出属性到文本

如果想批量打印属性值,利用UE的反射比较方便。方式是获取class/struct,遍历它的Property,通过调用ExportTextItem_InContainer,得到值字符串。

// 遍历所有属性  
for (TFieldIterator<FProperty> PropIt(FSkyCreatorWeatherSettings::StaticStruct()); PropIt; ++PropIt)  
{  
    FProperty* Property = *PropIt;  
    FString PropertyName = Property->GetName();  
  
    // 获取属性值  
    FString PropertyValue;  
    Property->ExportTextItem_InContainer(PropertyValue, &SkyCreator->WeatherSettings, nullptr, nullptr, PPF_IncludeTransient | PPF_Copy);  
  
    // 打印属性名称和值  
    UE_LOG(LogTemp, Log, TEXT("  [Weather] '%s' : '%s'"), *PropertyName, *PropertyValue);  
}

ExportTextItem_InContainer和ExportTextItem_Direct的区别在于前者会将地址作为基址,根据FProperty内部记录的偏移计算属性的基址;后者则需要直接提供属性基址。
注:如果属性的数值和对应类型默认构造函数产生的值相同,则不会导出。如果将Default值地址传入则会导出,但对于包含TMap属性,传入Default值地址会crash

比如:
struct A
{
	float B = 0.f;
	int C = 0;
	bool D = false;
};

上面属性B,C,D 的数值和对应构造函数float(),int(),boo() 的数值相同,所以无法导出。
可以参考代码:

virtual bool Identical( const void* A, const void* B, uint32 PortFlags=0 ) const override  
{  
    // RHS is the same as TTypeFundamentals::GetOptionalPropertyValue(B) but avoids an unnecessary copy of B  
    return TTypeFundamentals::GetPropertyValue(A) == (B ? TTypeFundamentals::GetPropertyValue(B) : TTypeFundamentals::GetDefaultPropertyValue());  
}
template<typename InTCppType>  
class TPropertyTypeFundamentals
{
	static FORCEINLINE TCppType GetDefaultPropertyValue()  
	{  
	    return TCppType();  
	}
}

bool FProperty::ExportText_Direct  
    (  
    FString&   ValueStr,  
    const void*    Data,  
    const void*    Delta,  
    UObject*   Parent,  
    int32     PortFlags,  
    UObject*   ExportRootScope  
    ) const  
{  
    if( Data==Delta || !Identical(Data,Delta,PortFlags) )  
    {       ExportText_Internal  
          (  
          ValueStr,  
          (uint8*)Data,  
          EPropertyPointerType::Direct,  
          (uint8*)Delta,  
          Parent,  
          PortFlags,  
          ExportRootScope  
          );  
       return true;  
    }  
    return false;  
}

Actor Overlap事件

问题:地图里在玩家出生位置摆放了一个Trigger,玩家刚出生时Trigger无法检测到玩家的Overlap事件,之后在内移动也无法触发。但换个简单图,或者摆放远处让玩家进去都能触发。
原因:地图有LevelStreaming关卡,触发Overlap时正在LevelStreaming,这时会判断Trigger上的bGenerateOverlapEventsDuringLevelStreaming配置,默认是False。勾选即可。

Simulation 开启

问题:Actor里的Mesh 设置物理模拟不起作用。
原因:Mobility 应该设成Movable。