[程式] 使用ObjectDeliverer傳送訊息
因為需求關係,
小弟用UE4的ObjectDeliverer,還有FMermoryReader/Writer,
憑藉微薄的經驗寫了簡單的socket message,
方便在裝置之間溝通
業界應該有很多類似的作法,不知道以前有沒有其他人貼過,
自己用unreal刻了一個,分享給大家看看
ObjectDeliverer是UE marketplace上的一套插件,
可以在裝置之間傳送TCP/IP的訊息,
使用方式可以參考他的頁面
https://github.com/ayumax/ObjectDeliverer/
首先寫一個存訊息資料的class
UCLASS()
class UNetMessage : public UObject
{
GENERATED_BODY()
public:
UNetMessage() {}
void Initialize(int32 InParameter)
{
Data = InParameter;
}
UPROPERTY()
int32 IntData;
}
IntData是我想要傳送出去的資料,
接著還需要一個將資料轉換成byte array的function -- SerializeMsg(),
以及儲存轉換後的buffer
UPROPERTY()
TArray<uint8> MessageBuffer;
void SerializeMsg(FArchiveProxy& Archive)
{
Archive << IntData;
}
用法是New出一個物件之後用ObjectDeliverer送出
// 建立訊息及初始化資料
UNetMessage* NetMsg = NewObject<UNetmessage>();
NetMsg->Initialize(IntegerPara);
// 轉換成bitarry
FMemoryWriter MemoryWriter =
FMemoryWriter(NetMsg->MessageBuffer, true, true);
NetMsg->SerializeMsg(MemoryWriter);
// 使用ObjectDeliverer送出訊息
Deliverer->Send(NetMsg->MessageBuffer);
先將MessageBuffer丟給MemoryWriter,再餵給SerializeMsg,
裡面的Archive << IntData會被轉換成raw data存進MessageBuffer內。
但是這樣不是很夠,因為一定會有很多不同的message要送
所以可以再寫一個enum以及Message的base class來區分不同的message
UENUM()
enum class ENetMessageIndex
{
Index_1,
Index_2,
// ...
}
// Base class
UCLASS()
class UNetMessageBase : public UObject
{
GENERATED_BODY()
public:
UNetMessageBase() {}
UNetMessageBase(ENetMessageIndex InNetMessageIndex)
: NetMessageIndex((int32)InNetMessageIndex)
{
}
void Initialize() {};
virtual void SerializeMsg(FArchiveProxy& Archive) {}
UPROPERTY()
int32 NetMessageIndex;
UPROPERTY()
TArray<uint8> MessageBuffer;
};
UCLASS()
class UNetMessage : public UNetMessageBase
{
GENERATED_BODY()
public:
UNetMessage() : UNetMessageBase(ENetMessageIndex::Index_1) {}
void Initialize(int32 InParameter)
{
Data = InParameter;
}
void SerializeMsg(FArchiveProxy& Archive)
{
Archive << Data;
}
UPROPERTY()
int32 Data;
};
SerializeMsg的部分則變成
// 先Serialize NetMessageIndex
MemoryWriter << NetMessage->NetMessageIndex;
NetMsg->SerializeMsg(MemoryWriter);
傳送的部分大致是這樣,接收的部分則是反過來,
先讀取出MessageIndex,再讀取MessageBuffer內的資料
void OnReceive(const UObjectDelivererProtocol* Socket,
const TArray<uint8>& Buffer)
{
FMemoryReader MemoryReader = FMemoryReader(Buffer, true);
uint32 Index;
// 先讀取MessageIndex
FMemoryReader << Index;
Msg->SerializeMsg(FMemoryReader);
switch ((ENetMessageIndex)Index)
{
case ENetMessageIndex::Index_1:
UNetMessageObject* Msg = NewObject(this);
// 依照Message做其他事情...
break;
}
}
OnReceive()是一個綁在ObjectDeliverer上的callback event,
當Deliverer收到資料的時候會呼叫他
相較FMemoryWriter,由於這邊是使用FMemoryReader,
SerializeMsg()會變成從byte array內依序撈資料出來,
然後依照不同Index做不同事情,這樣就完成了。
最後是用macro簡化傳送部分的code
#define NET_MSG(NetMessageClass, ...) \
NetMessageClass* NetMessage = NewObject<NetMessageClass>(); \
NetMessage->Initialize(__VA_ARGS__); \
FMemoryWriter MemoryWriter =
FMemoryWriter(NetMessage->MessageBuffer, true, true); \
FNetMessageArchive NetMessageArchive = FNetMessageArchive(MemoryWriter);\
NetMessageArchive << NetMessage->NetMessageIndex; \
NetMessage->SerializeMsg(NetMessageArchive); \
最後的結果:
NET_MSG(UNetMessage, Parameter);
Deliverer->Send(NetMessage->MessageBuffer);
這樣就可以在不同裝置之間傳送一個UNetMessage物件了~
要寫不同message的話可以直接繼承UNetMessageBase,
宣告想要傳送的資料,定義好enum還有Initialize就可以囉
第一次分享程式,沒想到用ptt意外的難打
還請多多指教了
--
※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 220.141.86.66 (臺灣)
※ 文章網址: https://www.ptt.cc/bbs/GameDesign/M.1582498593.A.005.html
※ 編輯: Roronia (220.141.86.66 臺灣), 02/24/2020 06:58:28
推
02/24 13:40,
4年前
, 1F
02/24 13:40, 1F
※ 編輯: Roronia (220.141.86.66 臺灣), 02/24/2020 17:53:19
推
02/25 10:14,
4年前
, 2F
02/25 10:14, 2F
小弟沒有用過flatbuffers的經驗,
所以好不好用我也回答不出來
不過用途看起來是差不多的,都是傳資料
以前待過的公司都用類似的作法
寫一個class或struct,塞東西進去
然後底層再用socket丟出去
自己就也寫了一個UE的版本XD
※ 編輯: Roronia (220.141.86.66 臺灣), 02/25/2020 12:58:21
推
02/25 14:44,
4年前
, 3F
02/25 14:44, 3F
→
02/25 14:45,
4年前
, 4F
02/25 14:45, 4F
→
02/25 14:47,
4年前
, 5F
02/25 14:47, 5F
推
02/25 14:54,
4年前
, 6F
02/25 14:54, 6F
GameDesign 近期熱門文章
PTT遊戲區 即時熱門文章
10
38