[程式] 使用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, 
                                5年前
                            , 1F
02/24 13:40, 1F
※ 編輯: Roronia (220.141.86.66 臺灣), 02/24/2020 17:53:19
推
02/25 10:14, 
                                5年前
                            , 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, 
                                5年前
                            , 3F
02/25 14:44, 3F
→
02/25 14:45, 
                                5年前
                            , 4F
02/25 14:45, 4F
→
02/25 14:47, 
                                5年前
                            , 5F
02/25 14:47, 5F
推
02/25 14:54, 
                                5年前
                            , 6F
02/25 14:54, 6F
GameDesign 近期熱門文章
PTT遊戲區 即時熱門文章
                            124
                        
                            143
                        
                            19
                        
                            31