close
開始之前先講明需求:
1.將收到的Packet(rawdata)轉換成可用的遊戲協議(Protocol)
2.動態生成而非使用type assertion去一個個switch case生成
3.有統一的abstract class來轉型並呼叫共通的function
這裡碰到了一些問題,
1.因為Golang不像C#等高階語言可以透過Reflection去走訪所有的Class(Golang也沒有Class),甚至像PHP那樣可以直接使用字串去new class,所以像C/C++那樣先行註冊所有Protocol似乎很難避免。
2.Golang沒有繼承的概念,最多就是可以宣告interface,而由其他struct去實作該interface所描述的函式。
下面是到處爬文跟參考後最終的結果,這作法老實說不知道是不是對的,但起碼是運作正常啦.....
package proto
import (
"reflect"
util "../lib/utility"
)
//宣告基礎介面類別,統一所有Protocols需要具備的函式
type IProtocol interface {
FromBytes(*util.BinaryReader)
ToBytes(*util.BinaryWriter)
Todo()
}
//以名稱來存放所有註冊的Protocol實體
var protoFactory = make(map[string]IProtocol)
//初始化Protocol
func InitProtocol() {
RegistProtocol(new(HeartBeatProto))
}
//註冊所有使用的Protocol
func RegistProtocol(dummy IProtocol) {
dummyType := reflect.TypeOf(dummy).Elem()
protoFactory[dummyType.Name()] = dummy
}
//由Protocol名稱產生一個對應新的Protocol
func MakeInstance(name string) IProtocol {
if dummy, ok := protoFactory[name]; ok {
t := reflect.New(reflect.TypeOf(dummy).Elem()).Interface()
if instance, ok := t.(IProtocol); ok {
return instance
}
}
return nil
}
//將從Packet裡的payload轉化成遊戲使用的Protocol
func TransferRawDataToProtocol(rawData []byte) []IProtocol {
reader := util.NewBinaryReader(rawData)
counts := reader.ReadInt()
protos := make([]IProtocol, counts)
for i := 0; i < counts; i++ {
name := reader.ReadString()
clone := MakeInstance(name)
clone.FromBytes(reader)
protos[i] = clone
}
return protos
}
//將遊戲使用的Protocol轉成Packet內的payload
func TransferProtocolToRawData(protos []IProtocol) []byte {
writer := util.NewBinaryWriter()
writer.WriteInt(len(protos))
for _, proto := range protos {
name := reflect.TypeOf(proto).Elem().Name()
writer.WriteString(name)
proto.ToBytes(writer)
}
rawData := writer.ToBytes()
return rawData
}
//測試用的HeartBeat Protocol
type HeartBeatProto struct {
_id int
_name string
}
//從payload取得自己的資料
func (p *HeartBeatProto) FromBytes(reader *util.BinaryReader) {
p._id = reader.ReadInt()
p._name = reader.ReadString()
}
//將自身資料吐給payload
func (p *HeartBeatProto) ToBytes(writer *util.BinaryWriter) {
writer.WriteInt(p._id)
writer.WriteString(p._name)
}
//遊戲內對應Protocol真正的實作內容
func (p *HeartBeatProto) Todo() {
//fmt.Println("HeartBeatProto Todo")
}
下一篇:
[Golang] 學習筆記(4) XORM設定補充
文章標籤
全站熱搜