LAPTOP-PC6VHEF0\XIONGHUY 1 éve
szülő
commit
88f3ba8abd
100 módosított fájl, 24697 hozzáadás és 0 törlés
  1. 1 0
      RO_Server_Trunk-branch_0.1.39/.gitignore
  2. 8 0
      RO_Server_Trunk-branch_0.1.39/.gitlab-ci.yml
  3. 0 0
      RO_Server_Trunk-branch_0.1.39/notice.php
  4. 291 0
      RO_Server_Trunk-branch_0.1.39/rocommon/codec.go
  5. 140 0
      RO_Server_Trunk-branch_0.1.39/rocommon/def.go
  6. 29 0
      RO_Server_Trunk-branch_0.1.39/rocommon/go.mod
  7. 182 0
      RO_Server_Trunk-branch_0.1.39/rocommon/go.sum
  8. 82 0
      RO_Server_Trunk-branch_0.1.39/rocommon/node.go
  9. 198 0
      RO_Server_Trunk-branch_0.1.39/rocommon/rpc/aesctrcrypt.go
  10. 317 0
      RO_Server_Trunk-branch_0.1.39/rocommon/rpc/msg.go
  11. 162 0
      RO_Server_Trunk-branch_0.1.39/rocommon/rpc/rsacrypt.go
  12. 140 0
      RO_Server_Trunk-branch_0.1.39/rocommon/service/etcddesc.go
  13. 433 0
      RO_Server_Trunk-branch_0.1.39/rocommon/service/etcdreg.go
  14. 183 0
      RO_Server_Trunk-branch_0.1.39/rocommon/service/eventqueue.go
  15. 24 0
      RO_Server_Trunk-branch_0.1.39/rocommon/service/flag.go
  16. 264 0
      RO_Server_Trunk-branch_0.1.39/rocommon/service/init.go
  17. 45 0
      RO_Server_Trunk-branch_0.1.39/rocommon/service/multinode.go
  18. 55 0
      RO_Server_Trunk-branch_0.1.39/rocommon/service/redisconnector.go
  19. 143 0
      RO_Server_Trunk-branch_0.1.39/rocommon/service/yamlconfig.go
  20. 102 0
      RO_Server_Trunk-branch_0.1.39/rocommon/socket/http/acceptor.go
  21. 118 0
      RO_Server_Trunk-branch_0.1.39/rocommon/socket/http/connector.go
  22. 39 0
      RO_Server_Trunk-branch_0.1.39/rocommon/socket/http/respond_msg.go
  23. 90 0
      RO_Server_Trunk-branch_0.1.39/rocommon/socket/http/session.go
  24. 97 0
      RO_Server_Trunk-branch_0.1.39/rocommon/socket/mysql/connector.go
  25. 106 0
      RO_Server_Trunk-branch_0.1.39/rocommon/socket/mysql/ormconnector.go
  26. 16 0
      RO_Server_Trunk-branch_0.1.39/rocommon/socket/mysql/sqlparam.go
  27. 79 0
      RO_Server_Trunk-branch_0.1.39/rocommon/socket/mysql/wrapper.go
  28. 144 0
      RO_Server_Trunk-branch_0.1.39/rocommon/socket/nodeproperty.go
  29. 33 0
      RO_Server_Trunk-branch_0.1.39/rocommon/socket/nodereg.go
  30. 436 0
      RO_Server_Trunk-branch_0.1.39/rocommon/socket/procrpc.go
  31. 39 0
      RO_Server_Trunk-branch_0.1.39/rocommon/socket/runtimetag.go
  32. 131 0
      RO_Server_Trunk-branch_0.1.39/rocommon/socket/sessionmanager.go
  33. 117 0
      RO_Server_Trunk-branch_0.1.39/rocommon/socket/socketoption.go
  34. 111 0
      RO_Server_Trunk-branch_0.1.39/rocommon/socket/tcp/acceptor.go
  35. 151 0
      RO_Server_Trunk-branch_0.1.39/rocommon/socket/tcp/connector.go
  36. 7 0
      RO_Server_Trunk-branch_0.1.39/rocommon/socket/tcp/log.go
  37. 21 0
      RO_Server_Trunk-branch_0.1.39/rocommon/socket/tcp/roreuse_linux.go
  38. 17 0
      RO_Server_Trunk-branch_0.1.39/rocommon/socket/tcp/roreuse_windows.go
  39. 335 0
      RO_Server_Trunk-branch_0.1.39/rocommon/socket/tcp/session.go
  40. 135 0
      RO_Server_Trunk-branch_0.1.39/rocommon/socket/websocket/acceptor.go
  41. 132 0
      RO_Server_Trunk-branch_0.1.39/rocommon/socket/websocket/connector.go
  42. 21 0
      RO_Server_Trunk-branch_0.1.39/rocommon/socket/websocket/roreuse_linux.go
  43. 17 0
      RO_Server_Trunk-branch_0.1.39/rocommon/socket/websocket/roreuse_windows.go
  44. 287 0
      RO_Server_Trunk-branch_0.1.39/rocommon/socket/websocket/session.go
  45. 51 0
      RO_Server_Trunk-branch_0.1.39/rocommon/syncrecv.go
  46. 36 0
      RO_Server_Trunk-branch_0.1.39/rocommon/sysmsg.go
  47. 77 0
      RO_Server_Trunk-branch_0.1.39/rocommon/util/bitmap.go
  48. 227 0
      RO_Server_Trunk-branch_0.1.39/rocommon/util/dfa_filter.go
  49. 38 0
      RO_Server_Trunk-branch_0.1.39/rocommon/util/ioutil.go
  50. 299 0
      RO_Server_Trunk-branch_0.1.39/rocommon/util/loghelper.go
  51. 388 0
      RO_Server_Trunk-branch_0.1.39/rocommon/util/timer.go
  52. 149 0
      RO_Server_Trunk-branch_0.1.39/rocommon/util/timewheel.go
  53. 62 0
      RO_Server_Trunk-branch_0.1.39/roserver/auth/main.go
  54. 139 0
      RO_Server_Trunk-branch_0.1.39/roserver/auth/model/auth_check_manager.go
  55. 49 0
      RO_Server_Trunk-branch_0.1.39/roserver/auth/model/auth_model.go
  56. 491 0
      RO_Server_Trunk-branch_0.1.39/roserver/auth/model/auth_msg.go
  57. 84 0
      RO_Server_Trunk-branch_0.1.39/roserver/auth/model/auth_proc.go
  58. 580 0
      RO_Server_Trunk-branch_0.1.39/roserver/baseserver/aoi/aoi.go
  59. 126 0
      RO_Server_Trunk-branch_0.1.39/roserver/baseserver/aoi/aoi_quadtree.go
  60. 361 0
      RO_Server_Trunk-branch_0.1.39/roserver/baseserver/aoi/quad_tree.go
  61. 283 0
      RO_Server_Trunk-branch_0.1.39/roserver/baseserver/aoi/skip_list.go
  62. 406 0
      RO_Server_Trunk-branch_0.1.39/roserver/baseserver/hook_event.go
  63. 373 0
      RO_Server_Trunk-branch_0.1.39/roserver/baseserver/init.go
  64. 149 0
      RO_Server_Trunk-branch_0.1.39/roserver/baseserver/init_hooker.go
  65. 7493 0
      RO_Server_Trunk-branch_0.1.39/roserver/baseserver/model/base_config.go
  66. 901 0
      RO_Server_Trunk-branch_0.1.39/roserver/baseserver/model/base_config_global.go
  67. 486 0
      RO_Server_Trunk-branch_0.1.39/roserver/baseserver/model/client_user.go
  68. 66 0
      RO_Server_Trunk-branch_0.1.39/roserver/baseserver/model/elastic_log_def.go
  69. 145 0
      RO_Server_Trunk-branch_0.1.39/roserver/baseserver/model/front_proc.go
  70. 27 0
      RO_Server_Trunk-branch_0.1.39/roserver/baseserver/model/gate_model.go
  71. 190 0
      RO_Server_Trunk-branch_0.1.39/roserver/baseserver/model/msg.go
  72. 273 0
      RO_Server_Trunk-branch_0.1.39/roserver/baseserver/model/orm_common.go
  73. 404 0
      RO_Server_Trunk-branch_0.1.39/roserver/baseserver/model/service_con.go
  74. 72 0
      RO_Server_Trunk-branch_0.1.39/roserver/baseserver/model/state_machine.go
  75. 468 0
      RO_Server_Trunk-branch_0.1.39/roserver/baseserver/model/util.go
  76. 65 0
      RO_Server_Trunk-branch_0.1.39/roserver/baseserver/router/msg_router.go
  77. 614 0
      RO_Server_Trunk-branch_0.1.39/roserver/baseserver/router/route_table.go
  78. 152 0
      RO_Server_Trunk-branch_0.1.39/roserver/baseserver/set/set.go
  79. 225 0
      RO_Server_Trunk-branch_0.1.39/roserver/baseserver/set/set_nots.go
  80. 300 0
      RO_Server_Trunk-branch_0.1.39/roserver/baseserver/set/set_nots_test.go
  81. 218 0
      RO_Server_Trunk-branch_0.1.39/roserver/baseserver/set/set_test.go
  82. 204 0
      RO_Server_Trunk-branch_0.1.39/roserver/baseserver/set/set_ts.go
  83. 331 0
      RO_Server_Trunk-branch_0.1.39/roserver/baseserver/set/set_ts_test.go
  84. 68 0
      RO_Server_Trunk-branch_0.1.39/roserver/baseserver/shm/shared_memory_linux.go
  85. 88 0
      RO_Server_Trunk-branch_0.1.39/roserver/baseserver/shm/shared_memory_windows.go
  86. 82 0
      RO_Server_Trunk-branch_0.1.39/roserver/baseserver/shm/shm.go
  87. 11 0
      RO_Server_Trunk-branch_0.1.39/roserver/baseserver/version.go
  88. 72 0
      RO_Server_Trunk-branch_0.1.39/roserver/battleboss/main.go
  89. 757 0
      RO_Server_Trunk-branch_0.1.39/roserver/battleboss/model/boss_manager.go
  90. 28 0
      RO_Server_Trunk-branch_0.1.39/roserver/battleboss/model/boss_model.go
  91. 129 0
      RO_Server_Trunk-branch_0.1.39/roserver/battleboss/model/boss_orm_helper.go
  92. 455 0
      RO_Server_Trunk-branch_0.1.39/roserver/battleboss/model/boss_player.go
  93. 40 0
      RO_Server_Trunk-branch_0.1.39/roserver/battleboss/model/boss_player_state.go
  94. 61 0
      RO_Server_Trunk-branch_0.1.39/roserver/battleboss/model/config.go
  95. 146 0
      RO_Server_Trunk-branch_0.1.39/roserver/battleboss/model/msg_send.go
  96. 61 0
      RO_Server_Trunk-branch_0.1.39/roserver/battleboss/msg/battle_msg.go
  97. 62 0
      RO_Server_Trunk-branch_0.1.39/roserver/battlerecord/main.go
  98. 22 0
      RO_Server_Trunk-branch_0.1.39/roserver/battlerecord/model/config.go
  99. 97 0
      RO_Server_Trunk-branch_0.1.39/roserver/battlerecord/model/record_helper.go
  100. 38 0
      RO_Server_Trunk-branch_0.1.39/roserver/battlerecord/msg/record_msg.go

+ 1 - 0
RO_Server_Trunk-branch_0.1.39/.gitignore

@@ -0,0 +1 @@
+.idea/

+ 8 - 0
RO_Server_Trunk-branch_0.1.39/.gitlab-ci.yml

@@ -0,0 +1,8 @@
+stages:
+  - build
+
+
+build:
+  stage: build
+  script:
+    -bash -c 'echo $CI_PROJECT_DIR && cd $CI_PROJECT_DIR && ./ci.sh'

+ 0 - 0
RO_Server_Trunk-branch_0.1.39/notice.php


+ 291 - 0
RO_Server_Trunk-branch_0.1.39/rocommon/codec.go

@@ -0,0 +1,291 @@
+package rocommon
+
+import (
+	"bytes"
+	"encoding/json"
+	"fmt"
+	"github.com/golang/protobuf/proto"
+	"io"
+	"io/ioutil"
+	"log"
+	"net/http"
+	"net/url"
+	"reflect"
+	"strconv"
+	"strings"
+)
+
+type Codec interface {
+	Marshal(msg interface{}) (interface{}, error) //todo...上下文Context
+
+	Unmarshal(data interface{}, msg interface{}) error
+
+	TypeOfName() string
+}
+
+var registerCodec Codec //后续有别的解析部分这边可以添加
+var httpCodec Codec
+
+func init() {
+	//注册protobuf解析
+	RegisterCodec(new(pbCodec))
+	httpCodec = &httpJsonCodec{}
+	//httpCodec = &httpFormCodec{}
+}
+
+func RegisterCodec(c Codec) {
+	log.Println("RegisterCodec pbcodec")
+	registerCodec = c
+}
+
+func GetCodec() Codec {
+	return registerCodec
+}
+func GetHttpCodec(codecName string) Codec {
+	if codecName == "" {
+		return httpCodec
+	}
+	switch codecName {
+	case "httpform":
+		return &httpFormCodec{}
+	case "httpjson":
+		return &httpJsonCodec{}
+	}
+	return httpCodec
+}
+
+//pbCodec
+type pbCodec struct {
+}
+
+func (this *pbCodec) TypeOfName() string {
+	return "protobuf"
+}
+func (this *pbCodec) Marshal(msg interface{}) (interface{}, error) {
+	return proto.Marshal(msg.(proto.Message))
+}
+func (this *pbCodec) Unmarshal(data interface{}, msg interface{}) error {
+	return proto.Unmarshal(data.([]byte), msg.(proto.Message))
+}
+
+//http json
+type httpJsonCodec struct {
+}
+
+func (this *httpJsonCodec) TypeOfName() string {
+	return "httpjson"
+}
+func (this *httpJsonCodec) MimeType() string {
+	return "application/json"
+}
+func (this *httpJsonCodec) Marshal(msg interface{}) (interface{}, error) {
+	httpData, err := json.Marshal(msg)
+	if err != nil {
+		return nil, err
+	}
+	//log.Printf("httpData:%v", httpData)
+
+	return bytes.NewReader(httpData), nil
+}
+func (this *httpJsonCodec) Unmarshal(data interface{}, msg interface{}) error {
+	var reader io.Reader
+	switch v := data.(type) {
+	case *http.Request:
+		reader = v.Body
+	case io.Reader:
+		reader = v
+	}
+	body, err := ioutil.ReadAll(reader)
+	if err != nil {
+		return err
+	}
+	log.Println("httpJsonCodec:", string(body))
+	return json.Unmarshal(body, msg)
+}
+
+//httpForm
+const defaultMemory = 32 * 1024 * 1024
+
+type httpFormCodec struct {
+}
+
+func (this *httpFormCodec) TypeOfName() string {
+	return "httpform"
+}
+func (this *httpFormCodec) MimeType() string {
+	return "application/x-www-form-urlencoded"
+}
+func (this *httpFormCodec) Marshal(msg interface{}) (interface{}, error) {
+	return strings.NewReader(this.form2UrlValues(msg).Encode()), nil
+}
+func (this *httpFormCodec) Unmarshal(data interface{}, msg interface{}) error {
+	//todo...
+	/*
+		var reader io.Reader
+		switch v := data.(type) {
+		case *http.Request:
+			reader = v.Body
+		case io.Reader:
+			reader = v
+		}
+		body,err := ioutil.ReadAll(reader)
+		if err != nil {
+			return err
+		}
+		type aast struct{
+			Ret int
+			Msg string
+		}
+		var aa aast
+		json.Unmarshal(body,&aa)
+		log.Println("body11:", string(body), aa)
+	*/
+
+	//log.Println("type:", reflect.TypeOf(data))
+
+	//reader, err := gzip.NewReader(data.(io.Reader))
+	if msg != nil {
+		body, err := ioutil.ReadAll(data.(io.Reader))
+		if err != nil {
+			return err
+		}
+		//log.Println("body11:", string(body))
+
+		msgValue := reflect.ValueOf(msg)
+		if msgValue.Kind() == reflect.Ptr {
+			msgValue = msgValue.Elem()
+		}
+		msgValue.Field(0).SetString(string(body))
+	}
+
+	//msg = this.value2String(string(body))
+
+	//
+	//resp := data.(*http.Request)
+	//err = resp.ParseForm()
+	//if err != nil {
+	//	return nil
+	//}
+	//log.Println("[httpFormCodec]body:", resp.Form)
+	//resp.ParseMultipartForm(defaultMemory)
+
+	return nil
+}
+func (this *httpFormCodec) form2UrlValues(obj interface{}) url.Values {
+	objValue := reflect.Indirect(reflect.ValueOf(obj))
+	objType := reflect.TypeOf(obj)
+
+	formValues := url.Values{}
+	for i := 0; i < objValue.NumField(); i++ {
+		field := objType.Field(i)
+		val := objValue.Field(i)
+		//if field {
+		formValues.Add(field.Name, this.value2String(val.Interface()))
+		//}
+	}
+	return formValues
+}
+func (this *httpFormCodec) value2String(value interface{}) string {
+	switch v := value.(type) {
+	case string:
+		return v
+	case bool:
+		return strconv.FormatBool(v)
+	case int:
+		return strconv.FormatInt(int64(v), 10)
+	case int32:
+		return strconv.FormatInt(int64(v), 10)
+	case int64:
+		return strconv.FormatInt(int64(v), 10)
+	case float32:
+		return strconv.FormatFloat(float64(v), 'f', -1, 32)
+	case float64:
+		return strconv.FormatFloat(v, 'f', -1, 64)
+	default:
+		panic("Unknown type to convert to string")
+	}
+}
+
+/////////////////////
+type MessageInfo struct {
+	Codec        Codec
+	Type         reflect.Type
+	ID           int
+	ConfirmMsgId int //需要确认的req消息,如果info是req则是ack的id,如果是ack则是req的id
+}
+
+var (
+	messageByID   = map[int]*MessageInfo{}
+	messageByType = map[reflect.Type]*MessageInfo{}
+	messageByName = map[string]*MessageInfo{}
+)
+
+func RegisterMessageInfo(info *MessageInfo) {
+	//注册时统一为非指针类型
+	if info.Type.Kind() == reflect.Ptr {
+		info.Type = info.Type.Elem()
+	}
+
+	if info.ID == 0 {
+		panic(fmt.Sprintf("message ID invalid:%v", info.Type.Name()))
+	}
+
+	if _, ok := messageByID[info.ID]; ok {
+		panic(fmt.Sprintf("message has register id:%v", info.Type.Name()))
+	} else {
+		messageByID[info.ID] = info
+	}
+
+	if _, ok := messageByType[info.Type]; ok {
+		panic(fmt.Sprintf("message has register type:%v", info.Type.Name()))
+	} else {
+		messageByType[info.Type] = info
+	}
+
+	if _, ok := messageByName[info.Type.Name()]; ok {
+		panic(fmt.Sprintf("message has register name:%v", info.Type.Name()))
+	} else {
+		messageByName[info.Type.Name()] = info
+	}
+
+	//log.Printf("message register [id|type|name][%v%v|%v]\n", info.ID,info.Type,info.Type.Name())
+}
+
+func MessageInfoByID(id int) *MessageInfo {
+	if data, ok := messageByID[id]; ok {
+		return data
+	}
+	return nil
+}
+
+func MessageInfoByMsg(msg interface{}) *MessageInfo {
+	msgType := reflect.TypeOf(msg)
+	if msgType.Kind() == reflect.Ptr {
+		if info, ok := messageByType[msgType.Elem()]; ok {
+			return info
+		}
+		return nil
+	} else {
+		if info, ok := messageByType[msgType]; ok {
+			return info
+		}
+		return nil
+	}
+}
+
+func MessageInfoByName(name string) *MessageInfo {
+	if info, ok := messageByName[name]; ok {
+		return info
+	}
+	return nil
+}
+
+func MessageToString(msg interface{}) string {
+	if msg == nil {
+		return ""
+	}
+	if str, ok := msg.(interface{ String() string }); ok {
+		return str.String()
+	}
+	return ""
+}

+ 140 - 0
RO_Server_Trunk-branch_0.1.39/rocommon/def.go

@@ -0,0 +1,140 @@
+package rocommon
+
+//连接session
+type Session interface {
+	//获得net.Conn
+	Raw() interface{}
+
+	//todo...
+	Node() ServerNode //tcpAcceptor / tcpConnector
+
+	Send(msg interface{})
+	Close()
+	//表示ID
+	ID() uint64
+
+	//aes密码(加密解密)
+	GetAES() *[]byte
+	SetAES(aes string)
+	GetHandCode() string
+	SetHandCode(code string)
+	GetSessionOpt() interface{}
+	GetSessionOptFlag() bool
+	SetSessionOptFlag(flag bool)
+	HeartBeat(msg interface{})
+	IncRecvPingNum(incNum int)
+	RecvPingNum() int
+}
+
+//事件处理队列
+type NetEventQueue interface {
+	StartQueue() NetEventQueue
+
+	StopQueue() NetEventQueue
+
+	Wait()
+
+	PostCb(callback func())
+
+	AttachUpdateModule(update UpdateModule)
+}
+
+//处理主逻辑的更新操作
+type UpdateModule interface {
+	//传入的时间为毫秒
+	Update(ms uint64)
+	Init()
+}
+type UpdateLogic interface {
+	//传入的时间为毫秒
+	Update(ms uint64)
+}
+
+//event相关
+type ProcEvent interface {
+	Session() Session //会话信息
+	Msg() interface{} //消息
+	SeqId() uint32    //消息序列号
+	KVTime() uint64   //接受到消息时的时间
+}
+
+//输入返回输出
+type EventHook interface {
+	InEvent(in ProcEvent) ProcEvent   //获得接收事件
+	OutEvent(out ProcEvent) ProcEvent //获得发送事件
+}
+type EventCallBack func(e ProcEvent)
+
+//消息处理
+type MessageProcessor interface {
+	//recv
+	OnRecvMsg(s Session) (interface{}, uint32, error)
+	//send
+	OnSendMsg(s Session, msg interface{}) error
+}
+
+///////////////////////////////////
+//recv send event -> ProcEvent
+type RecvMsgEvent struct {
+	Sess     Session
+	Message  interface{}
+	Err      error
+	MsgSeqId uint32
+	KvTime   uint64
+}
+
+func (this *RecvMsgEvent) Session() Session {
+	return this.Sess
+}
+func (this *RecvMsgEvent) Msg() interface{} {
+	return this.Message
+}
+func (this *RecvMsgEvent) SeqId() uint32 {
+	return this.MsgSeqId
+}
+func (this *RecvMsgEvent) KVTime() uint64 {
+	return this.KvTime
+}
+
+//接收到消息处理后并回复消息(如果需要回复调用该接口)
+func (this *RecvMsgEvent) Replay(msg interface{}) error {
+	this.Sess.Send(msg)
+	return nil
+}
+
+type SendMsgEvent struct {
+	Sess    Session
+	Message interface{}
+}
+
+func (this *SendMsgEvent) Session() Session {
+	return this.Sess
+}
+func (this *SendMsgEvent) Msg() interface{} {
+	return this.Message
+}
+func (this *SendMsgEvent) SeqId() uint32 {
+	return 0
+}
+func (this *SendMsgEvent) KVTime() uint64 {
+	return 0
+}
+
+type ReplayEvent interface {
+	Replay(msg interface{}) error
+}
+
+//直接发送数据,例如game,发给gate,然后gate直接发送
+type TransmitPacket struct {
+	MsgData []byte
+	MsgId   uint32
+	SeqId   uint32
+}
+
+///////////////////////////////////
+//http处理
+type HTTPRequest struct {
+	ReqMsg       interface{} //request
+	ResMsg       interface{} //response
+	ReqCodecName string      //默认为json
+}

+ 29 - 0
RO_Server_Trunk-branch_0.1.39/rocommon/go.mod

@@ -0,0 +1,29 @@
+module rocommon
+
+go 1.12
+
+require (
+	github.com/360EntSecGroup-Skylar/excelize v1.4.1 // indirect
+	github.com/coreos/etcd v3.3.13+incompatible
+	github.com/fogleman/gg v1.3.0 // indirect
+	github.com/gin-gonic/gin v1.6.3 // indirect
+	github.com/go-redis/redis v6.15.2+incompatible
+	github.com/go-sql-driver/mysql v1.5.0
+	github.com/gogf/gf v1.13.4 // indirect
+	github.com/gogo/protobuf v1.2.1
+	github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
+	github.com/golang/protobuf v1.3.3
+	github.com/labstack/echo/v4 v4.1.16 // indirect
+	github.com/olivere/elastic/v7 v7.0.12
+	github.com/pkg/profile v1.4.0 // indirect
+	go.etcd.io/etcd v3.3.13+incompatible //indirect
+	gopkg.in/yaml.v2 v2.2.8
+	gorm.io/driver/mysql v1.0.3
+	gorm.io/gorm v1.20.11
+)
+
+replace github.com/coreos/bbolt v1.3.6 => go.etcd.io/bbolt v1.3.6
+
+replace github.com/coreos/etcd => github.com/coreos/etcd v3.3.20+incompatible
+
+replace google.golang.org/grpc => google.golang.org/grpc v1.29.1

+ 182 - 0
RO_Server_Trunk-branch_0.1.39/rocommon/go.sum

@@ -0,0 +1,182 @@
+cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+github.com/360EntSecGroup-Skylar/excelize v1.4.1 h1:l55mJb6rkkaUzOpSsgEeKYtS6/0gHwBYyfo5Jcjv/Ks=
+github.com/360EntSecGroup-Skylar/excelize v1.4.1/go.mod h1:vnax29X2usfl7HHkBrX5EvSCJcmH3dT9luvxzu8iGAE=
+github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/aws/aws-sdk-go v1.29.11/go.mod h1:1KvfttTE3SPKMpo8g2c6jL3ZKfXtFvKscTgahTma5Xg=
+github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
+github.com/clbanning/mxj v1.8.5-0.20200714211355-ff02cfb8ea28/go.mod h1:BVjHeAH+rl9rs6f+QIpeRl0tfu10SXn1pUSa5PVGJng=
+github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
+github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
+github.com/coreos/etcd v3.3.13+incompatible h1:8F3hqu9fGYLBifCmRCJsicFqDx/D68Rt3q1JMazcgBQ=
+github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
+github.com/coreos/etcd v3.3.20+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
+github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
+github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
+github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
+github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g=
+github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
+github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
+github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
+github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14=
+github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
+github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
+github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
+github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
+github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no=
+github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
+github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY=
+github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=
+github.com/go-redis/redis v6.15.2+incompatible h1:9SpNVG76gr6InJGxoZ6IuuxaCOQwDAhzyXg+Bs+0Sb4=
+github.com/go-redis/redis v6.15.2+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
+github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
+github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
+github.com/gogf/gf v1.13.4/go.mod h1:dGX0/BElXDBYbdJGascqfrWScj8IMeOietDjVD6/5Fc=
+github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE=
+github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
+github.com/gogo/protobuf v1.3.0/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
+github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
+github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
+github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
+github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.3 h1:gyjaxf+svBWX08ZjK86iN9geUJF0H6gp2IRKX6Nf6/I=
+github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
+github.com/gomodule/redigo v2.0.0+incompatible/go.mod h1:B4C85qUVwatsJoIUNIfCRsp7qO0iAmpGFZ4EELWSbC4=
+github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
+github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
+github.com/gqcn/structs v1.1.1/go.mod h1:/aBhTBSsKQ2Ec9pbnYdGphtdWXHFn4KrCL0fXM/Adok=
+github.com/grokify/html-strip-tags-go v0.0.0-20190921062105-daaa06bf1aaf/go.mod h1:2Su6romC5/1VXOQMaWL2yb618ARB8iVo6/DR99A6d78=
+github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
+github.com/jinzhu/now v1.1.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
+github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
+github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
+github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
+github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
+github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
+github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/labstack/echo/v4 v4.1.16/go.mod h1:awO+5TzAjvL8XpibdsfXxPgHr+orhtXZJZIQCVjogKI=
+github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k=
+github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
+github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
+github.com/mailru/easyjson v0.7.1 h1:mdxE1MF9o53iCb2Ghj1VfWvh7ZOwHpnVG/xwXrV90U8=
+github.com/mailru/easyjson v0.7.1/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs=
+github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
+github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
+github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
+github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
+github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
+github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
+github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
+github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw=
+github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
+github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
+github.com/olivere/elastic/v7 v7.0.12 h1:91kj/UMKWQt8VAHBm5BDHpVmzdfPCmICaUFy2oH4LkQ=
+github.com/olivere/elastic/v7 v7.0.12/go.mod h1:14rWX28Pnh3qCKYRVnSGXWLf9MbLonYS/4FDCY3LAPo=
+github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
+github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
+github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/profile v1.4.0 h1:uCmaf4vVbWAOZz36k1hrQD7ijGRzLwaME8Am/7a4jZI=
+github.com/pkg/profile v1.4.0/go.mod h1:NWz/XGvpEW1FyYQ7fCx4dqYBLlfTcE+A9FLAkNKqjFE=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/smartystreets/assertions v1.0.1/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM=
+github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9/go.mod h1:SnhjPscd9TpLiy1LpzGSKh3bXCfxxXuqd9xmQJy3slM=
+github.com/smartystreets/gunit v1.1.3/go.mod h1:EH5qMBab2UclzXUcpR8b93eHsIlp9u+pDQIRp5DZNzQ=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.2.3-0.20181224173747-660f15d67dbb/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
+github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
+github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
+github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
+github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
+github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
+github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
+github.com/valyala/fasttemplate v1.1.0/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
+go.etcd.io/etcd v3.3.13+incompatible h1:jCejD5EMnlGxFvcGRyEV4VGlENZc7oPQX6o0t7n3xbw=
+go.etcd.io/etcd v3.3.13+incompatible/go.mod h1:yaeTdrJi5lOmYerz05bd8+V7KubZs8YSFZfzsF9A6aI=
+go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20200221231518-2aa609cf4a9d/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
+golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190724013045-ca1201d0de80 h1:Ao/3l156eZf2AW5wK8a7/smtodRU+gha3+BeqJ69lRk=
+golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200202094626-16171245cfb2 h1:CCH4IOTTfewWjGOlSp+zGcjutRKlBEZQ6wTn8ozI/nI=
+golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
+golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
+golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
+golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
+golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135 h1:5Beo0mZN8dRzgrMMkDp0jc8YXQKx9DiJ2k1dkvGsn5A=
+golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
+google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8 h1:Nw54tB0rB7hY/N0NQvRW8DG4Yk3Q6T9cu9RcFQDu1tc=
+google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
+google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb h1:i1Ppqkc3WQXikh8bXiwHqAN5Rv3/qDCcRk0/Otx73BY=
+google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
+google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
+google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
+google.golang.org/grpc v1.22.1 h1:/7cs52RnTJmD43s3uxzlq2U7nqVTd/37viQwMrMNlOM=
+google.golang.org/grpc v1.22.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
+google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
+gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gorm.io/driver/mysql v1.0.3/go.mod h1:twGxftLBlFgNVNakL7F+P/x9oYqoymG3YYT8cAfI9oI=
+gorm.io/gorm v1.20.4/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw=
+gorm.io/gorm v1.20.11/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw=
+honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

+ 82 - 0
RO_Server_Trunk-branch_0.1.39/rocommon/node.go

@@ -0,0 +1,82 @@
+package rocommon
+
+import (
+	"time"
+)
+
+//代表多种类型
+type ServerNode interface {
+	//开启服务器
+	Start() ServerNode
+	Stop()
+	//tcpConnector / tcpAcceptor
+	TypeOfName() string
+}
+
+type ServerNodeProperty interface {
+	GetName() string //ServerName gate/game/db
+	SetName(s string)
+	GetAddr() string
+	SetAddr(s string)
+	SetQueue(v NetEventQueue)
+	Queue() NetEventQueue
+	SetServerType(t int)
+	ServerType() int
+	SetZone(t int)
+	GetZone() int
+	SetIndex(t int)
+	GetIndex() int
+}
+
+//session管理接口
+type SessionMagExport interface {
+	GetSession(uint64) Session
+	SessionNum() int
+	CloseAllSession()
+	SetUuidCreateKey(genKey int)
+}
+
+//socketOption socketOption.go
+type TCPSocketOption interface {
+	SetSocketBuff(read, write int, noDelay bool)
+	SetMaxMsgLen(size int)
+	SetSocketDeadline(read, write time.Duration)
+}
+
+type MySqlOption interface {
+	SetConnCount(val int)
+}
+
+//NetProcessorRPC procrpc.go
+type ProcessorRPCBundle interface {
+	SetTransmitter(v MessageProcessor)
+	SetHooker(v EventHook)
+	SetCallback(v EventCallBack)
+}
+
+//tcpConnector暴露的对外接口
+type TCPConnector interface {
+	TCPSocketOption
+	SetReconnectTime(delta time.Duration)
+	Session() Session
+}
+
+//tcpAcceptor暴露的对外接口
+type TCPAcceptor interface {
+	TCPSocketOption
+	SessionMagExport
+}
+
+//NetContextSet nodeproperty.go
+type ContextSet interface {
+	//绑定自定义属性
+	SetContextData(key, value interface{}, from string)
+	//获得key对应的属性
+	GetContextData(key interface{}) (interface{}, bool)
+	//根据给定类型获取数据
+	RawContextData(key interface{}, valuePtr interface{}) bool //sid(etcd期间使用) ctx(连接成功后服务器之间使用)
+}
+
+type HTTPConnector interface {
+	Request(method, path string, param *HTTPRequest) error
+}

+ 198 - 0
RO_Server_Trunk-branch_0.1.39/rocommon/rpc/aesctrcrypt.go

@@ -0,0 +1,198 @@
+package rpc
+
+import (
+	"bytes"
+	"crypto/aes"
+	"crypto/cipher"
+	"errors"
+	"math/rand"
+	"strconv"
+)
+
+/*
+	textStr := []byte("we are ro team")
+
+	aesPass := []byte("wenting123456789")
+	retStr, err := rpc.AESCtrEncrypt(textStr, aesPass)
+	if err != nil {
+		log.Printf("err:%v", err)
+		return
+	}
+	retStr1 := base64.StdEncoding.EncodeToString(retStr)
+	log.Printf("en:%v", retStr1)
+
+	plainText,err := rpc.AESCtrDecrypt(retStr, aesPass)
+	if err != nil {
+		log.Printf("err:%v", err)
+		return
+	}
+	log.Printf("de:%v", string(plainText))
+*/
+
+var ErrKeyLen = errors.New("a sixteen or twenty-four or thirty-two length secret key is required")
+var ErrIvAes = errors.New("a sixteen-length ivaes is required")
+var ErrPaddingSize = errors.New("padding size error please check the secret key or iv")
+
+var ivaes = "wenting123456789"
+
+func GetAESKey(len int) string {
+	//key := make([]byte, len)
+	//for idx := 0; idx < len; idx++ {
+	//	key[idx] = byte(rand.Int31n(256))
+	//
+	//}
+	//retStr := base64.StdEncoding.EncodeToString(key)
+
+	//return "wenting123456789"
+	retStr := "wt"
+	for idx := 0; idx < len-2; idx++ {
+		retStr += strconv.Itoa(int(rand.Int31n(10)))
+
+	}
+	ivaes = retStr
+
+	return retStr
+}
+
+func AESCtrEncrypt(textStr, key []byte, ivAes ...byte) ([]byte, error) {
+	return AESCbcEncrypt(textStr, key, ivAes...)
+	//if len(key) != 16 && len(key) != 24 && len(key) != 32 {
+	//	return nil, ErrKeyLen
+	//}
+	//if len(ivAes) != 0 && len(ivAes) != 16 {
+	//	return nil, ErrIvAes
+	//}
+	//
+	//block, err := aes.NewCipher(key)
+	//if err != nil {
+	//	return nil, err
+	//}
+	//
+	//var iv []byte
+	//if len(ivAes) != 0 {
+	//	iv = ivAes
+	//} else {
+	//	iv = []byte(ivaes)
+	//}
+	//
+	//data := cipher.NewCTR(block, iv)
+	//retText := make([]byte, len(textStr))
+	//data.XORKeyStream(retText, textStr)
+	//
+	//return retText, nil
+}
+
+func AESCtrDecrypt(cryptText, key []byte, ivAes ...byte) ([]byte, error) {
+	return AESCbcDecrypt(cryptText, key, ivAes...)
+	//
+	//if key != nil && len(key) != 16 && len(key) != 24 && len(key) != 32 {
+	//	log.Println("AESCtrDecrypt key:", key)
+	//	return nil, ErrKeyLen
+	//}
+	//if len(ivAes) != 0 && len(ivAes) != 16 {
+	//	return nil, ErrIvAes
+	//}
+	//
+	//block, err := aes.NewCipher(key)
+	//if err != nil {
+	//	return nil, err
+	//}
+	//var iv []byte
+	//if len(ivAes) != 0 {
+	//	iv = ivAes
+	//} else {
+	//	iv = []byte(ivaes)
+	//}
+	//
+	//data := cipher.NewCTR(block, iv)
+	//retText := make([]byte, len(cryptText))
+	//data.XORKeyStream(retText, cryptText)
+	//return retText, nil
+}
+
+func AESCbcEncrypt(plainText, key []byte, ivAes ...byte) ([]byte, error) {
+	if len(key) != 16 && len(key) != 24 && len(key) != 32 {
+		return nil, ErrKeyLen
+	}
+	block, err := aes.NewCipher(key)
+	if err != nil {
+		return nil, err
+	}
+	paddingText := PKCS5Padding(plainText, block.BlockSize())
+
+	var iv []byte
+	if len(ivAes) != 0 {
+		if len(ivAes) != 16 {
+			return nil, ErrIvAes
+		} else {
+			iv = ivAes
+		}
+	} else {
+		iv = []byte(ivaes)
+	} // To initialize the vector, it needs to be the same length as block.blocksize
+	blockMode := cipher.NewCBCEncrypter(block, iv)
+	cipherText := make([]byte, len(paddingText))
+	blockMode.CryptBlocks(cipherText, paddingText)
+	return cipherText, nil
+}
+
+// decrypt
+func AESCbcDecrypt(cipherText, key []byte, ivAes ...byte) ([]byte, error) {
+	if len(key) != 16 && len(key) != 24 && len(key) != 32 {
+		return nil, ErrKeyLen
+	}
+
+	block, err := aes.NewCipher(key)
+	if err != nil {
+		return nil, err
+	}
+
+	var iv []byte
+	if len(ivAes) != 0 {
+		if len(ivAes) != 16 {
+			return nil, ErrIvAes
+		} else {
+			iv = ivAes
+		}
+	} else {
+		iv = []byte(ivaes)
+	}
+	blockMode := cipher.NewCBCDecrypter(block, iv)
+	paddingText := make([]byte, len(cipherText))
+	blockMode.CryptBlocks(paddingText, cipherText)
+
+	plainText, err := PKCS5UnPadding(paddingText)
+	if err != nil {
+		return nil, err
+	}
+	return plainText, nil
+}
+
+func PKCS5Padding(plainText []byte, blockSize int) []byte {
+	if blockSize <= 0 {
+		return nil
+	}
+	padding := blockSize - (len(plainText) % blockSize)
+	padText := bytes.Repeat([]byte{byte(padding)}, padding)
+	//todo...
+	// runtime.slicecopy()导致DATA RACE
+	len1 := len(plainText)
+	len2 := len(padText)
+	newText := make([]byte, len1+len2)
+	copy(newText[0:], plainText[:len1])
+	copy(newText[len1:], padText[:len2])
+	//newText := append(plainText, padText...)
+	return newText
+}
+
+func PKCS5UnPadding(plainText []byte) ([]byte, error) {
+	length := len(plainText)
+	if length <= 0 {
+		return plainText, nil
+	}
+	number := int(plainText[length-1])
+	if number > length {
+		return nil, ErrPaddingSize
+	}
+	return plainText[:length-number], nil
+}

+ 317 - 0
RO_Server_Trunk-branch_0.1.39/rocommon/rpc/msg.go

@@ -0,0 +1,317 @@
+package rpc
+
+import (
+	"encoding/binary"
+	"errors"
+	"fmt"
+	"io"
+	"reflect"
+	"rocommon"
+	"rocommon/util"
+)
+
+const (
+	lenMaxLen  = 2 //包体大小2个字节 uint16
+	msgIdLen   = 2 //包ID大小2个字节  uint16
+	msgSeqlen  = 4 //发送序列号2个字节大小,用来断线重连
+	msgFlaglen = 2 //暂定标记,加解密 1表示RSA,2表示AES
+
+	SC_HAND_SHAKE_NTFMsgId = 1006
+	SC_HAND_SHAKE_ACKMsgId = 0
+	CS_HAND_SHAKE_REQMsgId = 0
+	SC_PING_ACKMsgId       = 1001
+)
+
+//var SC_HAND_SHAKE_NTFMsgId = MessageInfoByName("SCHandShakeNtf").ID
+
+///////////////////////
+func ReadMessage(reader io.Reader, maxMsgLen int, aesKey *[]byte) (msg interface{}, msgSeqId uint32, err error) {
+	var msgId, flagId uint16 = 0, 0
+	var msgData []byte
+	msgId, msgSeqId, flagId, msgData, err = RecvPackageData(reader, maxMsgLen)
+	if err != nil {
+		return nil, 0, err
+	}
+
+	switch flagId {
+	case 1:
+		if int(msgId) == SC_HAND_SHAKE_NTFMsgId { //SC_HAND_SHAKE_NTF
+			msgData, err = RSADecrypt(msgData, PrivateClientKey)
+			if err != nil {
+				return nil, 0, err
+			}
+		} else if int(msgId) == CS_HAND_SHAKE_REQMsgId { //CS_HAND_SHAKE_REQ
+			msgData, err = RSADecrypt(msgData, PrivateServerKey)
+			if err != nil {
+				return nil, 0, err
+			}
+		} else if int(msgId) == SC_HAND_SHAKE_ACKMsgId { //SC_HAND_SHAKE_ACK
+			msgData, err = RSADecrypt(msgData, PrivateClientKey)
+			if err != nil {
+				return nil, 0, err
+			}
+		} else {
+			msgData, err = RSADecrypt(msgData, PrivateKey)
+			if err != nil {
+				return nil, 0, err
+			}
+		}
+	case 2:
+		msgData, err = AESCtrDecrypt(msgData, *aesKey, *aesKey...)
+		//msgData, err = AESCtrDecrypt(msgData, *aesKey)
+		if err != nil {
+			return nil, 0, err
+		}
+	}
+
+	//服务器内部不做加密处理
+	msg, _, err = DecodeMessage(int(msgId), msgData)
+	if err != nil {
+		//log.Println("[DecodeMessage] err:", err)
+		return nil, 0, errors.New(fmt.Sprintf("msg decodeMessage failed:%v %v", msgId, err))
+	}
+
+	/*
+
+		bufMsgLen := make([]byte, lenMaxLen)
+		_, err = io.ReadFull(reader, bufMsgLen)
+		if err != nil {
+			//log.Println("[ReadMessage] read message err:", err)
+			return
+		}
+
+		if len(bufMsgLen) < lenMaxLen {
+			err = errors.New("message too short")
+			return
+		}
+
+		msgLen := binary.BigEndian.Uint16(bufMsgLen)
+		if(msgLen > 0 && msgLen > uint16(maxMsgLen)) || msgLen < lenMaxLen{
+			err = errors.New(fmt.Sprintf("message too big33:%v %v\n",msgLen, maxMsgLen))
+			return
+		}
+
+		msgData := make([]byte, msgLen - lenMaxLen)
+		if _, err = io.ReadFull(reader, msgData); err != nil {
+			//log.Println("[ReadMessage] read message err:", err)
+			return
+		}
+		if len(msgData) < msgIdLen{
+			return nil, 0, errors.New("message id too short")
+		}
+
+		msgId := binary.BigEndian.Uint16(msgData)
+		msgData = msgData[msgIdLen:]
+		msgSeqId = binary.BigEndian.Uint32(msgData) //序列号
+		//log.Println("readSeqId:", msgSeqId)
+		body := msgData[msgSeqlen:]
+		msg, _, err = DecodeMessage(int(msgId), body)
+		if err != nil {
+			//log.Println("[DecodeMessage] err:", err)
+			return nil, 0, errors.New(fmt.Sprintf("msg decodeMessage failed:%v %v",msgId, err))
+		}
+	*/
+	return
+}
+
+//消息反序列化
+func DecodeMessage(id int, data []byte) (interface{}, *rocommon.MessageInfo, error) {
+	msgInfo := rocommon.MessageInfoByID(id)
+	if msgInfo == nil {
+		return nil, nil, errors.New("msg not register")
+	}
+
+	msg := reflect.New(msgInfo.Type).Interface()
+	//解码操作这边直接用protobuf即可
+	err := msgInfo.Codec.Unmarshal(data, msg)
+	if err != nil {
+		return nil, msgInfo, err
+	}
+	return msg, msgInfo, nil
+}
+
+func SendMessage(writer io.Writer, msg interface{}, aesKey *[]byte, maxMsgLen int, nodeName string) (err error) {
+	var (
+		msgData []byte
+		msgId   uint16
+		seqId   uint32
+		msgInfo *rocommon.MessageInfo
+	)
+
+	switch m := msg.(type) {
+	case *rocommon.TransmitPacket:
+		msgData = m.MsgData
+		msgId = uint16(m.MsgId)
+		seqId = m.SeqId
+	default:
+		msgData, msgInfo, err = EncodeMessage(msg)
+		if err != nil {
+			return err
+		}
+		msgId = uint16(msgInfo.ID)
+	}
+
+	//todo
+	// 注意上层发包不要超过最大值
+	msgLen := len(msgData)
+	var cryptType uint16 = 0
+
+	//握手阶段
+	if msgId == uint16(SC_HAND_SHAKE_NTFMsgId) {
+		cryptType = 1
+		msgData, err = RSAEncrypt(msgData, PublicClientKey)
+		if err != nil {
+			return err
+		}
+		msgLen = len(msgData)
+	} else {
+		if len(*aesKey) > 0 && msgId != SC_PING_ACKMsgId {
+			cryptType = 2
+			msgData, err = AESCtrEncrypt(msgData, *aesKey, *aesKey...)
+			//msgData, err = AESCtrEncrypt(msgData, *aesKey)
+			if err != nil {
+				return err
+			}
+			msgLen = len(msgData)
+		}
+	}
+
+	if msgLen > maxMsgLen {
+		err = errors.New(fmt.Sprintf("message too big msgId=%v msglen=%v maxlen=%v", msgId, msgLen, maxMsgLen))
+		util.FatalF("SendMessage err=%v", err)
+		err = nil
+		return
+	}
+
+	//data := make([]byte, lenMaxLen + msgIdLen + msgLen)
+	data := make([]byte, lenMaxLen+msgIdLen+msgSeqlen+msgFlaglen+msgLen) //head + body
+	//lenMaxLen
+	binary.BigEndian.PutUint16(data, uint16(msgLen))
+	//msgIdLen
+	binary.BigEndian.PutUint16(data[lenMaxLen:], msgId)
+	//seq 返回客户端发送的序列号
+	binary.BigEndian.PutUint32(data[lenMaxLen+msgIdLen:], seqId)
+	//log.Println("sendSeqId:", seqId)
+	//使用的加密方式AES
+	binary.BigEndian.PutUint16(data[lenMaxLen+msgIdLen+msgSeqlen:], cryptType)
+
+	//body
+	if msgLen > 0 {
+		copy(data[lenMaxLen+msgIdLen+msgSeqlen+msgFlaglen:], msgData)
+	}
+
+	//ioutil.go
+	err = util.WriteFull(writer, data)
+
+	//todo...使用内存池是否data数据
+
+	return err
+}
+
+//消息序列化
+func EncodeMessage(msg interface{}) (data []byte, info *rocommon.MessageInfo, err error) {
+	info = rocommon.MessageInfoByMsg(msg)
+	if info == nil {
+		return nil, nil, errors.New("msg not register")
+	}
+
+	//log.Println("EncodeMessage:", msg)
+	tempData, e := info.Codec.Marshal(msg)
+	data = tempData.([]byte)
+	err = e
+	return
+}
+
+//获取原始包数据(二进制),不做解析处理
+func RecvPackageData(reader io.Reader, maxMsgLen int) (msgId uint16, msgSeqId uint32, msgFlagId uint16, msgData []byte, err error) {
+	bufMsgLen := make([]byte, lenMaxLen)
+	_, err = io.ReadFull(reader, bufMsgLen)
+	if err != nil {
+		//log.Println("[ReadMessage] read message err:", err)
+		return
+	}
+
+	if len(bufMsgLen) < lenMaxLen {
+		//err = errors.New("message too short")
+		return
+	}
+
+	//msgId
+	bufIdLen := make([]byte, msgIdLen)
+	_, err = io.ReadFull(reader, bufIdLen)
+	if err != nil {
+		//log.Println("[ReadMessage] read message err:", err)
+		return
+	}
+	if len(bufIdLen) < msgIdLen {
+		//err = errors.New("message too short")
+		return
+	}
+	msgId = binary.BigEndian.Uint16(bufIdLen)
+	//msgseqid
+	bufSeqIdLen := make([]byte, msgSeqlen)
+	_, err = io.ReadFull(reader, bufSeqIdLen)
+	if err != nil {
+		//log.Println("[ReadMessage] read message err:", err)
+		return
+	}
+	if len(bufSeqIdLen) < msgSeqlen {
+		//err = errors.New("message too short")
+		return
+	}
+	msgSeqId = binary.BigEndian.Uint32(bufSeqIdLen)
+
+	//msgFlaglen 1表示RSA,2表示AES
+	bufFlagLen := make([]byte, msgFlaglen)
+	_, err = io.ReadFull(reader, bufFlagLen)
+	if err != nil {
+		return
+	}
+	if len(bufFlagLen) < msgFlaglen {
+		return
+	}
+	msgFlagId = binary.BigEndian.Uint16(bufFlagLen)
+
+	//BigEndian
+	msgLen := binary.BigEndian.Uint16(bufMsgLen)
+	if msgLen > 0 && msgLen > uint16(maxMsgLen) {
+		//err = errors.New("message too big")
+		err = errors.New(fmt.Sprintf("message too big msgid=%v mslen=%v maxlen=%v bufMsgLen=%v msgFlagId=%v\n",
+			msgId, msgLen, maxMsgLen, len(bufMsgLen), msgFlagId))
+		util.FatalF("RecvPackageData err=%v", err)
+		err = nil
+		return
+	}
+
+	//todo 可以使用内存池
+	if msgLen > 0 {
+		//body := make([]byte, msgLen)
+		//if _, err = io.ReadFull(reader, body); err != nil {
+		//	//log.Println("[ReadMessage] read message err:", err)
+		//	return
+		//}
+		//if len(body) < int(msgLen) {
+		//	err = errors.New(fmt.Sprintf("message id too short msgid=%v", msgId))
+		//	return
+		//}
+		//
+		////msgId = binary.BigEndian.Uint16(body)
+		////body = body[msgIdLen:]
+		////msgSeqId = binary.BigEndian.Uint32(body) //序列号
+		////log.Println("readSeqId:", msgSeqId)
+		////msgData = body[msgSeqlen:]
+		//msgData = body
+
+		msgData = make([]byte, msgLen)
+		if _, err = io.ReadFull(reader, msgData); err != nil {
+			//log.Println("[ReadMessage] read message err:", err)
+			return
+		}
+		if len(msgData) < int(msgLen) {
+			err = errors.New(fmt.Sprintf("message id too short msgid=%v", msgId))
+			return
+		}
+	}
+
+	return
+}

+ 162 - 0
RO_Server_Trunk-branch_0.1.39/rocommon/rpc/rsacrypt.go

@@ -0,0 +1,162 @@
+package rpc
+
+import (
+	"crypto/rand"
+	"crypto/rsa"
+	"crypto/x509"
+	"encoding/asn1"
+	"encoding/base64"
+	"encoding/pem"
+	"os"
+)
+
+const (
+	privateKey = `-----BEGIN RSA PRIVATE KEY-----
+MIICWwIBAAKBgQCTnWuCTLNtDiqCt6fEfnLRUGT4zrPPgL1l8alZBcgdIC8ErtqxOZLFjVTYqxE8dqnkyBhW9pjv2WodAf9o0D5Em0Ysx2I8yurWBGmvpxLIaMaqqIPuKBYJSzJkv2wht5eXrUpCJBxn/0kFSBBLvvq/9NWWDniVA71NQaGPUal/DQIBAwKBgBiaPJW3czzXscBz8UtqaHg4ENQic01AH5D9nDmA9q+FXStyecg0QyDs43lx2DS+caYhWWPTxCf5ka+AVTwitQsuDkQ/f9bLvxaqCqhZck2ph0Bb/N+CYKU5jgy88BNZjLvjdLBTjBeVQjk57ofLS6r9mn+QXF4z+fpnIEJrbX7LAkEA1/DMrghmNYuVWK5BKQWJzBkKS4k/ef7Gh8QFNyQ8pV+xExNK2T0BjmZH+uA6Sigkn3otqj7fnB3AtbNB5SDifQJBAK7/xpxazc7kuK97fGVfbKOCHjUNcZ/TY2oaExqncPjrf0V61VWW2PFVZfGY4rEMmWO8awIPgC/DriEsvuf3o9ECQQCP9d3JWu7OXQ47HtYbWQaIELGHsNT7/y8FLVjPbX3DlSC3YjHmKKu0RC/8lXwxcBhqUXPG1JUSvoB5IivuFexTAkB0qoRoPIk0mHsfp6hDlPMXrBQjXku/4kJGvAy8b6Cl8lTY/I45DztLjkP2Zex2CGZCfZysClV1LR7AyH9FT8KLAkEAvxsN59kyXjRrbyRcMzSPrBcVFgLfmFyPQZKc8+BgRENtxPM8+WRLIMgMzVh3Sh175kKNKUDeacpzu1uiaHt6VA==
+-----END RSA PRIVATE KEY-----
+`
+	publicKey = `-----BEGIN PUBLIC KEY-----
+MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQCTnWuCTLNtDiqCt6fEfnLRUGT4zrPPgL1l8alZBcgdIC8ErtqxOZLFjVTYqxE8dqnkyBhW9pjv2WodAf9o0D5Em0Ysx2I8yurWBGmvpxLIaMaqqIPuKBYJSzJkv2wht5eXrUpCJBxn/0kFSBBLvvq/9NWWDniVA71NQaGPUal/DQIBAw==
+-----END PUBLIC KEY-----
+`
+	//私钥是用PKCS8来生成的
+	privateClientKey = `-----BEGIN PRIVATE KEY-----
+MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAI0sUcw92U5v59lbWrOBNj6kNNG1bFjLJ3eKrMjBpR7vZY6yDkH/qQciXLKqYZdF2slUrgHNKLEnoQOaQEFfVw0uyc2juzb4gDGl+P0TCIhLJzlzyWP83d7p/ehCpcp34i21FmjDTEE/2O6k5FfytxbKFm33iaxd0CtNGl0TvAHXAgEDAoGAF4di91+kN71RTuSPHereX8YIzZ48uXcxPpcczCBGL9KQ7R2tCv/xgTBkyHG67oukduNyVaIxctvwK0RgCuU5LJxM4phwr+YOUgfiv0qjEqzrj10YqQ4C5qc1JQPs/q1BhSJp8nY5AgrUtBvZWsyM1i+A9nDlZqpRAn2y6+LaXGMCQQDrkcn4n/clnCmnt84IWhtO6quWspPy2qYf4pirvAd2w019WQdD1IFbptYjIzMj7x4HXYEtUob5apB6CFzuJuNvAkEAmWq0GHcgbo4bzvCzStv87rcxroLZtfHQ3txxf1vK8ZXBaUGyuiGzozXf2qkEA3rzpbMmJNa9Zn+L4OB41Hb0GQJBAJ0L2/sVT25oG8UlNAWRZ4nxx7nMYqHnGWqXEHJ9Wk8s3lOQr4KNq5JvOWzCIhf0vq+Tq3OMWfucYFFa6J7El58CQGZHIrr6FZ8JZ99LIjHn/fR6IR8B5nlL4JSS9lTn3KEOgPDWdybBImzOlTxwrVenTRkiGW3kfkRVB+tAUI2korsCQQCbEQHa0XbFjA230nejo8y1umltCvtD1eeomzblXLSLPqwenqd380B1vkZEUaSDafmo248THmWOfDom6T/hmvvW
+-----END PRIVATE KEY-----`
+	publicClientKey = `-----BEGIN PUBLIC KEY-----
+MIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQCNLFHMPdlOb+fZW1qzgTY+pDTRtWxYyyd3iqzIwaUe72WOsg5B/6kHIlyyqmGXRdrJVK4BzSixJ6EDmkBBX1cNLsnNo7s2+IAxpfj9EwiISyc5c8lj/N3e6f3oQqXKd+IttRZow0xBP9jupORX8rcWyhZt94msXdArTRpdE7wB1wIBAw==
+-----END PUBLIC KEY-----`
+
+	privateServerKey = ``
+
+	publicServerKey = ``
+)
+
+const (
+	privateKeyPrefix = "WT RSA PRIVATE KEY "
+	publicKeyPrefix  = " WT  RSA PUBLIC KEY "
+)
+
+var PublicKey []byte
+var PrivateKey []byte
+
+var PrivateClientKey []byte
+var PublicClientKey []byte
+var PrivateServerKey []byte
+var PublicServerKey []byte
+
+func init() {
+	PublicKey = []byte(publicKey)
+	PrivateKey = []byte(privateKey)
+
+	PrivateClientKey = []byte(privateClientKey)
+	PublicClientKey = []byte(publicClientKey)
+	PrivateServerKey = []byte(privateServerKey)
+	PublicServerKey = []byte(publicServerKey)
+}
+
+func GetRSAKey(prefix string) error {
+	privateKey, err := rsa.GenerateKey(rand.Reader, 1024)
+	if err != nil {
+		return err
+	}
+
+	//客户端需要PKCS8格式的私钥
+	x509PrivateKey, err := Marsha1PKCS8PrivateKey(privateKey)
+	if err != nil {
+		return err
+	}
+	//x509PrivateKey := x509.MarshalPKCS1PrivateKey(privateKey)
+	privateFile, err := os.Create("./private" + prefix + ".pem")
+	if err != nil {
+		return err
+	}
+	defer privateFile.Close()
+	privateBlock := pem.Block{
+		Type:  privateKeyPrefix,
+		Bytes: x509PrivateKey,
+	}
+
+	if err = pem.Encode(privateFile, &privateBlock); err != nil {
+		return err
+	}
+
+	publicKey := privateKey.PublicKey
+	x509PublicKey, err := x509.MarshalPKIXPublicKey(&publicKey)
+	if err != nil {
+		panic(err)
+	}
+	publicFile, err := os.Create("./public" + prefix + ".pem")
+	if err != nil {
+		return err
+	}
+	defer publicFile.Close()
+	publicBlock := pem.Block{
+		Type:  publicKeyPrefix,
+		Bytes: x509PublicKey,
+	}
+	if err = pem.Encode(publicFile, &publicBlock); err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func RSAEncrypt(textStr, key []byte) (cryptText []byte, err error) {
+	block, _ := pem.Decode(key)
+
+	publicKeyInterface, err := x509.ParsePKIXPublicKey(block.Bytes)
+	if err != nil {
+		return nil, err
+	}
+	tmpPublicKey := publicKeyInterface.(*rsa.PublicKey)
+
+	tmpRetText, err := rsa.EncryptPKCS1v15(rand.Reader, tmpPublicKey, textStr)
+	if err != nil {
+		return nil, err
+	}
+
+	retText := base64.StdEncoding.EncodeToString(tmpRetText)
+
+	return []byte(retText), nil
+}
+
+func RSADecrypt(cryptText, key []byte) ([]byte, error) {
+	block, _ := pem.Decode(key)
+	tmpPrivateKey, err := x509.ParsePKCS8PrivateKey(block.Bytes)
+	if err != nil {
+		return nil, err
+	}
+
+	//block, _ := pem.Decode(key)
+	//tmpPrivateKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
+	//if err != nil {
+	//	return nil, err
+	//}
+	tmpCryptText, err := base64.StdEncoding.DecodeString(string(cryptText))
+	if err != nil {
+		return nil, err
+	}
+
+	retText, err := rsa.DecryptPKCS1v15(rand.Reader, tmpPrivateKey.(*rsa.PrivateKey), tmpCryptText)
+	if err != nil {
+		return nil, err
+	}
+	return retText, nil
+}
+
+type pkcs8Key struct {
+	Version             int
+	PrivateKeyAlgorithm []asn1.ObjectIdentifier
+	PrivateKey          []byte
+}
+
+func Marsha1PKCS8PrivateKey(key *rsa.PrivateKey) ([]byte, error) {
+	var pkey pkcs8Key
+	pkey.Version = 0
+	pkey.PrivateKeyAlgorithm = make([]asn1.ObjectIdentifier, 1)
+	pkey.PrivateKeyAlgorithm[0] = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 1}
+	pkey.PrivateKey = x509.MarshalPKCS1PrivateKey(key)
+
+	return asn1.Marshal(pkey)
+}

+ 140 - 0
RO_Server_Trunk-branch_0.1.39/rocommon/service/etcddesc.go

@@ -0,0 +1,140 @@
+package service
+
+import (
+	"encoding/json"
+	"errors"
+	"fmt"
+	"rocommon"
+	"strconv"
+	"strings"
+)
+
+type ETCDServiceDesc struct {
+	Name      string
+	ID        string
+	Host      string
+	Port      int
+	Tags      []string
+	Type      int
+	Zone      int
+	Index     int
+	RegTime   int64 //注册时的时间单位为m
+	LocalAddr string
+}
+
+func (this *ETCDServiceDesc) String() string {
+	data, err := json.Marshal(this)
+	if err != nil {
+		return ""
+	}
+	return string(data)
+}
+
+//字符串形式返回服务器ID 例如:server/zone/gate#type@zone@index -> gate#1@1@1
+func GenServiceID(prop rocommon.ServerNodeProperty) string {
+	return fmt.Sprintf("%s#%d@%d@%d",
+		prop.GetName(),
+		prop.GetZone(),
+		prop.ServerType(),
+		prop.GetIndex(),
+	)
+}
+func GenSelfServiceID(prop configServerNode) string {
+	return fmt.Sprintf("%s#%d@%d@%d",
+		serviceName,
+		prop.Zone,
+		prop.Type,
+		prop.Id,
+	)
+}
+
+func GenDiscoveryServicePrefix(sName string, zone int) string {
+	if zone > 0 {
+		return "server/" + sName + "#" + strconv.Itoa(zone)
+	} else {
+		return "server/" + sName + "#"
+	}
+}
+
+func GenServicePrefix(sName string, zone int) string {
+	return "server/" + sName
+	//return "server/" + strconv.Itoa(zone) + "/" + sName
+}
+func GenServiceZonePrefix(zone int) string {
+	return "server/" + strconv.Itoa(zone)
+}
+
+func GenService(sKey string) string {
+	keyList := strings.Split(sKey, "/")
+	if len(keyList) >= 2 {
+		return keyList[1]
+	}
+	return ""
+}
+func GenServiceStatePrefix(prop configServerNode) string {
+	id := fmt.Sprintf("%s#%d@%d@%d",
+		serviceName,
+		prop.Zone,
+		prop.Type,
+		prop.Id,
+	)
+	return "serverstate/" + id
+}
+
+func str2Num(str string) (int, error) {
+	num, e := strconv.ParseInt(str, 10, 32)
+	if e != nil {
+		return 0, errors.New("serviceId invalid num convert error:" + str)
+	} else {
+		return int(num), nil
+	}
+}
+
+func ParseServiceID(sid string) (serverType, zone, index int, err error) {
+	str := strings.Split(sid, "#")
+	if len(str) < 2 {
+		err = errors.New("serviceId invalid:" + sid)
+		return
+	} else {
+		//serviceName := str[0]
+		strProp := strings.Split(str[1], "@")
+		if len(strProp) < 3 {
+			err = errors.New("serviceId invalid:" + sid)
+			return
+		} else {
+			zone, err = str2Num(strProp[0])
+			if err != nil {
+				return
+			}
+			serverType, err = str2Num(strProp[1])
+			if err != nil {
+				return
+			}
+			index, err = str2Num(strProp[2])
+			if err != nil {
+				return
+			}
+		}
+	}
+	return
+}
+
+type CrossMapServerStateInfoDesc struct {
+	LineNum int32 //线路编号
+	Num     int32 //线路人数
+}
+type ETCDServiceState struct {
+	ID          int
+	SID         string
+	MaxLineNum  int32 //每个服务器线路最大数量
+	StateList   []CrossMapServerStateInfoDesc
+	SpaceMaxNum int32 //每个线路最大在线人数
+}
+
+func (this ETCDServiceState) String() string {
+	data, err := json.Marshal(this)
+	if err != nil {
+		return ""
+	}
+	return string(data)
+}

+ 433 - 0
RO_Server_Trunk-branch_0.1.39/rocommon/service/etcdreg.go

@@ -0,0 +1,433 @@
+package service
+
+import (
+	"context"
+	"encoding/json"
+	"fmt"
+	"github.com/coreos/etcd/clientv3"
+	"github.com/coreos/etcd/mvcc/mvccpb"
+	"log"
+	"net"
+	"rocommon"
+	"rocommon/util"
+	"strconv"
+	"strings"
+	"sync/atomic"
+	"time"
+)
+
+//第一次服务器启动时间
+var ServiceStartupTime uint64 = 0
+
+//注册到服务器发现
+func ETCDRegister(node rocommon.ServerNode, opts ...interface{}) *ETCDServiceDesc {
+	property := node.(rocommon.ServerNodeProperty)
+	sd := &ETCDServiceDesc{
+		ID:    GenServiceID(property),
+		Name:  property.GetName(),
+		Host:  property.GetAddr(),
+		Type:  property.ServerType(),
+		Zone:  property.GetZone(),
+		Index: property.GetIndex(),
+	}
+	sd.RegTime = util.GetTimeSeconds()
+	//服务器节点信息
+	node.(rocommon.ContextSet).SetContextData("sid", sd, "ETCDRegister")
+
+	//获取本地IPv4
+	addrs, err := net.InterfaceAddrs()
+	if err == nil {
+		for _, addr := range addrs {
+			if ipnet, ok := addr.(*net.IPNet); ok && !ipnet.IP.IsLoopback() {
+				if ipnet.IP.To4() != nil {
+					sd.LocalAddr = ipnet.IP.String()
+					break
+				}
+			}
+		}
+	}
+	if sd.LocalAddr != "" {
+		hostList := strings.Split(sd.Host, ":")
+		if hostList[0] == "0.0.0.0" {
+			sd.Host = sd.LocalAddr + ":" + hostList[1]
+		}
+	}
+
+	//先查询是否存在相同的该节点,如果存在不做处理(或者通过del操作关闭其他客户端)
+	etcdKey := GenServicePrefix(sd.ID, property.GetZone())
+	rsp, err := etcdDiscovery.EtcdKV.Get(context.TODO(), etcdKey)
+	if err != nil {
+		util.PanicF("etcd discovery get err:%v\n", err)
+		//log.Fatalf("etcd discovery get err:%v\n", err)
+	} else {
+		if rsp.Count > 0 {
+			util.PanicF("current node has been register to etcd:%v\n", etcdKey)
+			//log.Fatalf("current node has been register to etcd", sd.ID)
+		} else {
+			etcdDiscovery.RegisterWithTimeOut(etcdKey, sd.String())
+			etcdDiscovery.WatchSelf(etcdKey, *sd)
+		}
+	}
+	//cross etcd
+	if crossEtcdDiscovery != nil {
+		//先查询是否存在相同的该节点,如果存在不做处理(或者通过del操作关闭其他客户端)
+		etcdKey := GenServicePrefix(sd.ID, property.GetZone())
+		rsp, err := crossEtcdDiscovery.EtcdKV.Get(context.TODO(), etcdKey)
+		if err != nil {
+			util.PanicF("etcd discovery get err:%v\n", err)
+		} else {
+			if rsp.Count > 0 {
+				util.PanicF("current node has been register to etcd:%v\n", etcdKey)
+			} else {
+				crossEtcdDiscovery.RegisterWithTimeOut(etcdKey, sd.String())
+				crossEtcdDiscovery.WatchSelf(etcdKey, *sd)
+			}
+		}
+	}
+
+	//添加服务器开服时间(server/zone)
+	InitServiceStartupTime(property.GetZone())
+
+	return sd
+}
+
+func InitServiceStartupTime(zone int) {
+	//添加服务器开服时间(server/zone)
+	startupKey := GenServiceZonePrefix(zone)
+	rsp1, err1 := etcdDiscovery.EtcdKV.Get(context.TODO(), startupKey)
+	if err1 != nil {
+		util.PanicF("etcd discovery get err:%v\n", err1)
+	} else {
+		if rsp1.Count > 0 {
+			//已经注册了服务器启动时间
+			tmpTime, _ := strconv.ParseUint(string(rsp1.Kvs[0].Value), 10, 64)
+			atomic.StoreUint64(&ServiceStartupTime, tmpTime)
+		} else {
+			nowTime := util.GetCurrentTime()
+			atomic.StoreUint64(&ServiceStartupTime, nowTime)
+			val := strconv.FormatUint(nowTime, 10)
+			etcdDiscovery.Register(startupKey, val)
+		}
+		tmpTime := GetServiceStartupTime()
+		tmpTime1 := time.Unix(int64(tmpTime/1000), 0).In(util.GetLoc())
+		util.InfoF("Service StartupTime %v| %v", tmpTime, tmpTime1)
+	}
+}
+
+//return ms
+func GetServiceStartupTime() uint64 {
+	return atomic.LoadUint64(&ServiceStartupTime)
+}
+
+//todo..解除注册
+func ETCDUnregister(node rocommon.ServerNode) {
+	property := node.(rocommon.ServerNodeProperty)
+	sd := &ETCDServiceDesc{
+		ID:    GenServiceID(property),
+		Name:  property.GetName(),
+		Host:  property.GetAddr(),
+		Type:  property.ServerType(),
+		Zone:  property.GetZone(),
+		Index: property.GetIndex(),
+	}
+	sd.RegTime = util.GetTimeSeconds()
+	etcdKey := GenServicePrefix(sd.ID, property.GetZone())
+
+	util.InfoF("ETCDUnregister =%v", etcdKey)
+	etcdDiscovery.Del(etcdKey)
+	if crossEtcdDiscovery != nil {
+		crossEtcdDiscovery.Del(etcdKey)
+	}
+}
+
+//发现服务器,服务可能有多个地址,例如需要连接多个game
+//todo...返回多个servernode结构体
+func DiscoveryService(serviceName string, serviceZone int, nodeCreator func(MultiServerNode, *ETCDServiceDesc)) rocommon.ServerNode {
+	//如果已经存在的,就停止之前正在运行的节点(注意不要配置成一样的节点信息,否则会关闭之前的连接)
+	multiNode := NewMultiServerNode() //nodereg.go
+
+	//连接同一个zone里的服务器节点
+	etcdKey := GenDiscoveryServicePrefix(serviceName, serviceZone)
+	/*
+		rsp, err := etcdDiscovery.EtcdKV.Get(context.TODO(),etcdKey, clientv3.WithPrefix())
+		if err != nil {
+			util.FatalF("etcd discovery get err:%v", err)
+			//log.Fatalf("etcd discovery get err:%v\n", err)
+		}
+
+		logutil.InfoF("service[%v] node find count:%v", etcdKey, rsp.Count)
+		//log.Printf("service[%v] node find count:%v\n", serviceName, rsp.Count)
+		for _,data := range rsp.Kvs {
+			util.InfoF("etcd discovery start connect:%v", string(data.Key))
+			//需要判断节点是否已经存在
+			var sd ETCDServiceDesc
+			err := json.Unmarshal(data.Value, &sd)
+			if err != nil {
+				util.InfoF("etcd discovery kv[%v][value]err:%v",data.Key, err)
+				continue
+			}
+			//先停止之前的连接,再执行新的连接
+			if preNode := multiNode.GetNode(sd.ID); preNode != nil {
+				multiNode.RemoveNode(sd.ID)
+				preNode.Stop()
+			}
+			nodeCreator(multiNode, &sd)
+		}
+	*/
+
+	//会收到key 对应的最近一次变化通知,
+	var ch clientv3.WatchChan
+	ch = etcdDiscovery.EtcdCli.Watch(context.TODO(), etcdKey, clientv3.WithPrefix())
+	//watch操作
+	go func() {
+		//查找已经存在的节点
+		rsp, err := etcdDiscovery.EtcdKV.Get(context.TODO(), etcdKey, clientv3.WithPrefix())
+		if err != nil {
+			util.FatalF("etcd discovery get err:%v", err)
+			//log.Fatalf("etcd discovery get err:%v\n", err)
+		}
+		util.InfoF("service[%v] node find count:%v", etcdKey, rsp.Count)
+		for _, data := range rsp.Kvs {
+			util.InfoF("etcd discovery start connect:%v", string(data.Key))
+			//需要判断节点是否已经存在
+			var sd ETCDServiceDesc
+			err := json.Unmarshal(data.Value, &sd)
+			if err != nil {
+				util.InfoF("etcd discovery kv[%v][value]err:%v", data.Key, err)
+				continue
+			}
+			//先停止之前的连接,再执行新的连接
+			if preNode := multiNode.GetNode(sd.ID); preNode != nil {
+				multiNode.RemoveNode(sd.ID)
+				preNode.Stop()
+			}
+			nodeCreator(multiNode, &sd)
+		}
+
+		for {
+			select {
+			case c := <-ch:
+				//log.Println("etcd discovery watch count:",len(c.Events))
+				//todo...处理删除kv操作
+				for _, ev := range c.Events {
+					switch ev.Type {
+					case mvccpb.PUT:
+						var sd ETCDServiceDesc
+						err := json.Unmarshal(ev.Kv.Value, &sd)
+						if err != nil {
+							util.InfoF("err:etcd discovery kv[%v][value]err:%v", string(ev.Kv.Key), err)
+							continue
+						}
+
+						util.InfoF("etcd discovery watch put key=%v", string(ev.Kv.Key))
+						//log.Println("etcd discovery watch put key:",string(ev.Kv.Key))
+						//先停止之前的连接,再执行新的连接
+						if preNode := multiNode.GetNode(sd.ID); preNode != nil {
+							//todo...
+							//暂时先处理成,如果存在节点则返回(保证节点ip和端口不变的情况下,否则需要启用移除老连接启用新连接)
+							util.InfoF("etcd discovery watch put find oldkey:%v %v", string(ev.Kv.Key), sd.ID)
+							//continue
+							//调试模式下使用已经存在的节点
+							if DebugMode {
+								util.InfoF("etcd discovery DebugMode=%v", DebugMode)
+								continue
+							}
+
+							var preDesc *ETCDServiceDesc
+							preNode.(rocommon.ContextSet).RawContextData("sid", &preDesc)
+							if preDesc.RegTime == sd.RegTime {
+								continue
+							}
+							multiNode.RemoveNode(sd.ID)
+							//todo...通过etcd处理,如果相同的键值还存在则服务器启动时会失败,所以这边暂时不做停止处理
+							// 后续解决重连时需要注意
+							// 重连产生的问题,重连上来后再断开后stop中的wait才能继续,然后再调用nodeCreator函数,导致每次
+							// 关闭对端的节点后才进行连接,因为主动调用stop时,重连上了,导致stop会一直在wait状态,导致执行
+							// 不到nodeCreator,关闭对端后,stop中的wait被解除(断开连接导致解除),然后执行nodeCreator
+							// 但是因为此时对端已经关闭,所以导致开始时想要连接的反而连接不上,处于重连状态
+							// 需要context来主动断开所有协程
+							preNode.Stop()
+							util.InfoF("remove old node:%v time:%v %v", sd.ID, preDesc.RegTime, util.GetTimeByUint32(uint32(preDesc.RegTime)).String())
+							//log.Println("remove node:", sd.ID)
+						}
+						//util.InfoF("etcd discovery watch put k1111ey:%v", string(ev.Kv.Key))
+						nodeCreator(multiNode, &sd)
+
+					case mvccpb.DELETE:
+						//注意:social关注本区中的其他social节点,所以自己的节点删除这边会通知,其他节点不会
+						util.InfoF("etcd discovery watch delete key:%v", string(ev.Kv.Key))
+						//log.Println("etcd discovery watch delete key:", string(ev.Kv.Key))
+
+						nodeID := GenService(string(ev.Kv.Key))
+						//log.Println("pre delete:", nodeID)
+						//先停止之前的连接,再执行新的连接
+						if preNode := multiNode.GetNode(nodeID); preNode != nil {
+							//不移除可以触发断线重连,否则,这边直接把节点关闭无法触发断线重连
+							//避免这边移除后导致etcd无法成功注册的话还能重连成功
+							//multiNode.RemoveNode(nodeID)
+							//preNode.Stop()
+							util.InfoF("delete node:%v", nodeID)
+						}
+					}
+				}
+			}
+		}
+	}()
+
+	return nil
+}
+
+///////////////////////////////////////////
+type ServiceDiscovery struct {
+	etcdConfig clientv3.Config
+	EtcdCli    *clientv3.Client //clientv3.New(conf)
+	EtcdKV     clientv3.KV
+}
+
+func NewNetServiceDiscovery(addr string) (*ServiceDiscovery, error) {
+	sd := &ServiceDiscovery{}
+	epsStr := fmt.Sprintf("http://%s", addr)
+	sd.etcdConfig = clientv3.Config{
+		Endpoints:   []string{epsStr},
+		DialTimeout: 3 * time.Second,
+	}
+	cli, err := clientv3.New(sd.etcdConfig)
+	if err != nil {
+		return nil, err
+	} else {
+		sd.EtcdCli = cli
+		sd.EtcdKV = clientv3.NewKV(sd.EtcdCli)
+		return sd, nil
+	}
+}
+
+func (this *ServiceDiscovery) Close() {
+	this.EtcdCli.Close()
+}
+
+func (this *ServiceDiscovery) RegisterWithTimeOut(key string, value string) int64 {
+	//获得lease数据
+	leaseRsp, err := this.EtcdCli.Grant(context.TODO(), 3)
+	if err != nil {
+		util.PanicF("etcd grant falied=%v", err)
+		//log.Fatalf("etcd grant falied:%v\n", err)
+		return 0
+	}
+	ctx, cancel := context.WithTimeout(context.TODO(), 3*time.Second)
+	defer cancel()
+	rsp, err := this.EtcdKV.Put(ctx, key, value, clientv3.WithLease(leaseRsp.ID))
+	if err != nil {
+		//util.PanicF("etcd put key failed=%v\n", err)
+		util.FatalF("etcd put key failed:%v\n", err)
+		return 0
+	} else {
+		util.InfoF("etcd register ok key=%v clusterid=%v leaseid=%v etcdaddr=%v", key, rsp.Header.ClusterId, leaseRsp.ID, this.etcdConfig.Endpoints)
+		//log.Printf("etcd register server:%v clusterid:%v", key, rsp.Header.ClusterId)
+	}
+	_, err = this.EtcdCli.KeepAlive(context.TODO(), leaseRsp.ID)
+	if err != nil {
+		util.PanicF("etcd put key failed=%v\n", err)
+	}
+	return int64(leaseRsp.ID)
+}
+
+//watch自己,网络恢复后得到自己被删除的通知,重新设置key租约
+//WatchSelf只重新设置lease,不做其他操作(key只是自己)
+func (this *ServiceDiscovery) WatchSelf(key string, value ETCDServiceDesc) {
+	//调试模式下不生效
+	if DebugMode {
+		util.InfoF("DebugMode=%v WatchSelf Invalid", DebugMode)
+		return
+	}
+	//watch自己,网络恢复后得到自己被删除的通知,重新设置key租约
+	keepaliveWatch := this.EtcdCli.Watch(context.TODO(), key)
+	go func() {
+		for {
+			select {
+			case c := <-keepaliveWatch:
+				for _, ev := range c.Events {
+					switch ev.Type {
+					case mvccpb.DELETE:
+						util.InfoF("etcd WatchSelf del-self key=%v etcdaddr=%v", key, this.etcdConfig.Endpoints)
+						value.RegTime = util.GetTimeSeconds()
+						this.RegisterWithTimeOut(key, value.String())
+					}
+				}
+			}
+		}
+	}()
+}
+
+func (this *ServiceDiscovery) WatchKey(key string) {
+	keepaliveWatch := this.EtcdCli.Watch(context.TODO(), key)
+	go func() {
+		for {
+			select {
+			case c := <-keepaliveWatch:
+				for _, ev := range c.Events {
+					switch ev.Type {
+					case mvccpb.DELETE:
+						util.InfoF("etcd WatchKey del key=%v etcdaddr=%v", key, this.etcdConfig.Endpoints)
+					}
+				}
+			}
+		}
+	}()
+}
+
+func (this *ServiceDiscovery) Del(key string) bool {
+	_, err := this.EtcdCli.Delete(context.TODO(), key)
+	if err != nil {
+		util.FatalF("etcd del key failed:%v", key)
+		return false
+	}
+	return true
+}
+
+func (this *ServiceDiscovery) Register(key string, value string) {
+	rsp, err := this.EtcdKV.Put(context.TODO(), key, value)
+	if err != nil {
+		util.PanicF("etcd put key failed:%v\n", err)
+		//log.Fatalf("etcd put key failed:%v\n", err)
+		return
+	} else {
+		util.InfoF("etcd register server:%v clusterid:%v", key, rsp.Header.ClusterId)
+		log.Printf("etcd register server:%v clusterid:%v", key, rsp.Header.ClusterId)
+	}
+}
+
+//上报自己服务器当前的状态,供其它进程获取(例如获取当前地图线路情况)
+//leaseId < 0 表示不带lease的key更新
+func (this *ServiceDiscovery) UpdateStateToETCD(key, val string, leaseId int64) int64 {
+	ctx, cancel := context.WithTimeout(context.TODO(), 3*time.Second)
+	defer cancel()
+
+	if leaseId >= 0 {
+		if clientv3.LeaseID(leaseId) == clientv3.NoLease {
+			leaseId = this.RegisterWithTimeOut(key, val)
+			util.InfoF("UpdateStateToETCD first key=%v leaseid=%v", key, leaseId)
+			return leaseId
+		}
+
+		//查看lease是否过期
+		_, err := this.EtcdKV.Put(ctx, key, val, clientv3.WithLease(clientv3.LeaseID(leaseId)))
+		if err != nil {
+			util.FatalF("UpdateStateToETCD etcd update key failed:%v\n", err)
+			//重新申请lease并注册
+			leaseId = this.RegisterWithTimeOut(key, val)
+		} else {
+			//util.InfoF("UpdateStateToETCD etcd update ok key=%v clusterid=%v leaseId=%v etcdaddr=%v", key, rsp.Header.ClusterId, leaseId, this.etcdConfig.Endpoints)
+			//log.Printf("etcd register server:%v clusterid:%v", key, rsp.Header.ClusterId)
+		}
+	} else {
+		_, err := this.EtcdKV.Put(ctx, key, val)
+		if err != nil {
+			util.FatalF("UpdateStateToETCD etcd update key failed:%v\n", err)
+		} else {
+			//util.InfoF("UpdateStateToETCD etcd update ok key=%v clusterid=%v etcdaddr=%v", key, rsp.Header.ClusterId, this.etcdConfig.Endpoints)
+			//log.Printf("etcd register server:%v clusterid:%v", key, rsp.Header.ClusterId)
+		}
+	}
+
+	return leaseId
+}

+ 183 - 0
RO_Server_Trunk-branch_0.1.39/rocommon/service/eventqueue.go

@@ -0,0 +1,183 @@
+package service
+
+import (
+	"rocommon"
+	"rocommon/util"
+	"runtime/debug"
+	"sync"
+	"time"
+)
+
+////事件处理队列
+//type NetEventQueue interface {
+//	StartQueue() NetEventQueue
+//
+//	StopQueue() NetEventQueue
+//
+//	Wait()
+//
+//	PostCb(callback func())
+//
+//	AttachUpdateModule(update rocommon.UpdateModule)
+//}
+
+//通用UpdateModule处理
+type CommonUpdateModule struct {
+}
+
+func (this *CommonUpdateModule) Init()            {}
+func (this *CommonUpdateModule) Update(ms uint64) {}
+
+func NewEventQueue() rocommon.NetEventQueue {
+	que := &eventQueue{
+		onError: func(data interface{}) {
+			util.InfoF("onError data:%v \n%s\n", data, string(debug.Stack()))
+			//打印堆栈信息
+			debug.PrintStack()
+		},
+	}
+	//todo...
+	//事件列表暂时容量为20000
+	que.queList = make(chan interface{}, 20000)
+	que.updateModule = &CommonUpdateModule{}
+	return que
+}
+
+//eventQueue
+type eventQueue struct {
+	wg           sync.WaitGroup
+	queList      chan interface{}  //目前用channel来代替 todo...
+	onError      func(interface{}) //打印奔溃处理
+	updateModule rocommon.UpdateModule
+}
+
+func (this *eventQueue) AttachUpdateModule(update rocommon.UpdateModule) {
+	//if this.updateModule != nil {
+	//	util.PanicF("update module has been attached !!!")
+	//}
+	if update != nil {
+		update.Init()
+		this.updateModule = update
+		util.InfoF("update module attached success")
+	}
+}
+
+var procNum int = 0
+var procNumTime time.Time
+var callbackNum int = 0
+var callbackTime time.Duration
+
+//处理回调队列主循环
+func (this *eventQueue) StartQueue() rocommon.NetEventQueue {
+	this.wg.Add(1)
+	//游戏服务器只有一个协程,机器人测试时会有DATE RACE
+	//procNumTime = util.GetCurrentTimeNow()
+
+	go func() {
+		//log.Println("StartQueue goroutine")
+		delayTimer := time.NewTimer(5 * time.Millisecond)
+		for {
+			delayTimer.Reset(5 * time.Millisecond)
+			startUpTime := GetServiceStartupTime()
+			if startUpTime > 0 {
+				break
+			}
+			select {
+			case <-delayTimer.C:
+			}
+		}
+		//默认执行一次更新操作
+		this.updateModule.Update(util.GetCurrentTime())
+
+		nowTime1 := util.GetTimeMilliseconds()
+		updateDelayTimer := time.NewTicker(5 * time.Millisecond)
+	loop:
+		for {
+			//nowTime1 := util.GetTimeMilliseconds()
+			//delayTimer.Reset(5 * time.Millisecond)
+			exit := false
+			select {
+			case msg := <-this.queList:
+				switch t := msg.(type) {
+				case func():
+					//procNum++
+					this.queueCall(t)
+				case nil:
+					exit = true
+					break loop //break //退出事件主循环
+					//break //退出事件主循环
+				}
+			//case <-delayTimer.C:
+			case <-updateDelayTimer.C:
+			}
+
+			//这边添加阶段判断,避免eventqueue中频繁的Update操作
+			nowTime2 := util.GetTimeMilliseconds()
+			if nowTime1+10 <= nowTime2 { //10ms
+				nowTime1 = nowTime2
+				this.updateModule.Update(nowTime2)
+			}
+
+			//1秒内处理的协议数量
+			//this.AddProcNum(time.Now())
+			//定时器update操作
+			//callbackNum++
+			//callbackTime += time.Now().Sub(now) //一个tick执行的消耗时间
+
+			//nowTime := util.GetTimeMilliseconds()
+			//delTime1 := nowTime2 - nowTime1
+			//delTime2 := nowTime - nowTime1
+			//if len(this.queList) > 100 {
+			//	util.DebugF("StartQueue deltime1=%v deltime2=%v quelen=%v", delTime1, delTime2, len(this.queList))
+			//}
+
+			if exit {
+				break
+			}
+		}
+
+		this.wg.Done()
+		//util.InfoF("Exit Queue goroutine")
+	}()
+	return this
+}
+
+func (this *eventQueue) AddProcNum(nowTime time.Time) {
+	if nowTime.Sub(procNumTime) > 1*time.Second {
+		if callbackNum > 50 && procNum > 0 {
+			util.InfoF("[1s] t=%v procNum=%v quelen=%v callbackNum=%v", nowTime.Sub(procNumTime), procNum,
+				len(this.queList), callbackNum)
+		}
+		procNum = 0
+		procNumTime = nowTime
+		callbackTime = 0
+		callbackNum = 0
+	}
+}
+
+func (this *eventQueue) StopQueue() rocommon.NetEventQueue {
+	this.queList <- nil
+	return this
+}
+
+func (this *eventQueue) Wait() {
+	this.wg.Wait()
+}
+
+func (this *eventQueue) PostCb(cb func()) {
+	if cb != nil {
+		this.queList <- cb
+	}
+}
+
+func (this *eventQueue) queueCall(cb func()) {
+	//todo...
+	defer func() {
+		//打印奔溃信息
+		if err := recover(); err != nil {
+			this.onError(err)
+		}
+	}()
+
+	cb()
+}

+ 24 - 0
RO_Server_Trunk-branch_0.1.39/rocommon/service/flag.go

@@ -0,0 +1,24 @@
+package service
+
+import (
+	"flag"
+	"os"
+)
+
+var (
+	ServerCmd = flag.NewFlagSet(os.Args[0], flag.ExitOnError)
+
+	//服务器启动配置文件
+	flagServerConfigPath = ServerCmd.String("config", "config.yaml", "server config")
+	flagServerName       = ServerCmd.String("server", "", "server name")
+	FlagServerList       = ServerCmd.String("serverlist", "serverlist.yaml", "serverlist.yaml")
+
+	//临时参数使用
+	TempParam         = ServerCmd.String("diff", "abc", "Temp param")
+	DBIndexParam      = ServerCmd.Int("db", 0, "DBIndexParam")
+	ZoneParam         = ServerCmd.String("zone", "8", "ZoneParam")
+	MaxOnlineNumParam = ServerCmd.Int("num", 0, "max online num")
+	TestTypeParam     = ServerCmd.Int("t", 1, "test type 1登录压测 2功能压测")
+	IPParam           = ServerCmd.String("ip", "127.0.0.1:21001", "test type 1登录压测 2功能压测")
+	TypeParam         = ServerCmd.String("type", "", "操作类型")
+)

+ 264 - 0
RO_Server_Trunk-branch_0.1.39/rocommon/service/init.go

@@ -0,0 +1,264 @@
+package service
+
+import (
+	"fmt"
+	"io/ioutil"
+	"log"
+	"math/rand"
+	"os"
+	"os/signal"
+	"rocommon/socket"
+	"rocommon/socket/mysql"
+	"rocommon/util"
+	"strconv"
+	"strings"
+	"syscall"
+
+	"github.com/olivere/elastic/v7"
+	"github.com/olivere/elastic/v7/config"
+	"gopkg.in/yaml.v2"
+)
+
+var (
+	serviceName        string //gate game
+	serviceConfig      ConfigServerNode
+	etcdDiscovery      *ServiceDiscovery //etcd服务器发现
+	crossEtcdDiscovery *ServiceDiscovery //跨服etcd服务器发现
+	redisConnector     RedisConnector    //用来db连接redis使用
+	elasticConnector   *elastic.Client   //elastic
+	mysqlConnector     *mysql.MysqlConnector
+	mysqlOrmConnector  *mysql.MysqlOrmConnector
+
+	//调试标记(调试模式下设置成true,不会触发重连)
+	//默认为非调试模式
+	DebugMode = false
+)
+
+func Init(name string) {
+	rand.Seed(int64(util.GetTimeMilliseconds()))
+	serviceName = name
+	err := ServerCmd.Parse(os.Args[1:])
+	if err != nil {
+		log.Printf("ServerCmd.Parse failed!!!")
+		panic(err)
+	}
+
+	//命令行解析 / yaml配置文件解析 :start game.exe -config game_config.yaml -server game1
+	initServerConfig(*flagServerConfigPath, *flagServerName)
+	serviceConfig.ServerStartTime = util.GetTimeMilliseconds()
+
+	//日志初始化
+	err = util.InitLog(serviceConfig.Node.LogLevel, serviceConfig.Node.LogMaxSize,
+		serviceConfig.Node.Logfile, serviceName+strconv.Itoa(serviceConfig.Node.Id)+"_",
+		serviceConfig.Node.UniLogFile)
+	if err != nil {
+		log.Printf("InitLog failed!!! err=%v", err)
+		panic(err)
+	}
+
+	//etcd
+	if etcdDiscovery == nil && serviceConfig.Node.EtcdAddr != "" {
+		sd, err := NewNetServiceDiscovery(serviceConfig.Node.EtcdAddr)
+		if err != nil {
+			util.PanicF("Service Discovery start err:%v addr:%v", err, serviceConfig.Node.EtcdAddr)
+		} else {
+			etcdDiscovery = sd
+			util.InfoF("service discovery start success")
+		}
+	}
+	//cross etcd
+	if crossEtcdDiscovery == nil && serviceConfig.Node.CrossEtcdAddr != "" &&
+		serviceConfig.Node.CrossEtcdAddr != serviceConfig.Node.EtcdAddr {
+		sd, err := NewNetServiceDiscovery(serviceConfig.Node.CrossEtcdAddr)
+		if err != nil {
+			util.PanicF("Service CrossDiscovery start err:%v addr:%v", err, serviceConfig.Node.CrossEtcdAddr)
+		} else {
+			crossEtcdDiscovery = sd
+			util.InfoF("service CrossDiscovery start success")
+		}
+	}
+
+	//是否需要连接redis数据库
+	if len(serviceConfig.Redis.RedisAddr) > 0 {
+		redisConnector = NewNetRedisConnector(serviceConfig.Redis.RedisAddr,
+			serviceConfig.Redis.Password,
+			serviceConfig.Redis.DBIndex,
+			serviceConfig.Redis.RedisCluster)
+		redisConnector.SetName(serviceName)
+		_, err := redisConnector.RedisCli().Ping().Result()
+		if err != nil {
+			util.PanicF("New RedisConnector ping failed er=%v", err)
+		}
+		util.InfoF("redisconnector success...")
+	}
+	//mysql
+	if serviceConfig.Redis.MysqlAddr != "" {
+		mysqlConnector = socket.NewServerNode("mysqlConnector", name,
+			serviceConfig.Redis.MysqlAddr, nil).(*mysql.MysqlConnector)
+		mysqlConnector.Start()
+		if mysqlConnector.IsReady() {
+			util.InfoF("mysqlConnector connect success...")
+		} else {
+			util.PanicF("mysqlConnector connect failed...")
+		}
+
+		mysqlOrmConnector = socket.NewServerNode("MysqlOrmConnector", name,
+			serviceConfig.Redis.MysqlAddr, nil).(*mysql.MysqlOrmConnector)
+		mysqlOrmConnector.Start()
+		if mysqlOrmConnector.IsReady() {
+			util.InfoF("mysqlOrmConnector connect success...")
+		} else {
+			util.PanicF("mysqlOrmConnector connect failed...")
+		}
+
+		//
+		//mysqlConnector.Operate(func(rawClient interface{}) interface{} {
+		//	client := rawClient.(*sql.DB)
+		//	retQuery := mysql.NewWrapper(client).Query("select User from user")
+		//
+		//	retQuery.Each(func(wrapper *mysql.Wrapper) bool {
+		//		var name string
+		//		err := wrapper.Scan(&name)
+		//		util.InfoF("scan=%v err=%v", name, err)
+		//		return true
+		//	})
+		//
+		//	return nil
+		//})
+	}
+
+	//是否需要连接elasticsearch
+	//http://www.wtgame.cn:9200/_nodes/http?pretty
+	if serviceConfig.Elastic.Url != "" {
+		var err error = nil
+		bSniff := false
+		elasticConnector, err = elastic.NewClientFromConfig(&config.Config{
+			URL:   serviceConfig.Elastic.Url,
+			Index: serviceConfig.Elastic.Index,
+			Sniff: &bSniff,
+		})
+		if err != nil {
+			util.ErrorF("New elasticConnector err=%v...", err)
+		}
+		util.InfoF("New ElasticConnector...")
+	}
+}
+
+func WaitExitSignal() {
+	log.Printf("wait for exit signal[SIGTERM SIGINT SIGQUIT SIGKILL]")
+	util.InfoF("wait for exit signal[SIGTERM SIGINT SIGQUIT SIGKILL]")
+	ch := make(chan os.Signal, 1)
+	signal.Notify(ch, syscall.SIGTERM, syscall.SIGINT, syscall.SIGQUIT, syscall.SIGKILL)
+
+	<-ch
+
+	if GetMysql() != nil {
+		GetMysql().Stop()
+	}
+	if GetMysqlORM() != nil {
+		GetMysqlORM().Stop()
+	}
+}
+
+func GetServiceName() string {
+	return serviceName
+}
+
+//server/gate#type@zone@index -> gate#1@1@1
+func GetLocalServiceID() string {
+	//gate#id@zone@type
+	return fmt.Sprintf("%s#%d@%d@%d", serviceName,
+		serviceConfig.Node.Zone, serviceConfig.Node.Type, serviceConfig.Node.Id)
+}
+
+func initServerConfig(configPath, serverName string) {
+	if configPath == "" {
+		return
+	}
+
+	yamlFile, err := ioutil.ReadFile(configPath)
+	if err != nil {
+		log.Fatalf("load config [%v] err:%v\n", configPath, err)
+	}
+	//err = yaml.Unmarshal(yamlFile, &serviceConfig)
+
+	//tmpaa := ConfigServerNode{}
+	//ab := ConfigServerNode{
+	//	Node: configServerNode{
+	//		NodeName: "gate1",
+	//		Addr:     "12312313",
+	//		Type:     1,
+	//		Id:       1,
+	//		Zone:     1,
+	//	},
+	//	Acceptor: configServerAcceptor{
+	//		Addr: "123123",
+	//	},
+	//	Redis: configServerDB{
+	//		RedisAddr: "1231232",
+	//		Password:  "123",
+	//	},
+	//}
+	//tmpaa.Server = append(tmpaa.Server, ab)
+	//tmpaa.Server = append(tmpaa.Server, ab)
+	//tt, _ := yaml.Marshal(tmpaa)
+	//log.Printf("aa=%v", string(tt))
+
+	serviceConfigList := ServerNode{}
+	err = yaml.Unmarshal(yamlFile, &serviceConfigList)
+	if err != nil {
+		log.Fatalf("unmarshal [%v] err:%v\n", configPath, err)
+	}
+
+	if serverName == "" {
+		strList := strings.Split(configPath, "/")
+		if len(strList) > 0 {
+			strList1 := strings.Split(strList[len(strList)-1], "_")
+			if len(strList1) > 0 {
+				serverName = strList1[0]
+				if serverName == "" {
+					log.Panicf("servername invalid path=%v servername=%v", configPath, serverName)
+				}
+			}
+		}
+
+	}
+	bFind := false
+	for idx := 0; idx < len(serviceConfigList.Server); idx++ {
+		if serviceConfigList.Server[idx].Node.NodeName == serverName {
+			serviceConfig = serviceConfigList.Server[idx]
+			bFind = true
+			break
+		}
+	}
+	if !bFind {
+		log.Panicf("servername yaml not find path=%v servername=%v", configPath, serverName)
+	}
+	log.Println("Server yaml config load success:", configPath, serverName)
+}
+
+//返回服务器配置文件
+func GetServiceConfig() ConfigServerNode {
+	return serviceConfig
+}
+
+func GetServiceDiscovery() *ServiceDiscovery {
+	return etcdDiscovery
+}
+
+func GetRedis() BaseCmdable {
+	return redisConnector.RedisCli()
+}
+func SetRedis(cli RedisConnector) {
+	redisConnector = cli
+}
+
+func GetElastic() *elastic.Client {
+	return elasticConnector
+}
+func GetMysql() *mysql.MysqlConnector {
+	return mysqlConnector
+}
+func GetMysqlORM() *mysql.MysqlOrmConnector {
+	return mysqlOrmConnector
+}

+ 45 - 0
RO_Server_Trunk-branch_0.1.39/rocommon/service/multinode.go

@@ -0,0 +1,45 @@
+package service
+
+import (
+	"rocommon"
+	"sync"
+)
+
+type MultiServerNode interface {
+	GetNode(serviceId string) rocommon.ServerNode
+	//添加服务器节点 tcpConnector成功后的节点
+	AddNode(desc *ETCDServiceDesc, node rocommon.ServerNode)
+	RemoveNode(serviceId string)
+}
+
+type netServerNode struct {
+	sync.RWMutex
+	nodeList map[string]rocommon.ServerNode
+}
+
+func NewMultiServerNode() *netServerNode {
+	m := &netServerNode{}
+	m.nodeList = map[string]rocommon.ServerNode{}
+	return m
+}
+
+func (this *netServerNode) GetNode(serviceId string) rocommon.ServerNode {
+	this.RLock()
+	defer this.RUnlock()
+	if node, ok := this.nodeList[serviceId]; ok {
+		return node
+	}
+	return nil
+}
+
+func (this *netServerNode) RemoveNode(serviceId string) {
+	this.Lock()
+	defer this.Unlock()
+	delete(this.nodeList, serviceId)
+}
+
+func (this *netServerNode) AddNode(desc *ETCDServiceDesc, node rocommon.ServerNode) {
+	this.Lock()
+	this.nodeList[desc.ID] = node
+	this.Unlock()
+}

+ 55 - 0
RO_Server_Trunk-branch_0.1.39/rocommon/service/redisconnector.go

@@ -0,0 +1,55 @@
+package service
+
+import (
+	"github.com/go-redis/redis"
+	"rocommon/socket"
+)
+
+const NIL = redis.Nil
+
+type BaseStore = redis.ZStore
+type BaseZ = redis.Z
+type BaseCmdable = redis.Cmdable
+
+type RedisConnector interface {
+	RedisCli() BaseCmdable
+	SetName(s string)
+}
+
+type NetRedisConnector struct {
+	socket.NetServerNodeProperty
+	socket.NetContextSet
+	socket.NetRedisParam
+	redisCommonCli redis.Cmdable
+	//redisCli       *redis.Client
+	//redisClusterCli *redis.ClusterClient
+	cluster int //>0表示cluster模式(集群版本)
+}
+
+func NewNetRedisConnector(addr []string, pwd string, dbIndex, cluster int) RedisConnector {
+	rs := &NetRedisConnector{}
+	rs.cluster = cluster
+	if cluster <= 0 {
+		rs.SetAddr(addr[0])
+		rs.SetPwd(pwd)
+		rs.SetDBIndex(dbIndex)
+
+		rs.redisCommonCli = redis.NewClient(&redis.Options{
+			Addr:     addr[0],
+			Password: pwd,
+			DB:       dbIndex,
+		})
+	} else {
+		rs.SetPwd(pwd)
+		rs.redisCommonCli = redis.NewClusterClient(
+			&redis.ClusterOptions{
+				Addrs:    addr,
+				Password: pwd,
+			})
+	}
+	return rs
+}
+
+func (this *NetRedisConnector) RedisCli() BaseCmdable {
+	return this.redisCommonCli
+}

+ 143 - 0
RO_Server_Trunk-branch_0.1.39/rocommon/service/yamlconfig.go

@@ -0,0 +1,143 @@
+package service
+
+import "fmt"
+
+/*
+#服务器都对内监听处理(处理服务器之间的连接)
+#loglevel
+#   Debug 1
+#	Info 2
+#	Warning 3
+#	Error 4
+#	Fatal 5
+# 服务器类型节点Type:[1 gate] [2 game] [3 db] [4 auth] [5 social chat mail] [10 map]
+
+#服务器都对内监听处理(处理服务器之间的连接)
+node:
+  addr: 0.0.0.0:8101
+  type: 1
+  id: 1
+  zone: 1
+  logfile: 。/log
+  config: ./config/csv
+  loglevel: 1
+  etcdaddr: 192.168.56.102:2379
+  concern: game
+
+#服务器对外开放端口
+acceptor:
+  addr: 0.0.0.0:21001
+
+#处理redis连接使用
+db:
+  redisaddr: 0.0.0.0:6379
+*/
+//yaml 数据转换为 Go 结构体的在线服务
+//https://zhwt.github.io/yaml-to-go/
+type ServerNode struct {
+	Server []ConfigServerNode
+}
+type ConfigServerNode struct {
+	//服务器都对内监听处理(处理服务器之间的连接)
+	Node configServerNode `yaml:"node"`
+	//服务器对外开放端口(一般gate使用)
+	Acceptor configServerAcceptor `yaml:"acceptor"`
+	//redis连接使用
+	Redis configServerDB `yaml:"db"`
+	//elastic
+	Elastic configElastic `yaml:"elastic"`
+	//SDK
+	SDKConfig configSDK `yaml:"sdkhttp"`
+
+	ServerStartTime uint64
+}
+
+type configServerNode struct {
+	NodeName string `yaml:"nodename"`
+	Addr     string `yaml:"addr"`
+	//是否是websocket模式
+	ISWS       bool   `yaml:"ws"`
+	Type       int    `yaml:"type"`
+	Id         int    `yaml:"id"`
+	Zone       int    `yaml:"zone"`
+	Logfile    string `yaml:"logfile"`
+	UniLogFile string `yaml:"unilogfile"`
+	RecordFile string `yaml:"recordfile"`
+	//日志文件等级
+	LogLevel int `yaml:"loglevel"`
+	//单个日志大小M
+	LogMaxSize int    `yaml:"logmaxsize"`
+	EtcdAddr   string `yaml:"etcdaddr"`
+	//局部跨服etcd注册(跨服远航)
+	CrossEtcdAddr string `yaml:"crossetcdaddr"`
+	//所有服务器跨服etcd注册
+	GCrossEtcdAddr string `yaml:"gcrossetcdaddr"`
+	//配置文件路径
+	Config string `yaml:"config"`
+	//需要连接的服务器类型节点
+	Concern []string `yaml:"concern,flow"`
+	//创建角色后注册到serverlist列表
+	ServerList string `yaml:"serverlist"`
+	//php后台gm地址
+	PhpServerAddr string `yaml:"phpserveraddr"`
+	//是否开启服务器的断线重连
+	Reconnect int `yaml:"reconnect"`
+	//账号验证模式1:PC模式,不做任何处理 2:激活码模式 3:第三方平台验证模式SDK
+	AuthMode int `yaml:"authmode"`
+	//1:机器人模式 2:无法注册 3:关闭付费功能
+	RobotMode int    `yaml:"robotmode"`
+	HttpAddr  string `yaml:"httpaddr"` //gmweb服务器http监听端口
+	//gm白名单
+	WhiteListGM []string `yaml:"whitelist,flow"`
+}
+
+type configServerAcceptor struct {
+	Addr string `yaml:"addr"`
+}
+
+type configServerConnector struct {
+	Concern string `yaml:"concern"`
+}
+
+type configServerDB struct {
+	RedisAddr    []string `yaml:"redisaddr,flow"`
+	Password     string   `yaml:"password"`
+	DBIndex      int      `yaml:"dbindex"`
+	MysqlAddr    string   `yaml:"mysqladdr"`
+	RedisCluster int      `yaml:"cluster"`
+}
+
+type configElastic struct {
+	Url   string `yaml:"url"`
+	Index string `yaml:"index"`
+}
+
+type configSDK struct {
+	QuickHttpAddr    string `yaml:"quickhttpaddr"`
+	QuickHttpAuth    string `yaml:"quickhttpauth"`
+	QuickProductCode string `yaml:"quickproductcode"`
+	QuickProductKey  string `yaml:"quickproductkey"`
+	QuickCallbackKey string `yaml:"quickcallbackkey"`
+	QuickMd5key      string `yaml:"quickmd5key"`
+
+	UniHttpAddr     string `yaml:"unihttpaddr"`
+	UniSecretKey    string `yaml:"unisecretkey"`
+	UniWebTokenAddr string `yaml:"uniwebtokenaddr"`
+	UniWebSalt      string `yaml:"uniwebsalt"`
+	UniWebPid       string `yaml:"uniwebpid"`
+
+	NbHttpAddr string `yaml:"nbhttpaddr"`
+	NbHttpAuth string `yaml:"nbhttpauth"`
+	NbGameKey  string `yaml:"nbgamekey"`
+
+	YouYiHttpAddr      string   `yaml:"youyihttpaddr"`
+	YouYiPayKey        string   `yaml:"youyipaykey"`
+	YouYiGameId        string   `yaml:"youyigameid"`
+	YouYiGameIdList    []string `yaml:"youyigameidlist"`
+	YouYiGameIdIOS     string   `yaml:"youyigameidios"`
+	YouYiGameIdListIOS []string `yaml:"youyigameidlistios"`
+}
+
+func (this *ConfigServerNode) Error() string {
+	return fmt.Sprintf("%+v", *this)
+}

+ 102 - 0
RO_Server_Trunk-branch_0.1.39/rocommon/socket/http/acceptor.go

@@ -0,0 +1,102 @@
+package http
+
+import (
+	"errors"
+	"net"
+	"net/http"
+	"rocommon"
+	"rocommon/socket"
+	"rocommon/util"
+	"time"
+)
+
+var errNotFound = errors.New("404 Not found")
+var ErrUnknownOperation = errors.New("unknown http operation")
+
+type tcpKeepAliveListener struct {
+	*net.TCPListener
+}
+
+func (this tcpKeepAliveListener) Accept() (net.Conn, error) {
+	tc, err := this.AcceptTCP()
+	if err != nil {
+		return nil, err
+	}
+	tc.SetKeepAlive(true)
+	tc.SetKeepAlivePeriod(3 * time.Minute)
+	return tc, nil
+}
+
+type httpAcceptor struct {
+	socket.NetContextSet
+	socket.NetServerNodeProperty
+	socket.NetProcessorRPC //事件处理相关
+
+	sv *http.Server
+
+	httpDir  string
+	httpRoot string
+
+	listener net.Listener
+}
+
+func (this *httpAcceptor) Port() int {
+	if this.listener == nil {
+		return 0
+	}
+	return this.listener.Addr().(*net.TCPAddr).Port
+}
+
+func (this *httpAcceptor) Start() rocommon.ServerNode {
+	//ServeHTTP
+	this.sv = &http.Server{Addr: this.GetAddr(), Handler: this}
+
+	ln, err := net.Listen("tcp", this.GetAddr())
+	if err != nil {
+		util.ErrorF("http.listen failed=%v", err)
+		return this
+	}
+
+	this.listener = ln
+	util.ErrorF("http.listen success")
+
+	go func() {
+		this.sv.Serve(tcpKeepAliveListener{this.listener.(*net.TCPListener)})
+		if err != nil && err != http.ErrServerClosed {
+			util.ErrorF("http.listen name=%v failed=%v", this.GetName(), err)
+		}
+	}()
+	return this
+}
+
+func (this *httpAcceptor) Stop() {
+
+}
+
+func (this *httpAcceptor) TypeOfName() string {
+	return "httpAcceptor"
+}
+
+func (this *httpAcceptor) ServeHTTP(res http.ResponseWriter, req *http.Request) {
+	sess := newHttpSession(this, req, res)
+
+	var msg interface{}
+	var err error
+
+	this.ProcEvent(&rocommon.RecvMsgEvent{Sess: sess, Message: msg})
+
+	if sess.err != nil {
+		err = sess.err
+		http.Error(sess.resp, err.Error(), http.StatusInternalServerError)
+		return
+	}
+	//todo...
+	// .html
+}
+
+func init() {
+	socket.RegisterServerNode(func() rocommon.ServerNode {
+		node := &httpAcceptor{}
+		return node
+	})
+}

+ 118 - 0
RO_Server_Trunk-branch_0.1.39/rocommon/socket/http/connector.go

@@ -0,0 +1,118 @@
+package http
+
+import (
+	"context"
+	"fmt"
+	"io"
+	"log"
+	"net"
+	"net/http"
+	"rocommon"
+	"rocommon/socket"
+	"strings"
+	"time"
+)
+
+type httpConnector struct {
+	socket.NetServerNodeProperty
+	socket.NetContextSet
+	socket.NetProcessorRPC //事件处理相关
+}
+
+func (this *httpConnector) Start() rocommon.ServerNode {
+	return this
+}
+
+func (this *httpConnector) Stop() {
+}
+
+func (this *httpConnector) TypeOfName() string {
+	return "httpConnector"
+}
+func (this *httpConnector) Request(method, path string, param *rocommon.HTTPRequest) error {
+	codecProc := rocommon.GetHttpCodec(param.ReqCodecName)
+	if method == "POST" {
+		data, err := codecProc.Marshal(param.ReqMsg)
+		if err != nil {
+			return err
+		}
+
+		url := fmt.Sprintf("http://%s%s", this.GetAddr(), path)
+		if strings.Contains(this.GetAddr(), "http") {
+			url = fmt.Sprintf("%s%s", this.GetAddr(), path)
+		}
+
+		req, err := http.NewRequest(method, url, data.(io.Reader))
+		if err != nil {
+			return nil
+		}
+
+		mimeType := codecProc.(interface {
+			MimeType() string
+		}).MimeType()
+		req.Header.Set("Content-Type", mimeType)
+
+		resp, err := defaultHttpClient.Do(req)
+		if resp != nil {
+			defer resp.Body.Close()
+		}
+		if err != nil {
+			return err
+		}
+
+		//log.Println("[header]:", resp.Header, resp.Status, resp.Body)
+		return codecProc.Unmarshal(resp.Body, param.ResMsg)
+	} else {
+		url := fmt.Sprintf("http://%s%s", this.GetAddr(), path)
+		if strings.Contains(this.GetAddr(), "http") {
+			url = fmt.Sprintf("%s%s", this.GetAddr(), path)
+		}
+		req, err := http.NewRequest(method, url, nil)
+		if err != nil {
+			return nil
+		}
+
+		mimeType := codecProc.(interface {
+			MimeType() string
+		}).MimeType()
+		req.Header.Set("Content-Type", mimeType)
+
+		resp, err := defaultHttpClient.Do(req)
+		if resp != nil {
+			defer resp.Body.Close()
+		}
+		if err != nil {
+			return err
+		}
+
+		//log.Println("[header]:", resp.Header, resp.Status, resp.Body)
+		return codecProc.Unmarshal(resp.Body, param.ResMsg)
+	}
+}
+
+var defaultHttpClient *http.Client = nil
+
+func defaultClient() {
+	defaultHttpClient = &http.Client{
+		Transport: &http.Transport{
+			DialContext: func(ctx context.Context, network, addr string) (net.Conn, error) {
+				deadline := time.Now().Add(time.Second * 30)
+				c, err := net.DialTimeout(network, addr, time.Second*30)
+				if err != nil {
+					return nil, err
+				}
+				c.SetDeadline(deadline)
+				return c, nil
+			},
+		},
+	}
+}
+
+func init() {
+	log.Println("httpConnector server node register")
+	socket.RegisterServerNode(func() rocommon.ServerNode {
+		node := &httpConnector{}
+		return node
+	})
+	defaultClient()
+}

+ 39 - 0
RO_Server_Trunk-branch_0.1.39/rocommon/socket/http/respond_msg.go

@@ -0,0 +1,39 @@
+package http
+
+import (
+	"errors"
+	"io"
+	"io/ioutil"
+	"net/http"
+	"rocommon"
+)
+
+type MessageRespond struct {
+	Msg        interface{}
+	StatusCode int
+}
+
+func (this *MessageRespond) WriteRespond(sess *httpSession) error {
+	this.StatusCode = http.StatusOK
+
+	httpCodec := rocommon.GetHttpCodec("httpjson")
+	if httpCodec == nil {
+		return errors.New("ResponseCodec not found httpjson")
+	}
+
+	data, err := httpCodec.Marshal(this.Msg)
+	if err != nil {
+		return err
+	}
+
+	sess.resp.Header().Set("Content-Type", "application/json"+";charset=UTF-8")
+	sess.resp.WriteHeader(this.StatusCode)
+	bodyData, err := ioutil.ReadAll(data.(io.Reader))
+	if err != nil {
+		return err
+	}
+
+	sess.resp.Write(bodyData)
+
+	return nil
+}

+ 90 - 0
RO_Server_Trunk-branch_0.1.39/rocommon/socket/http/session.go

@@ -0,0 +1,90 @@
+package http
+
+import (
+	"net/http"
+	"rocommon"
+)
+
+type ResponseProc interface {
+	WriteRespond(*httpSession) error
+}
+type RequestProc interface {
+	Match(method, url string) bool
+}
+
+type httpSession struct {
+	err     error
+	respond bool
+
+	node rocommon.ServerNode
+
+	req  *http.Request
+	resp http.ResponseWriter
+}
+
+func newHttpSession(node rocommon.ServerNode, req *http.Request, res http.ResponseWriter) *httpSession {
+	sess := &httpSession{
+		node: node,
+		req:  req,
+		resp: res,
+	}
+	return sess
+}
+
+func (this *httpSession) Node() rocommon.ServerNode {
+	return this.node
+}
+func (this *httpSession) Raw() interface{} {
+	return nil
+}
+func (this *httpSession) ID() uint64 {
+	return 0
+}
+
+func (this *httpSession) GetAES() *[]byte {
+	return nil
+}
+func (this *httpSession) SetAES(aes string) {
+}
+func (this *httpSession) GetHandCode() string {
+	return ""
+}
+func (this *httpSession) IncRecvPingNum(incNum int) {
+}
+func (this *httpSession) RecvPingNum() int {
+	return 0
+}
+
+func (this *httpSession) SetHandCode(code string) {
+}
+func (this *httpSession) GetSessionOpt() interface{} {
+	return nil
+}
+func (this *httpSession) GetSessionOptFlag() bool {
+	return true
+}
+func (this *httpSession) SetSessionOptFlag(flag bool) {
+}
+
+func (this *httpSession) Close() {
+}
+func (this *httpSession) Match(method, url string) bool {
+	return this.req.Method == method && this.req.URL.Path == url
+}
+func (this *httpSession) Request() *http.Request {
+	return this.req
+}
+func (this *httpSession) Response() http.ResponseWriter {
+	return this.resp
+}
+
+func (this *httpSession) Send(msg interface{}) {
+	if proc, ok := msg.(ResponseProc); ok {
+		this.err = proc.WriteRespond(this)
+		this.respond = true
+	} else {
+		this.err = ErrUnknownOperation
+	}
+}
+
+func (this *httpSession) HeartBeat(msg interface{}) {}

+ 97 - 0
RO_Server_Trunk-branch_0.1.39/rocommon/socket/mysql/connector.go

@@ -0,0 +1,97 @@
+package mysql
+
+import (
+	"database/sql"
+	"github.com/go-sql-driver/mysql"
+	"rocommon"
+	"rocommon/socket"
+	"rocommon/util"
+	"sync"
+	"time"
+)
+
+type MysqlConnector struct {
+	MySQLParameter
+	socket.NetServerNodeProperty
+	db      *sql.DB
+	dbMutex sync.RWMutex
+
+	reconDur time.Duration
+}
+
+func (this *MysqlConnector) dbConn() *sql.DB {
+	this.dbMutex.RLock()
+	defer this.dbMutex.RUnlock()
+
+	return this.db
+}
+
+func (this *MysqlConnector) IsReady() bool {
+	return this.dbConn() != nil
+}
+
+func (this *MysqlConnector) Operate(cb func(client interface{}) interface{}) interface{} {
+	return cb(this.dbConn())
+}
+
+func (this *MysqlConnector) TypeOfName() string {
+	return "mysqlConnector"
+}
+
+func (this *MysqlConnector) SetReconnectDuration(v time.Duration) {
+	this.reconDur = v
+}
+
+func (this *MysqlConnector) tryConnect() {
+	_, err := mysql.ParseDSN(this.GetAddr())
+	if err != nil {
+		util.ErrorF("invalid mysql dns=%v err=%v", this.GetAddr(), err)
+		return
+	}
+	//util.InfoF("connect to mysql name=%v addr=%v dbname=%v", this.GetName(), cfg.Addr, cfg.DBName)
+
+	db, err := sql.Open("mysql", this.GetAddr())
+	if err != nil {
+		util.ErrorF("open mysql database err=%v", err)
+		return
+	}
+
+	err = db.Ping()
+	if err != nil {
+		util.ErrorF("ping err=%v", err)
+		return
+	}
+
+	db.SetMaxIdleConns(int(this.PoolConnCount))
+	db.SetMaxIdleConns(int(this.PoolConnCount))
+
+	this.dbMutex.Lock()
+	this.db = db
+	this.dbMutex.Unlock()
+}
+func (this *MysqlConnector) Start() rocommon.ServerNode {
+	for {
+		this.tryConnect()
+		if this.reconDur == 0 || this.IsReady() {
+			break
+		}
+		time.Sleep(this.reconDur)
+	}
+	return this
+}
+
+func (this *MysqlConnector) Stop() {
+	db := this.dbConn()
+	if db != nil {
+		db.Close()
+	}
+}
+
+func init() {
+	socket.RegisterServerNode(func() rocommon.ServerNode {
+		node := new(MysqlConnector)
+		node.MySQLParameter.Init()
+		return node
+	})
+
+}

+ 106 - 0
RO_Server_Trunk-branch_0.1.39/rocommon/socket/mysql/ormconnector.go

@@ -0,0 +1,106 @@
+package mysql
+
+import (
+	"database/sql"
+	"gorm.io/driver/mysql"
+	"gorm.io/gorm"
+	"rocommon"
+	"rocommon/socket"
+	"rocommon/util"
+	"sync"
+	"time"
+)
+
+type MysqlOrmConnector struct {
+	MySQLParameter
+	socket.NetServerNodeProperty
+	db      *sql.DB
+	ormDb   *gorm.DB
+	dbMutex sync.RWMutex
+
+	reconDur time.Duration
+}
+
+func (this *MysqlOrmConnector) dbConn() *sql.DB {
+	this.dbMutex.RLock()
+	defer this.dbMutex.RUnlock()
+
+	return this.db
+}
+func (this *MysqlOrmConnector) DbConnORM() *gorm.DB {
+	this.dbMutex.RLock()
+	defer this.dbMutex.RUnlock()
+
+	return this.ormDb
+}
+func (this *MysqlOrmConnector) IsReady() bool {
+	return this.dbConn() != nil
+}
+
+func (this *MysqlOrmConnector) Operate(cb func(client interface{}) interface{}) interface{} {
+	return cb(this.dbConn())
+}
+
+func (this *MysqlOrmConnector) TypeOfName() string {
+	return "MysqlOrmConnector"
+}
+
+func (this *MysqlOrmConnector) SetReconnectDuration(v time.Duration) {
+	this.reconDur = v
+}
+func (this *MysqlOrmConnector) tryConnect() {
+	tmpOrmDb, err := gorm.Open(mysql.Open(this.GetAddr()), &gorm.Config{})
+	//_, err := mysql.ParseDSN(this.GetAddr())
+	if err != nil {
+		util.ErrorF("invalid mysql dns=%v err=%v", this.GetAddr(), err)
+		return
+	}
+
+	//util.InfoF("connect to mysql name=%v addr=%v dbname=%v", this.GetName(), cfg.Addr, cfg.DBName)
+	this.ormDb = tmpOrmDb
+	tmpDb, err := this.ormDb.DB()
+	if err != nil {
+		util.ErrorF("invalid mysql DB() err=%v", this.GetAddr(), err)
+		return
+	}
+
+	err = tmpDb.Ping()
+	if err != nil {
+		util.ErrorF("ping err=%v", err)
+		return
+	}
+
+	tmpDb.SetMaxIdleConns(int(this.PoolConnCount))
+	tmpDb.SetMaxIdleConns(int(this.PoolConnCount))
+
+	this.dbMutex.Lock()
+	this.db = tmpDb
+	this.dbMutex.Unlock()
+}
+
+func (this *MysqlOrmConnector) Start() rocommon.ServerNode {
+	for {
+		this.tryConnect()
+		if this.reconDur == 0 || this.IsReady() {
+			break
+		}
+		time.Sleep(this.reconDur)
+	}
+	return this
+}
+
+func (this *MysqlOrmConnector) Stop() {
+	db := this.dbConn()
+	if db != nil {
+		db.Close()
+	}
+}
+
+func init() {
+	socket.RegisterServerNode(func() rocommon.ServerNode {
+		node := new(MysqlOrmConnector)
+		node.MySQLParameter.Init()
+		return node
+	})
+
+}

+ 16 - 0
RO_Server_Trunk-branch_0.1.39/rocommon/socket/mysql/sqlparam.go

@@ -0,0 +1,16 @@
+package mysql
+
+type MySQLParameter struct {
+	PoolConnCount int
+}
+
+func (this *MySQLParameter) Init() {
+	this.PoolConnCount = 32
+}
+
+func (this *MySQLParameter) SetPassword(v string) {
+}
+
+func (this *MySQLParameter) SetConnCount(val int) {
+	this.PoolConnCount = val
+}

+ 79 - 0
RO_Server_Trunk-branch_0.1.39/rocommon/socket/mysql/wrapper.go

@@ -0,0 +1,79 @@
+package mysql
+
+import (
+	"database/sql"
+	"errors"
+)
+
+type Wrapper struct {
+	drv   *sql.DB
+	row   *sql.Rows
+	query string
+
+	Err error
+}
+
+var ErrDriverNotReady = errors.New("driver not ready")
+
+func (this *Wrapper) Query(query string, args ...interface{}) *Wrapper {
+	if this.drv == nil {
+		this.Err = ErrDriverNotReady
+		return this
+	}
+
+	this.query = query
+	this.row, this.Err = this.drv.Query(query, args...)
+
+	//log.Println("rows=", this.row)
+
+	return this
+}
+
+func (this *Wrapper) Execute(query string, args ...interface{}) *Wrapper {
+	if this.drv == nil {
+		this.Err = ErrDriverNotReady
+		return this
+	}
+
+	this.query = query
+	_, this.Err = this.drv.Exec(query, args...)
+
+	return this
+}
+
+func (this *Wrapper) Each(cb func(wrapper *Wrapper) bool) *Wrapper {
+	if this.Err != nil {
+		return this
+	}
+	if this.drv == nil {
+		this.Err = ErrDriverNotReady
+		return this
+	}
+
+	for this.row.Next() {
+		if !cb(this) {
+			break
+		}
+
+		if this.Err != nil {
+			return this
+		}
+	}
+
+	this.row.Close()
+	return this
+}
+
+func (this *Wrapper) Scan(dest ...interface{}) error {
+	this.Err = this.row.Scan(dest...)
+	if this.Err != nil {
+		return this.Err
+	}
+	return nil
+}
+
+func NewWrapper(drv *sql.DB) *Wrapper {
+	return &Wrapper{
+		drv: drv,
+	}
+}

+ 144 - 0
RO_Server_Trunk-branch_0.1.39/rocommon/socket/nodeproperty.go

@@ -0,0 +1,144 @@
+package socket
+
+import (
+	"reflect"
+	"rocommon"
+	"sync"
+)
+
+/////////////////////////////////////////////NetServerNodeProperty
+type NetServerNodeProperty struct {
+	name       string //服务器名称 game,game,auth
+	addr       string //包含了ip和port
+	queue      rocommon.NetEventQueue
+	serverType int //服务器类型(例如gate,game,auth)
+	zone       int //前服务器区号(理解成服务组)
+	index      int //服务器区内的编号
+}
+
+func (this *NetServerNodeProperty) GetName() string {
+	return this.name
+}
+
+func (this *NetServerNodeProperty) SetName(s string) {
+	this.name = s
+}
+
+func (this *NetServerNodeProperty) GetAddr() string {
+	return this.addr
+}
+
+func (this *NetServerNodeProperty) SetAddr(s string) {
+	this.addr = s
+}
+
+func (this *NetServerNodeProperty) SetQueue(v rocommon.NetEventQueue) {
+	this.queue = v
+}
+
+func (this *NetServerNodeProperty) Queue() rocommon.NetEventQueue {
+	return this.queue
+}
+
+func (this *NetServerNodeProperty) SetServerType(t int) {
+	this.serverType = t
+}
+
+func (this *NetServerNodeProperty) ServerType() int {
+	return this.serverType
+}
+
+func (this *NetServerNodeProperty) SetZone(t int) {
+	this.zone = t
+}
+
+func (this *NetServerNodeProperty) GetZone() int {
+	return this.zone
+}
+
+func (this *NetServerNodeProperty) SetIndex(t int) {
+	this.index = t
+}
+
+func (this *NetServerNodeProperty) GetIndex() int {
+	return this.index
+}
+
+/////////////////////////////////////////////NetContextSet
+//用来记录session数据
+type NetContextSet struct {
+	guard   sync.RWMutex //读写锁
+	dataMap map[interface{}]keyValueData
+	//user 玩家
+	//sd 服务器相关数据
+}
+type keyValueData struct {
+	key   interface{}
+	value interface{}
+}
+
+func (this *NetContextSet) SetContextData(key, value interface{}, from string) {
+	this.guard.Lock()
+	defer this.guard.Unlock()
+	if this.dataMap == nil {
+		this.dataMap = map[interface{}]keyValueData{}
+	}
+
+	if _, ok := this.dataMap[key]; ok {
+		if value == nil {
+			//util.InfoF("ContextData clean key:%v oldValue:%v newValue:%v [%v]", key, data, value, from)
+		} else {
+			//util.FatalF("ContextData exist key:%v oldValue:%v newValue:%v [%v]", key, data, value, from)
+		}
+		this.dataMap[key] = keyValueData{key, value}
+	} else {
+		this.dataMap[key] = keyValueData{key, value}
+	}
+}
+
+func (this *NetContextSet) GetContextData(key interface{}) (interface{}, bool) {
+	this.guard.RLock()
+	defer this.guard.RUnlock()
+	if this.dataMap == nil {
+		this.dataMap = map[interface{}]keyValueData{}
+	}
+
+	if data, ok := this.dataMap[key]; ok {
+		return data.value, true
+	}
+	return nil, false
+}
+
+//根据给定类型获取数据
+func (this *NetContextSet) RawContextData(key interface{}, valuePtr interface{}) bool {
+	value, ok := this.GetContextData(key)
+	if !ok {
+		return false
+	}
+
+	switch outValue := valuePtr.(type) {
+	case *string:
+		*outValue = value.(string)
+	default:
+		v := reflect.Indirect(reflect.ValueOf(valuePtr))
+		if value != nil {
+
+			v.Set(reflect.ValueOf(value))
+		}
+	}
+	return true
+}
+
+/////////////////////////////////////////////NetRedisParam
+type NetRedisParam struct {
+	Pwd     string
+	DBIndex int
+}
+
+func (this *NetRedisParam) SetPwd(pwd string) {
+	this.Pwd = pwd
+}
+
+func (this *NetRedisParam) SetDBIndex(db int) {
+	this.DBIndex = db
+}

+ 33 - 0
RO_Server_Trunk-branch_0.1.39/rocommon/socket/nodereg.go

@@ -0,0 +1,33 @@
+package socket
+
+import (
+	"log"
+	"rocommon"
+	"rocommon/util"
+)
+
+type serverCreate func() rocommon.ServerNode
+
+var serverNodeByName = map[string]serverCreate{}
+
+func RegisterServerNode(f serverCreate) {
+	node := f()
+
+	if _, ok := serverNodeByName[node.TypeOfName()]; ok {
+		log.Fatalf("serverNode type has register name:[%v]", node.TypeOfName())
+	}
+	serverNodeByName[node.TypeOfName()] = f
+}
+
+func NewServerNode(serverType, serverName, addr string, que rocommon.NetEventQueue) rocommon.ServerNode {
+	f := serverNodeByName[serverType]
+	if f == nil {
+		util.PanicF("serverNoe type not found %v", serverType)
+	}
+	node := f()
+	nodeProperty := node.(rocommon.ServerNodeProperty)
+	nodeProperty.SetAddr(addr)
+	nodeProperty.SetName(serverName)
+	nodeProperty.SetQueue(que)
+	return node
+}

+ 436 - 0
RO_Server_Trunk-branch_0.1.39/rocommon/socket/procrpc.go

@@ -0,0 +1,436 @@
+package socket
+
+import (
+	"encoding/binary"
+	"errors"
+	"fmt"
+	"io"
+	"net"
+	"rocommon"
+	"rocommon/rpc"
+	"rocommon/util"
+
+	"github.com/gorilla/websocket"
+)
+
+type (
+	NetProcessorRPC struct {
+		//解析消息数据,发送消息数据处理
+		MsgRPC rocommon.MessageProcessor
+		//def.go 消息解析操作放到队列直接的过滤操作(已经序列化为protobuf消息结构,如果在转换之前就做处理的,可以在MsgRPC中直接处理
+		Hooker rocommon.EventHook
+		//def.go  注册的具体函数回掉(具体的逻辑实现方法,例如:pbbind_gen.go中的gateHandler),没有回调函数时设置为nil
+		Callback rocommon.EventCallBack
+	}
+)
+type ProcessorRPCBinder func(b rocommon.ProcessorRPCBundle, usercb rocommon.EventCallBack, args ...interface{})
+
+var (
+	//当前执行的进程名称,和回调相关的函数操作
+	procRPCByName = map[string]ProcessorRPCBinder{}
+)
+
+func RegisterProcessRPC(procName string, f ProcessorRPCBinder) {
+	if _, ok := procRPCByName[procName]; ok {
+		panic("procRPC has register:" + procName)
+	}
+	procRPCByName[procName] = f
+}
+
+func SetProcessorRPC(node rocommon.ServerNode, procName string, callback rocommon.EventCallBack, args ...interface{}) {
+	if proc, ok := procRPCByName[procName]; ok {
+		b := node.(rocommon.ProcessorRPCBundle)
+		proc(b, callback, args)
+	} else {
+		panic("procRPC not register:" + procName)
+	}
+}
+
+//加入回调队列或者直接执行回调操作
+func QueueEventCall(cb rocommon.EventCallBack) rocommon.EventCallBack {
+	return func(e rocommon.ProcEvent) {
+		if cb != nil {
+			SessionQueueCall(e.Session(), func() {
+				//now1 := time.Now()
+				cb(e)
+				//deltaT := time.Now().Sub(now1)
+				//if deltaT > 1*time.Millisecond {
+				//	if e.Msg() != nil && reflect.TypeOf(e.Msg()) != nil {
+				//		tmpMsg := reflect.TypeOf(e.Msg()).Elem().String()
+				//		util.DebugF("t=%v profile=%v", deltaT, tmpMsg)
+				//	}
+				//}
+			})
+		}
+	}
+}
+
+//在会话上执行事件回调,有队列则加入队列,没有就直接执行回调
+func SessionQueueCall(s rocommon.Session, cb func()) {
+	if s == nil {
+		return
+	}
+	que := s.Node().(interface{ Queue() rocommon.NetEventQueue }).Queue()
+	if que != nil {
+		que.PostCb(cb) //加入事件队列中
+	} else {
+		//todo...
+		cb() //不存在直接执行回调函数(注意多线程冲突问题)
+	}
+}
+
+//注册和回掉函数相关操作
+func init() {
+	RegisterProcessRPC("tcp.pb",
+		func(b rocommon.ProcessorRPCBundle, usercb rocommon.EventCallBack, arg ...interface{}) {
+			b.SetTransmitter(new(TCPMessageProcessor))
+			b.SetHooker(new(TCPEventHook))
+			b.SetCallback(QueueEventCall(usercb))
+		})
+}
+
+/////////////////////////////////////////////
+//NetProcessorRPC
+func (this *NetProcessorRPC) GetRPC() *NetProcessorRPC {
+	return this
+}
+
+//收到消息后调用该函数入队列操作
+func (this *NetProcessorRPC) ProcEvent(e rocommon.ProcEvent) {
+	//todo... hooker callback
+	if this.Hooker != nil {
+		e = this.Hooker.InEvent(e) //对不同消息类型进行解析,并进行处理
+	}
+
+	if this.Callback != nil && e != nil {
+		this.Callback(e)
+	}
+}
+
+func (this *NetProcessorRPC) ReadMsg(session rocommon.Session) (interface{}, uint32, error) {
+	if this.MsgRPC != nil {
+		return this.MsgRPC.OnRecvMsg(session)
+	}
+	return nil, 0, errors.New("msgrpc not set!!!")
+}
+
+func (this *NetProcessorRPC) SendMsg(ev rocommon.ProcEvent) error {
+	//执行hook
+	if this.Hooker != nil {
+		ev = this.Hooker.OutEvent(ev)
+	}
+	if this.MsgRPC != nil {
+		return this.MsgRPC.OnSendMsg(ev.Session(), ev.Msg())
+	}
+	return nil
+}
+
+func (self *NetProcessorRPC) SetTransmitter(mp rocommon.MessageProcessor) {
+	self.MsgRPC = mp
+}
+
+func (self *NetProcessorRPC) SetHooker(ev rocommon.EventHook) {
+	self.Hooker = ev
+}
+
+func (self *NetProcessorRPC) SetCallback(ecb rocommon.EventCallBack) {
+	self.Callback = ecb
+}
+
+/////////////////////////////////////////////
+//EventHook interface def.go
+type TCPEventHook struct {
+}
+
+func (this *TCPEventHook) InEvent(e rocommon.ProcEvent) rocommon.ProcEvent {
+	//todo... important
+	//根据收到的消息类型进行过滤处理,例如如果是RecvMsgEvent事件,那么说明进过了protobuf解析,直接返回
+	//例如远程过程调用的方式
+	inEvent, handled, err := RPCResolveInEvent(e)
+	if err != nil {
+		util.InfoF("rpc ResolveInEvent err:%v", err)
+		return nil
+	}
+	if !handled {
+		//todo... delay resolve event
+	}
+
+	return inEvent
+}
+
+//获得发送事件
+func (this *TCPEventHook) OutEvent(out rocommon.ProcEvent) rocommon.ProcEvent {
+	//todo...
+	handled, err := RPCResloveOutEvent(out)
+	if err != nil {
+		util.InfoF("rpc RPCResolveOutEvent err:%v", err)
+		return nil
+	}
+
+	if !handled {
+		//todo... delay reslove event
+	}
+	return out
+}
+
+//multiHook 例如game server有多个处理操作
+type MultiTCPEventHook []rocommon.EventHook
+
+func (this MultiTCPEventHook) InEvent(in rocommon.ProcEvent) rocommon.ProcEvent {
+	for _, ev := range this {
+		in = ev.InEvent(in)
+		if in == nil {
+			break
+		}
+	}
+	return in
+}
+
+//获得发送事件
+func (this MultiTCPEventHook) OutEvent(out rocommon.ProcEvent) rocommon.ProcEvent {
+	for _, ev := range this {
+		out = ev.OutEvent(out)
+		if out == nil {
+			break
+		}
+	}
+	return out
+}
+
+func NewMultiTCPEventHook(args ...rocommon.EventHook) rocommon.EventHook {
+	return MultiTCPEventHook(args)
+}
+
+//根据收到的消息类型进行过滤处理,例如如果是RecvMsgEvent事件,那么说明经过了protobuf解析,直接返回
+//例如远程过程调用的方式 / RPC消息解析
+func RPCResolveInEvent(inEvent rocommon.ProcEvent) (rocommon.ProcEvent, bool, error) {
+	//是接收处理消息
+	if _, ok := inEvent.(*rocommon.RecvMsgEvent); ok {
+		return inEvent, false, nil
+	}
+
+	//todo...其他消息类型处理 important
+	return inEvent, false, nil
+}
+
+func RPCResloveOutEvent(outEvent rocommon.ProcEvent) (bool, error) {
+	//todo... RemoteCallMsg
+	return true, nil
+}
+
+/////////////////////////////////////////////
+//MessageProcessor interface def.go
+type TCPMessageProcessor struct {
+}
+
+//recv
+func (this *TCPMessageProcessor) OnRecvMsg(s rocommon.Session) (msg interface{}, msgSeqId uint32, err error) {
+	//todo...
+	reader, ok := s.Raw().(io.Reader)
+	if !ok || reader == nil {
+		util.InfoF("[TCPMessageProcessor] OnRecvMsg err")
+		return nil, 0, nil
+	}
+
+	opt := s.Node().(SocketOption)
+	opt.SocketReadTimeout(reader.(net.Conn), func() {
+		msg, msgSeqId, err = rpc.ReadMessage(reader, opt.MaxMsgLen(), s.GetAES())
+	})
+	return
+}
+
+//send
+var tmpClient = []byte("client")
+
+func (this *TCPMessageProcessor) OnSendMsg(s rocommon.Session, msg interface{}) (err error) {
+	util.InfoF("[TCPMessageProcessor] OnSendMsg session=%v msg=%v", s, msg)
+	//todo...
+	writer, ok := s.Raw().(io.Writer)
+	if !ok || writer == nil {
+		util.InfoF("[TCPMessageProcessor] OnSendMsg err")
+		return nil
+	}
+
+	opt := s.Node().(SocketOption)
+	opt.SocketWriteTimeout(writer.(net.Conn), func() {
+		nodeName := s.Node().(rocommon.ServerNodeProperty).GetName()
+		if nodeName == "client" {
+			err = rpc.SendMessage(writer, msg, s.GetAES(), opt.MaxMsgLen(), nodeName)
+		} else {
+			err = rpc.SendMessage(writer, msg, s.GetAES(), opt.MaxMsgLen(), nodeName)
+
+		}
+	})
+	return
+}
+
+/////////////////////////////////////////////
+//MessageProcessor interface def.go
+type WSMessageProcessor struct {
+}
+
+const (
+	lenMaxLen  = 2 //包体大小2个字节 uint16
+	msgIdLen   = 2 //包ID大小2个字节  uint16
+	msgSeqlen  = 4 //发送序列号2个字节大小,用来断线重连
+	msgFlaglen = 2 //暂定标记,加解密 1表示RSA,2表示AES
+)
+
+//recv
+func (this *WSMessageProcessor) OnRecvMsg(s rocommon.Session) (msg interface{}, msgSeqId uint32, err error) {
+	conn, ok := s.Raw().(*websocket.Conn)
+	if !ok || conn == nil {
+		util.InfoF("[WSMessageProcessor] OnRecvMsg err")
+		return nil, 0, nil
+	}
+
+	//reader, ok := s.Raw().(io.Reader)
+	//if !ok || reader == nil {
+	//	util.InfoF("[TCPMessageProcessor] OnRecvMsg err")
+	//	return nil, 0, nil
+	//}
+
+	messageType, raw, err := conn.ReadMessage()
+	if err != nil {
+		util.InfoF("[WSMessageProcessor] OnRecvMsg err=%v", err)
+		return nil, 0, nil
+	}
+	if messageType != websocket.BinaryMessage {
+		util.InfoF("[WSMessageProcessor] OnRecvMsg err messageType=%v", messageType)
+		return nil, 0, nil
+	}
+
+	var msgId uint16
+	//var seqId uint32  //包序列号,客户端发送时的序列从1开始
+	var flagId uint16 //加密方式
+	var msgData []byte
+
+	binary.BigEndian.Uint16(raw) //msgDataLen
+	msgId = binary.BigEndian.Uint16(raw[lenMaxLen:])
+	msgSeqId = binary.BigEndian.Uint32(raw[lenMaxLen+msgIdLen:])
+	flagId = binary.BigEndian.Uint16(raw[lenMaxLen+msgIdLen+msgSeqlen:])
+	msgData = raw[msgIdLen+msgSeqlen+msgFlaglen+lenMaxLen:]
+
+	aesKey := s.GetAES()
+	switch flagId {
+	case 1:
+		if int(msgId) == rpc.SC_HAND_SHAKE_NTFMsgId { //SC_HAND_SHAKE_NTF
+			msgData, err = rpc.RSADecrypt(msgData, rpc.PrivateClientKey)
+			if err != nil {
+				return nil, 0, err
+			}
+		} else if int(msgId) == rpc.CS_HAND_SHAKE_REQMsgId { //CS_HAND_SHAKE_REQ
+			msgData, err = rpc.RSADecrypt(msgData, rpc.PrivateServerKey)
+			if err != nil {
+				return nil, 0, err
+			}
+		} else if int(msgId) == rpc.SC_HAND_SHAKE_ACKMsgId { //SC_HAND_SHAKE_ACK
+			msgData, err = rpc.RSADecrypt(msgData, rpc.PrivateClientKey)
+			if err != nil {
+				return nil, 0, err
+			}
+		} else {
+			msgData, err = rpc.RSADecrypt(msgData, rpc.PrivateKey)
+			if err != nil {
+				return nil, 0, err
+			}
+		}
+	case 2:
+		msgData, err = rpc.AESCtrDecrypt(msgData, *aesKey, *aesKey...)
+		//msgData, err = AESCtrDecrypt(msgData, *aesKey)
+		if err != nil {
+			return nil, 0, err
+		}
+	}
+
+	//服务器内部不做加密处理
+	msg, _, err = rpc.DecodeMessage(int(msgId), msgData)
+	if err != nil {
+		//log.Println("[DecodeMessage] err:", err)
+		return nil, 0, errors.New(fmt.Sprintf("msg decodeMessage failed:%v %v", msgId, err))
+	}
+
+	return
+}
+
+func (this *WSMessageProcessor) OnSendMsg(s rocommon.Session, msg interface{}) (err error) {
+	opt := s.Node().(SocketOption)
+
+	conn, ok := s.Raw().(*websocket.Conn)
+	if !ok || conn == nil {
+		util.InfoF("[WSMessageProcessor] OnRecvMsg err")
+		return nil
+	}
+	nodeName := s.Node().(rocommon.ServerNodeProperty).GetName()
+	if nodeName != "wsclient" {
+		return
+	}
+	aesKey := s.GetAES()
+	var (
+		msgData []byte
+		msgId   uint16
+		seqId   uint32
+		msgInfo *rocommon.MessageInfo
+	)
+	switch m := msg.(type) {
+	case *rocommon.TransmitPacket:
+		msgData = m.MsgData
+		msgId = uint16(m.MsgId)
+		seqId = m.SeqId
+	default:
+		msgData, msgInfo, err = rpc.EncodeMessage(msg)
+		if err != nil {
+			return err
+		}
+		msgId = uint16(msgInfo.ID)
+	}
+	//todo
+	// 注意上层发包不要超过最大值
+	msgLen := len(msgData)
+	var cryptType uint16 = 0
+	//握手阶段
+	if msgId == uint16(rpc.SC_HAND_SHAKE_NTFMsgId) {
+		cryptType = 1
+		msgData, err = rpc.RSAEncrypt(msgData, rpc.PublicClientKey)
+		if err != nil {
+			return err
+		}
+		msgLen = len(msgData)
+	} else {
+		if len(*aesKey) > 0 && msgId != rpc.SC_PING_ACKMsgId {
+			cryptType = 2
+			msgData, err = rpc.AESCtrEncrypt(msgData, *aesKey, *aesKey...)
+			//msgData, err = AESCtrEncrypt(msgData, *aesKey)
+			if err != nil {
+				return err
+			}
+			msgLen = len(msgData)
+		}
+	}
+	if msgLen > opt.MaxMsgLen() {
+		err = errors.New(fmt.Sprintf("message too big msgId=%v msglen=%v maxlen=%v", msgId, msgLen, opt.MaxMsgLen()))
+		util.FatalF("SendMessage err=%v", err)
+		err = nil
+		return
+	}
+
+	//data := make([]byte, lenMaxLen + msgIdLen + msgLen)
+	data := make([]byte, lenMaxLen+msgIdLen+msgSeqlen+msgFlaglen+msgLen) //head + body
+	//lenMaxLen
+	binary.BigEndian.PutUint16(data, uint16(msgLen))
+	//msgIdLen
+	binary.BigEndian.PutUint16(data[lenMaxLen:], uint16(msgId))
+	//seq 返回客户端发送的序列号
+	binary.BigEndian.PutUint32(data[lenMaxLen+msgIdLen:], seqId)
+	//log.Println("sendSeqId:", seqId)
+	//使用的加密方式AES
+	binary.BigEndian.PutUint16(data[lenMaxLen+msgIdLen+msgSeqlen:], cryptType)
+
+	//body
+	if msgLen > 0 {
+		copy(data[lenMaxLen+msgIdLen+msgSeqlen+msgFlaglen:], msgData)
+	}
+	conn.WriteMessage(websocket.BinaryMessage, data)
+
+	return
+}

+ 39 - 0
RO_Server_Trunk-branch_0.1.39/rocommon/socket/runtimetag.go

@@ -0,0 +1,39 @@
+package socket
+
+import (
+	"sync"
+	"sync/atomic"
+)
+
+type (
+	NetRuntimeTag struct {
+		sync.Mutex
+		runState  int64
+		StopWg    sync.WaitGroup
+		CloseFlag bool
+	}
+)
+
+func (this *NetRuntimeTag) SetCloseFlag(b bool) {
+	this.Lock()
+	defer this.Unlock()
+	this.CloseFlag = b
+}
+
+func (this *NetRuntimeTag) GetCloseFlag() bool {
+	this.Lock()
+	defer this.Unlock()
+	return this.CloseFlag
+}
+
+func (this *NetRuntimeTag) SetRuneState(b bool) {
+	if b {
+		atomic.StoreInt64(&this.runState, 1)
+	} else {
+		atomic.StoreInt64(&this.runState, 0)
+	}
+}
+
+func (this *NetRuntimeTag) GetRuneState() bool {
+	return atomic.LoadInt64(&this.runState) != 0
+}

+ 131 - 0
RO_Server_Trunk-branch_0.1.39/rocommon/socket/sessionmanager.go

@@ -0,0 +1,131 @@
+package socket
+
+import (
+	"rocommon"
+	"rocommon/util"
+	"sync"
+	"sync/atomic"
+	"time"
+)
+
+//SessionMagExport interface
+type (
+	SessionManager interface {
+		rocommon.SessionMagExport
+
+		Add(rocommon.Session)
+		Remove(rocommon.Session)
+	}
+
+	NetSessionManager struct {
+		sessionIdGen int64
+		count        int64
+		sessionMap   sync.Map
+		genKey       int
+		timeKey      uint32
+
+		lastTimeStamp uint64
+		sequence      uint64
+	}
+)
+
+func NewNetSessionManager() *NetSessionManager {
+	mag := &NetSessionManager{
+		lastTimeStamp: util.GetTimeMilliseconds(),
+	}
+	return mag
+}
+
+//func (this *NetSessionManager) Add(s rocommon.Session) {
+//	id := atomic.AddInt64(&this.sessionIdGen, 1)
+//	atomic.AddInt64(&this.count, 1)
+//	if id >= math.MaxUint32 {
+//		id = 1
+//		atomic.StoreInt64(&this.sessionIdGen, 1)
+//	}
+//	uuid := this.uuidCreate(id)
+//	s.(interface{ SetID(uint642 uint64) }).SetID(uuid)
+//	this.sessionMap.Store(uuid, s)
+//}
+func (this *NetSessionManager) Add(s rocommon.Session) {
+	uuid := this.genSessionId()
+	s.(interface{ SetID(uint642 uint64) }).SetID(uuid)
+	//util.InfoF("NetSessionManager add uid=%v", uuid)
+	if _, ok := this.sessionMap.Load(uuid); ok {
+		util.ErrorF("NetSessionManager add multiple uid=%v", uuid)
+		panic(nil)
+	}
+	this.sessionMap.Store(uuid, s)
+}
+
+func (this *NetSessionManager) Remove(s rocommon.Session) {
+	this.sessionMap.Delete(s.ID())
+	s.(rocommon.ContextSet).SetContextData("user", nil, "MagRemove")
+	//if data,ok := s.(rocommon.ContextSet).SetContextData("user");ok {
+	//	if data != nil {
+	//		data.
+	//	}
+	//}
+	atomic.AddInt64(&this.count, -1)
+}
+
+func (this *NetSessionManager) GetSession(id uint64) rocommon.Session {
+	if s, ok := this.sessionMap.Load(id); ok {
+		return s.(rocommon.Session)
+	}
+	return nil
+}
+
+func (this *NetSessionManager) SessionNum() int {
+	return int(atomic.LoadInt64(&this.count))
+}
+
+func (this *NetSessionManager) CloseAllSession() {
+	this.sessionMap.Range(func(key, value interface{}) bool {
+		value.(rocommon.Session).Close()
+		return true
+	})
+}
+
+func (this *NetSessionManager) SetUuidCreateKey(genKey int) {
+	this.genKey = genKey
+	this.timeKey = uint32(time.Now().UnixNano())
+}
+
+func (this *NetSessionManager) uuidCreate(id int64) uint64 {
+	var uuid uint64 = 0
+	uuid |= uint64(uint64(this.genKey) << 32) //6位
+	uuid |= uint64(id) << 20
+	uuid |= uint64(this.timeKey) & 0xfffff
+
+	return uuid
+}
+func (this *NetSessionManager) genSessionId() uint64 {
+	currentTimeStamp := uint64(time.Now().Unix())
+	if this.lastTimeStamp == 0 {
+		this.lastTimeStamp = currentTimeStamp
+	}
+
+	if this.genKey > 0xff {
+		return 0
+	}
+	if this.lastTimeStamp == currentTimeStamp {
+		this.sequence++
+		if this.sequence > 0xffff {
+			//一秒内尝试的数量超过上限
+			return 0
+		}
+	} else {
+		this.lastTimeStamp = currentTimeStamp
+		this.sequence = 1
+	}
+
+	var uid uint64 = 0
+	//前32位时间戳(秒)
+	uid |= this.lastTimeStamp << 24
+	//16位序列号
+	uid |= uint64(this.sequence&0xffff) << 8
+	//左后是逻辑ID(服务器id)
+	uid |= uint64(this.genKey & 0xff)
+	return uid
+}

+ 117 - 0
RO_Server_Trunk-branch_0.1.39/rocommon/socket/socketoption.go

@@ -0,0 +1,117 @@
+package socket
+
+import (
+	"github.com/gorilla/websocket"
+	"math"
+	"net"
+	"time"
+)
+
+type SocketOption interface {
+	MaxMsgLen() int
+	SocketReadTimeout(c net.Conn, callback func())
+	SocketWriteTimeout(c net.Conn, callback func())
+	CopyOpt(opt *NetTCPSocketOption)
+	GetSocketDeadline() (time.Duration, time.Duration)
+}
+
+type NetTCPSocketOption struct {
+	readBufferSize  int
+	writeBufferSize int
+	readTimeout     time.Duration
+	writeTimeout    time.Duration
+
+	noDelay   bool
+	maxMsgLen int
+}
+
+func (this *NetTCPSocketOption) Init() {
+	//todo...
+	this.maxMsgLen = 1024 * 4 * 10 //40k(发送和接受字节最大数量)
+}
+
+func (this *NetTCPSocketOption) WriteTimeout() time.Duration {
+	return this.writeTimeout
+}
+
+func (this *NetTCPSocketOption) ReadTimeout() time.Duration {
+	return this.readTimeout
+}
+
+func (op *NetTCPSocketOption) SocketOpt(c net.Conn) {
+	if conn, ok := c.(*net.TCPConn); ok {
+		conn.SetNoDelay(op.noDelay)
+		conn.SetReadBuffer(op.readBufferSize)
+		conn.SetWriteBuffer(op.writeBufferSize)
+		//reuse addr
+		//todo...
+	}
+}
+func (op *NetTCPSocketOption) SocketOptWebSocket(c *websocket.Conn) {
+	if conn, ok := c.UnderlyingConn().(*net.TCPConn); ok {
+		conn.SetNoDelay(op.noDelay)
+		conn.SetReadBuffer(op.readBufferSize)
+		conn.SetWriteBuffer(op.writeBufferSize)
+		//reuse addr
+		//todo...
+	}
+}
+
+func (op *NetTCPSocketOption) MaxMsgLen() int {
+	return op.maxMsgLen
+}
+
+func (op *NetTCPSocketOption) SetMaxMsgLen(size int) {
+	op.maxMsgLen = size
+}
+
+//http://blog.sina.com.cn/s/blog_9be3b8f10101lhiq.html
+func (op *NetTCPSocketOption) SocketReadTimeout(c net.Conn, callback func()) {
+	if op.readTimeout > 0 {
+		c.SetReadDeadline(time.Now().Add(op.readTimeout))
+		callback()
+		c.SetReadDeadline(time.Time{})
+	} else {
+		callback()
+	}
+}
+
+func (op *NetTCPSocketOption) SocketWriteTimeout(c net.Conn, callback func()) {
+	if op.writeTimeout > 0 {
+		c.SetWriteDeadline(time.Now().Add(op.writeTimeout))
+		callback()
+		c.SetWriteDeadline(time.Time{})
+	} else {
+		callback()
+	}
+}
+
+func (op *NetTCPSocketOption) SetSocketBuff(read, write int, noDelay bool) {
+	op.readBufferSize = read
+	op.writeBufferSize = write
+	op.noDelay = noDelay
+	if read > 0 {
+		op.maxMsgLen = read
+	}
+	if op.maxMsgLen >= math.MaxUint16 {
+		op.maxMsgLen = math.MaxUint16
+	}
+}
+
+func (op *NetTCPSocketOption) SetSocketDeadline(read, write time.Duration) {
+	op.readTimeout = read
+	op.writeTimeout = write
+}
+
+func (op *NetTCPSocketOption) GetSocketDeadline() (time.Duration, time.Duration) {
+	return op.readTimeout, op.writeTimeout
+}
+
+func (op *NetTCPSocketOption) CopyOpt(opt *NetTCPSocketOption) {
+	//opt.writeTimeout = op.writeTimeout
+	//opt.readTimeout = op.readTimeout
+	opt.maxMsgLen = op.maxMsgLen
+	opt.noDelay = op.noDelay
+	opt.readBufferSize = op.readBufferSize
+	opt.writeBufferSize = op.writeBufferSize
+}

+ 111 - 0
RO_Server_Trunk-branch_0.1.39/rocommon/socket/tcp/acceptor.go

@@ -0,0 +1,111 @@
+package tcp
+
+import (
+	"context"
+	"log"
+	"net"
+	"rocommon"
+	"rocommon/socket"
+	"rocommon/util"
+	"time"
+)
+
+// 监听器实现(启动时可能会有多个连接器)
+type tcpAcceptor struct {
+	socket.NetRuntimeTag      //运行状态
+	socket.NetTCPSocketOption //socket相关设置
+	socket.NetProcessorRPC    //事件处理相关
+	socket.SessionManager     //会话管理
+	socket.NetServerNodeProperty
+	socket.NetContextSet
+
+	listener net.Listener
+}
+
+// //interface ServerNode
+func (this *tcpAcceptor) Start() rocommon.ServerNode {
+	//正在停止先等待
+	this.StopWg.Wait()
+	//防止重入导致错误
+	if this.GetRuneState() {
+		return this
+	}
+
+	//https://github.com/gogf/greuse/blob/master/greuse.go
+	var listenCfg = net.ListenConfig{Control: Control}
+	util.InfoF("tcpAcceptor GetAddr:%v", this.GetAddr())
+	ln, err := listenCfg.Listen(context.Background(), "tcp", this.GetAddr())
+	//ln, err := net.Listen("tcp", this.GetAddr())
+	if err != nil {
+		util.PanicF("tcpAcceptor listen failure=%v", err)
+	}
+
+	this.listener = ln
+	util.InfoF("tcpAcceptor listen success=%v", this.GetAddr())
+
+	go this.tcpAccept()
+	return this
+}
+
+func (this *tcpAcceptor) tcpAccept() {
+	this.SetRuneState(true)
+	for {
+		conn, err := this.listener.Accept()
+		util.InfoF("Accept successful:")
+		//结束中
+		if this.GetCloseFlag() {
+			break
+		}
+		if err != nil {
+			if ne, ok := err.(net.Error); ok && ne.Temporary() {
+				select {
+				case <-time.After(time.Millisecond): //尝试重新获取连接
+					continue
+				}
+			}
+			util.InfoF("[tcpAcceptor] accept err:%v", err)
+			break
+		}
+		util.InfoF("accept ok:%v", conn)
+		this.SocketOpt(conn) //option 设置
+		func() {
+			session := newTcpSession(conn, this, nil)
+			//util.InfoF("[tcpAcceptor] accept session:start:%v", session)
+			session.Start()
+			//通知上层事件(这边的回调要放到队列中,否则会有多线程冲突)
+			this.ProcEvent(&rocommon.RecvMsgEvent{Sess: session, Message: &rocommon.SessionAccepted{}})
+		}()
+	}
+	this.SetRuneState(false)
+	this.SetCloseFlag(false)
+	this.StopWg.Done()
+}
+
+func (this *tcpAcceptor) Stop() {
+	if !this.GetRuneState() {
+		return
+	}
+
+	this.StopWg.Add(1)
+	this.SetCloseFlag(true)
+	this.listener.Close()
+	//关闭当前监听服务器的所有连接
+	this.CloseAllSession()
+	//等待协程结束
+	this.StopWg.Wait()
+}
+
+func (this *tcpAcceptor) TypeOfName() string {
+	return "tcpAcceptor"
+}
+
+func init() {
+	log.Println("tcpAcceptor server node register")
+	socket.RegisterServerNode(func() rocommon.ServerNode {
+		node := &tcpAcceptor{
+			SessionManager: socket.NewNetSessionManager(),
+		}
+		node.NetTCPSocketOption.Init()
+		return node
+	})
+}

+ 151 - 0
RO_Server_Trunk-branch_0.1.39/rocommon/socket/tcp/connector.go

@@ -0,0 +1,151 @@
+package tcp
+
+import (
+	"log"
+	"net"
+	"rocommon"
+	"rocommon/service"
+	"rocommon/socket"
+	"rocommon/util"
+	"sync"
+	"time"
+)
+
+//连接器实现(启动时可能会有多个连接器)
+type tcpConnector struct {
+	socket.NetRuntimeTag      //运行状态
+	socket.NetTCPSocketOption //socket相关设置
+	socket.NetProcessorRPC    //事件处理相关
+	socket.NetServerNodeProperty
+	socket.SessionManager //会话管理
+	socket.NetContextSet
+
+	connNum       int //重连次数
+	reconnectTime time.Duration
+	wg            sync.WaitGroup
+
+	//连接会话
+	sess *tcpSession
+}
+
+func (c *tcpConnector) connect(addr string) {
+	c.SetRuneState(true) //true表示正在运行
+	for {
+		c.connNum++
+
+		if c.connNum > 1 {
+			var preDesc *service.ETCDServiceDesc
+			c.RawContextData("sid", &preDesc)
+			if preDesc != nil {
+				//preDesc 目标节点信息
+				util.DebugF("[tcpConnector] connect begin=%v sid=%v[%v]", addr, preDesc.ID, c.connNum-1)
+			}
+		}
+		conn, err := net.Dial("tcp", addr)
+		if err != nil {
+			//log.Println("dail err:", err)
+			if c.reconnectTime == 0 || c.GetCloseFlag() {
+				//连接出错事件
+				util.ErrorF("tcpConnector err=%v", err.Error())
+				c.ProcEvent(&rocommon.RecvMsgEvent{Sess: c.sess, Message: &rocommon.SessionConnectError{}, Err: err})
+				break
+			}
+
+			select {
+			case <-time.After(c.reconnectTime):
+				continue
+			}
+		}
+		if c.connNum > 1 {
+			var preDesc *service.ETCDServiceDesc
+			c.RawContextData("sid", &preDesc)
+			if preDesc != nil {
+				//preDesc 目标节点信息
+				util.DebugF("[tcpConnector] connect success:%v sid=%v[%v]", addr, preDesc.ID, c.connNum-1)
+			}
+		}
+		if c.GetCloseFlag() {
+			util.DebugF("[tcpConnector] connect success but be stoped by new node:%v [%v]", addr, c.connNum-1)
+			break
+		}
+
+		c.wg.Add(1)
+		//设置socket选项
+		c.SocketOpt(conn)
+		c.connNum = 0
+		c.sess.setConn(conn)
+		//放到session管理器中
+		c.sess.Start()
+		//连接事件
+		c.ProcEvent(&rocommon.RecvMsgEvent{Sess: c.sess, Message: &rocommon.SessionConnected{}})
+
+		c.wg.Wait()
+
+		c.sess.setConn(nil)
+		if c.reconnectTime == 0 || c.GetCloseFlag() {
+			break
+		}
+
+		//sleep reconnectTime
+		select {
+		case <-time.After(c.reconnectTime):
+			continue
+		}
+	}
+	c.SetRuneState(false)
+	//todo... 在调用stop后需要处理
+	if c.GetCloseFlag() {
+		c.StopWg.Done()
+	}
+	util.InfoF("connector stop...")
+}
+
+//interface ServerNode
+func (c *tcpConnector) Start() rocommon.ServerNode {
+	c.StopWg.Wait()
+	if c.GetRuneState() {
+		return c
+	}
+
+	go c.connect(c.GetAddr())
+	return c
+}
+
+func (c *tcpConnector) Stop() {
+	if !c.GetRuneState() {
+		return
+	}
+	c.SetCloseFlag(true)
+	c.StopWg.Add(1)
+	c.sess.Close()
+	c.StopWg.Wait()
+}
+
+func (c *tcpConnector) TypeOfName() string {
+	return "tcpConnector"
+}
+
+func (c *tcpConnector) Session() rocommon.Session {
+	return c.sess
+}
+
+func (c *tcpConnector) SetReconnectTime(delta time.Duration) {
+	//调试模式下重连不生效
+	if service.DebugMode {
+		return
+	}
+	c.reconnectTime = delta
+}
+
+func init() {
+	log.Println("tcpConnector server node register")
+	socket.RegisterServerNode(func() rocommon.ServerNode {
+		node := new(tcpConnector)
+		node.SessionManager = socket.NewNetSessionManager()
+		node.sess = newTcpSession(nil, node, func() {
+			node.wg.Done()
+		})
+		node.NetTCPSocketOption.Init()
+		return node
+	})
+}

+ 7 - 0
RO_Server_Trunk-branch_0.1.39/rocommon/socket/tcp/log.go

@@ -0,0 +1,7 @@
+package tcp
+
+import "log"
+
+func init() {
+	log.SetFlags(log.Llongfile | log.LstdFlags)
+}

+ 21 - 0
RO_Server_Trunk-branch_0.1.39/rocommon/socket/tcp/roreuse_linux.go

@@ -0,0 +1,21 @@
+package tcp
+
+import (
+	"golang.org/x/sys/unix"
+	"syscall"
+)
+
+func Control(network, addr string, c syscall.RawConn) (err error) {
+	ret := c.Control(func(fd uintptr) {
+		if err = unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_REUSEADDR, 1); err != nil {
+			panic(err)
+		}
+		if err = unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_REUSEPORT, 1); err != nil {
+			panic(err)
+		}
+	})
+	if ret != nil {
+		return ret
+	}
+	return
+}

+ 17 - 0
RO_Server_Trunk-branch_0.1.39/rocommon/socket/tcp/roreuse_windows.go

@@ -0,0 +1,17 @@
+package tcp
+
+import (
+	"syscall"
+)
+
+func Control(network, addr string, c syscall.RawConn) (err error) {
+	ret := c.Control(func(fd uintptr) {
+		if err = syscall.SetsockoptInt(syscall.Handle(fd), syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1); err != nil {
+			return
+		}
+	})
+	if ret != nil {
+		return ret
+	}
+	return
+}

+ 335 - 0
RO_Server_Trunk-branch_0.1.39/rocommon/socket/tcp/session.go

@@ -0,0 +1,335 @@
+package tcp
+
+import (
+	"net"
+	"rocommon"
+	"rocommon/socket"
+	"rocommon/util"
+	"runtime/debug"
+	"sync"
+	"sync/atomic"
+	"time"
+)
+
+type SessionIdentify struct {
+	id uint64
+}
+
+func (this *SessionIdentify) ID() uint64 {
+	return this.id
+}
+
+func (this *SessionIdentify) SetID(id uint64) {
+	this.id = id
+}
+
+//Session interface def.go
+type tcpSession struct {
+	sync.Mutex
+	SessionIdentify         //添加到SessionManager中时会设置tcpSession的ID属性
+	*socket.NetProcessorRPC //事件处理相关 procrpc.go
+	socket.NetContextSet    //记录session绑定信息 nodeproperty.go
+	node                    rocommon.ServerNode
+
+	//net.Conn
+	conn      net.Conn
+	sendQueue chan interface{}
+
+	exitWg      sync.WaitGroup
+	endCallback func()
+	closeInt    int64
+
+	aesMutex      sync.RWMutex
+	aesStr        []byte
+	handCodeMutex sync.RWMutex
+	handCodeStr   string
+
+	sessionOpt     socket.NetTCPSocketOption
+	optMutex       sync.RWMutex
+	sessionOptFlag bool //是否启用无读无写超时处理
+
+	sendQueueMaxLen int
+
+	recvPingNum int
+}
+
+func (this *tcpSession) GetSessionOpt() interface{} {
+	return &this.sessionOpt
+}
+func (this *tcpSession) GetSessionOptFlag() bool {
+	this.optMutex.RLock()
+	defer this.optMutex.RUnlock()
+
+	return this.sessionOptFlag
+}
+func (this *tcpSession) SetSessionOptFlag(flag bool) {
+	this.optMutex.Lock()
+	defer this.optMutex.Unlock()
+
+	this.sessionOptFlag = flag
+}
+
+func (this *tcpSession) setConn(c net.Conn) {
+	this.Lock()
+	defer this.Unlock()
+	this.conn = c
+}
+
+func (this *tcpSession) GetConn() net.Conn {
+	this.Lock()
+	defer this.Unlock()
+	return this.conn
+}
+
+func (this *tcpSession) Raw() interface{} {
+	return this.GetConn()
+}
+
+func (this *tcpSession) Node() rocommon.ServerNode {
+	return this.node
+}
+
+func (this *tcpSession) GetAES() *[]byte {
+	this.aesMutex.RLock()
+	defer this.aesMutex.RUnlock()
+	return &this.aesStr
+}
+
+func (this *tcpSession) SetAES(aes string) {
+	this.aesMutex.Lock()
+	defer this.aesMutex.Unlock()
+	this.aesStr = []byte(aes)
+	//log.Println("SetAES:", aes)
+}
+
+func (this *tcpSession) GetHandCode() string {
+	this.handCodeMutex.RLock()
+	defer this.handCodeMutex.RUnlock()
+	return this.handCodeStr
+}
+
+func (this *tcpSession) SetHandCode(code string) {
+	this.handCodeMutex.Lock()
+	defer this.handCodeMutex.Unlock()
+	this.handCodeStr = code
+	//log.Println("SetAES:", aes)
+}
+
+func (this *tcpSession) IncRecvPingNum(incNum int) {
+	if incNum <= 0 {
+		this.recvPingNum = incNum
+	} else {
+		this.recvPingNum += incNum
+	}
+}
+func (this *tcpSession) RecvPingNum() int {
+	return this.recvPingNum
+}
+
+var sendQueueMaxLen = 2000
+var sendQueuePool = sync.Pool{
+	New: func() interface{} {
+		return make(chan interface{}, sendQueueMaxLen+1)
+	},
+}
+
+func (this *tcpSession) Start() {
+	atomic.StoreInt64(&this.closeInt, 0)
+
+	//重置发送队列
+	this.sendQueueMaxLen = sendQueueMaxLen
+	if this.node.(rocommon.ServerNodeProperty).GetName() == "gate" {
+		this.sendQueueMaxLen = 200
+	}
+	this.sendQueue = make(chan interface{}, this.sendQueueMaxLen+1)
+	//this.sendQueue = make(chan interface{}, 32) //todo..暂时默认发送队列长度2000
+	//this.sendQueue = make(chan interface{}, sendQueueMaxLen+1) //todo..暂时默认发送队列长度2000
+	//this.sendQueue = sendQueuePool.Get().(chan interface{})
+
+	this.exitWg.Add(2)
+	//this.node tcpAcceptor
+	this.node.(socket.SessionManager).Add(this) //添加到session管理器中
+	if this.node.TypeOfName() == "tcpAcceptor" {
+
+		//log.Println("sessionMagNum:", this.node.(socket.SessionManager).SessionNum())
+	}
+	go func() {
+		this.exitWg.Wait()
+		//结束操作处理
+		close(this.sendQueue)
+		//sendQueuePool.Put(this.sendQueue)
+
+		this.node.(socket.SessionManager).Remove(this)
+		if this.endCallback != nil {
+			this.endCallback()
+		}
+		//debug.FreeOSMemory()
+	}()
+
+	go this.RunRecv()
+	go this.RunSend()
+}
+
+func (this *tcpSession) Close() {
+	//已经关闭
+	if ok := atomic.SwapInt64(&this.closeInt, 1); ok != 0 {
+		return
+	}
+
+	conn := this.GetConn()
+	if conn != nil {
+		conn.Close()
+		//关闭读
+		//conn.(*net.TCPConn).CloseRead()
+	}
+	//util.InfoF("close session")
+}
+
+func (this *tcpSession) Send(msg interface{}) {
+	//已经关闭
+	if atomic.LoadInt64(&this.closeInt) != 0 {
+		util.ErrorF("SendLen-sendQueue closeInt connId=%v", this.id)
+		return
+	}
+
+	//this.sendQueue <- msg
+
+	sendLen := len(this.sendQueue)
+	if sendLen < sendQueueMaxLen {
+		this.sendQueue <- msg
+		return
+	}
+	util.ErrorF("SendLen-sendQueue=%v addr=%v", sendLen, this.conn.LocalAddr())
+}
+
+//服务器进程之前启用ping操作
+func (this *tcpSession) HeartBeat(msg interface{}) {
+	//已经关闭
+	if atomic.LoadInt64(&this.closeInt) != 0 {
+		return
+	}
+
+	go func() {
+		tmpMsg := msg
+		delayTimer := time.NewTimer(15 * time.Second)
+		for {
+			delayTimer.Reset(5 * time.Second)
+			select {
+			case <-delayTimer.C:
+				if atomic.LoadInt64(&this.closeInt) != 0 {
+					break
+				}
+
+				this.Send(tmpMsg)
+				//util.InfoF("Send PingReq id=%v", this.ID())
+			}
+		}
+	}()
+}
+
+func (this *tcpSession) RunRecv() {
+	//util.DebugF("start RunRecv goroutine")
+	defer func() {
+		//打印奔溃信息
+		//if err := recover(); err != nil {
+		//	this.onError(err)
+		//}
+		//util.InfoF("Stack---:\n%s\n", string(debug.Stack()))
+		//打印堆栈信息
+		if err := recover(); err != nil {
+			debug.PrintStack()
+		}
+	}()
+
+	recvCount := 0
+	for {
+		msg, seqId, err := this.ReadMsg(this) //procrpc.go
+		if err != nil {
+			util.ErrorF("Readmsg-RunRecv error=%v sessionId=%v", err, this.ID())
+
+			//这边需要加锁,避免主线程继续在closInt还未设置成断开时还继续往session写数据,导致多线程冲突
+			//this.Lock()
+			//做关闭处理,发送数据时已经无法进行发送
+			atomic.StoreInt64(&this.closeInt, 1)
+			//close(this.sendQueue) //用来退出写协程
+			this.sendQueue <- nil //用来退出写协程
+			//this.Unlock()
+
+			//抛出错误事件
+			this.ProcEvent(&rocommon.RecvMsgEvent{Sess: this, Message: &rocommon.SessionClosed{}, Err: err})
+
+			//todo...或者通过关闭sendQueue来实现关闭
+			break
+		}
+		//接收数据事件放到队列中(需要放到队列中,否则会有线程冲突)
+		this.ProcEvent(&rocommon.RecvMsgEvent{Sess: this, Message: msg, Err: nil, MsgSeqId: seqId, KvTime: util.GetTimeMilliseconds()})
+		//this.ProcEvent(&rocommon.RecvMsgEvent{Sess: this, Message: msg, Err: nil, MsgSeqId: seqId})
+
+		recvCount++
+		if recvCount >= 100 {
+			recvCount = 0
+			//util.InfoF("RunRecv recCount sessionId=%v", this.ID())
+		}
+	}
+
+	util.DebugF("exit RunRecv goroutine addr=%v remoteAddr=%v id=%v", this.conn.LocalAddr(), this.conn.RemoteAddr(), this.id)
+	this.exitWg.Done()
+}
+
+func (this *tcpSession) RunSend() {
+	//util.DebugF("start RunSend goroutine")
+	defer func() {
+		//打印奔溃信息
+		//if err := recover(); err != nil {
+		//	this.onError(err)
+		//}
+		//util.InfoF("Stack---:\n%s\n", string(debug.Stack()))
+		//打印堆栈信息
+		if err := recover(); err != nil {
+			debug.PrintStack()
+		}
+	}()
+
+	sendCount := 0
+	//放到另外的队列中c
+	for data := range this.sendQueue {
+		if data == nil {
+			break
+		}
+		err := this.SendMsg(&rocommon.SendMsgEvent{Sess: this, Message: data})
+		//err := this.SendMsg(this, data) //procrpc.go
+		if err != nil {
+			util.ErrorF("SendMsg RunSend error %v", err)
+			break
+		}
+		sendCount++
+		if sendCount >= 100 {
+			sendCount = 0
+			//util.InfoF("RunSend sendCount sessionId=%v", this.ID())
+		}
+	}
+
+	util.DebugF("exit RunSend goroutine addr=%v remoteAddr=%v id=%v", this.conn.LocalAddr(), this.conn.RemoteAddr(), this.id)
+	c := this.GetConn()
+	if c != nil {
+		c.Close()
+	}
+
+	this.exitWg.Done()
+}
+
+///////////////////////
+//acceptor中获取到连接后创建session使用
+func newTcpSession(c net.Conn, node rocommon.ServerNode, endCallback func()) *tcpSession {
+	session := &tcpSession{
+		conn:        c,
+		node:        node,
+		endCallback: endCallback,
+		NetProcessorRPC: node.(interface {
+			GetRPC() *socket.NetProcessorRPC
+		}).GetRPC(), //使用外层node的RPC处理接口
+	}
+	node.(socket.SocketOption).CopyOpt(&session.sessionOpt)
+
+	return session
+}

+ 135 - 0
RO_Server_Trunk-branch_0.1.39/rocommon/socket/websocket/acceptor.go

@@ -0,0 +1,135 @@
+package websocket
+
+import (
+	"context"
+	"github.com/gorilla/websocket"
+	"log"
+	"net"
+	"net/http"
+	"rocommon"
+	"rocommon/socket"
+	"rocommon/util"
+)
+
+//监听器实现(启动时可能会有多个连接器)
+type tcpWebSocketAcceptor struct {
+	socket.NetRuntimeTag      //运行状态
+	socket.NetTCPSocketOption //socket相关设置
+	socket.NetProcessorRPC    //事件处理相关
+	socket.SessionManager     //会话管理
+	socket.NetServerNodeProperty
+	socket.NetContextSet
+
+	// 保存端口
+	listener net.Listener
+
+	certfile string
+	keyfile  string
+	upgrader *websocket.Upgrader
+	sv       *http.Server
+}
+
+func (this *tcpWebSocketAcceptor) TypeOfName() string {
+	return "wsAcceptor"
+}
+
+func (this *tcpWebSocketAcceptor) SetHttps(certfile, keyfile string) {
+	this.certfile = certfile
+	this.keyfile = keyfile
+}
+
+func (this *tcpWebSocketAcceptor) Start() rocommon.ServerNode {
+	//正在停止先等待
+	this.StopWg.Wait()
+	//防止重入导致错误
+	if this.GetRuneState() {
+		return this
+	}
+
+	//https://github.com/gogf/greuse/blob/master/greuse.go
+	var listenCfg = net.ListenConfig{Control: Control}
+	ln, err := listenCfg.Listen(context.Background(), "tcp", this.GetAddr())
+	//ln, err := net.Listen("tcp", this.GetAddr())
+	if err != nil {
+		util.PanicF("webSocketAcceptor listen failure=%v", err)
+	}
+
+	this.listener = ln
+	util.InfoF("webSocketAcceptor listen success=%v", this.GetAddr())
+
+	//process
+	//结束中
+	if this.GetCloseFlag() {
+		return this
+	}
+	this.SetRuneState(true)
+
+	mux := http.NewServeMux()
+	mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
+		conn, err := this.upgrader.Upgrade(w, r, nil)
+		if err != nil {
+			util.InfoF("[webSocketAcceptor] accept err=%v", err)
+			return
+		}
+
+		this.SocketOptWebSocket(conn) //option 设置
+		session := newWebSocketSession(conn, this, nil)
+		session.SetContextData("request", r, "newWebSocketSession") //获取request相关信息
+		//util.InfoF("[tcpAcceptor] accept session:start:%v", session)
+		session.Start()
+		//通知上层事件(这边的回调要放到队列中,否则会有多线程冲突)
+		this.ProcEvent(&rocommon.RecvMsgEvent{Sess: session, Message: &rocommon.SessionAccepted{}})
+	})
+
+	this.sv = &http.Server{Addr: this.GetAddr(), Handler: mux}
+	go func() {
+		util.InfoF("ws.listen(%s) %s", this.GetName(), this.GetAddr())
+
+		if this.certfile != "" && this.keyfile != "" {
+			err = this.sv.ServeTLS(this.listener, this.certfile, this.keyfile)
+		} else {
+			err = this.sv.Serve(this.listener)
+		}
+
+		//服务关闭时会打印
+		if err != nil {
+			util.ErrorF("ws.listen. failed(%s) %v", this.GetName(), err.Error())
+		}
+
+		this.SetRuneState(false)
+		this.SetCloseFlag(false)
+		this.StopWg.Done()
+	}()
+
+	return this
+}
+
+func (this *tcpWebSocketAcceptor) Stop() {
+	if !this.GetRuneState() {
+		return
+	}
+
+	this.StopWg.Add(1)
+	this.SetCloseFlag(true)
+	this.listener.Close()
+	//关闭当前监听服务器的所有连接
+	this.CloseAllSession()
+	//等待协程结束
+	this.StopWg.Wait()
+}
+
+func init() {
+	log.Println("webSocketAcceptor server node register")
+	socket.RegisterServerNode(func() rocommon.ServerNode {
+		node := &tcpWebSocketAcceptor{
+			SessionManager: socket.NewNetSessionManager(),
+			upgrader: &websocket.Upgrader{
+				CheckOrigin: func(r *http.Request) bool {
+					return true
+				},
+			},
+		}
+		node.NetTCPSocketOption.Init()
+		return node
+	})
+}

+ 132 - 0
RO_Server_Trunk-branch_0.1.39/rocommon/socket/websocket/connector.go

@@ -0,0 +1,132 @@
+package websocket
+
+import (
+	"github.com/gorilla/websocket"
+	"log"
+	"net/http"
+	"rocommon"
+	"rocommon/service"
+	"rocommon/socket"
+	"rocommon/util"
+	"sync"
+	"time"
+)
+
+//连接器实现(启动时可能会有多个连接器)
+type wsConnector struct {
+	socket.NetRuntimeTag      //运行状态
+	socket.NetTCPSocketOption //socket相关设置
+	socket.NetProcessorRPC    //事件处理相关
+	socket.NetServerNodeProperty
+	socket.SessionManager //会话管理
+	socket.NetContextSet
+
+	connNum       int //重连次数
+	reconnectTime time.Duration
+	wg            sync.WaitGroup
+
+	//连接会话
+	sess *wsSession
+}
+
+func (c *wsConnector) Start() rocommon.ServerNode {
+	c.StopWg.Wait()
+
+	if c.GetRuneState() {
+		return c
+	}
+
+	go c.connect(c.GetAddr())
+	return c
+}
+
+func (c *wsConnector) Stop() {
+	if !c.GetRuneState() {
+		return
+	}
+
+	c.StopWg.Add(1)
+	c.sess.Close()
+	c.SetCloseFlag(true)
+	c.StopWg.Wait()
+}
+func (c *wsConnector) TypeOfName() string {
+	return "wsConnector"
+}
+
+func (c *wsConnector) Session() rocommon.Session {
+	return c.sess
+}
+
+func (c *wsConnector) SetReconnectTime(delta time.Duration) {
+	//调试模式下重连不生效
+	if service.DebugMode {
+		return
+	}
+	c.reconnectTime = delta
+}
+
+func (c *wsConnector) connect(addr string) {
+	c.SetRuneState(true) //true表示正在运行
+	for {
+		c.connNum++
+
+		dialer := websocket.Dialer{}
+		dialer.Proxy = http.ProxyFromEnvironment
+		dialer.HandshakeTimeout = 60 * time.Second
+
+		conn, _, err := dialer.Dial(addr, nil)
+		if err != nil {
+			util.InfoF("dail err=%v", err)
+			if c.reconnectTime == 0 || c.GetCloseFlag() {
+				//todo... 连接出错事件
+				c.ProcEvent(&rocommon.RecvMsgEvent{Sess: c.sess, Message: &rocommon.SessionConnectError{}, Err: err})
+				break
+			}
+
+			select {
+			case <-time.After(c.reconnectTime):
+				continue
+			}
+		}
+		c.sess.setConn(conn)
+
+		c.wg.Add(1)
+		//设置socket选项
+		c.SocketOptWebSocket(conn)
+		c.connNum = 0
+		//放到session管理器中
+		c.sess.Start()
+		//连接事件
+		c.ProcEvent(&rocommon.RecvMsgEvent{Sess: c.sess, Message: &rocommon.SessionConnected{}})
+		c.wg.Wait()
+
+		c.sess.setConn(nil)
+		if c.reconnectTime == 0 || c.GetCloseFlag() {
+			break
+		}
+
+		//sleep reconnectTime
+		select {
+		case <-time.After(c.reconnectTime):
+			continue
+		}
+	}
+	c.SetRuneState(false)
+	//todo... 在调用stop后需要处理
+	//c.StopWg.Done()
+	util.InfoF("connector stop...")
+}
+
+func init() {
+	log.Println("wsConnector server node register")
+	socket.RegisterServerNode(func() rocommon.ServerNode {
+		node := new(wsConnector)
+		node.SessionManager = socket.NewNetSessionManager()
+		node.sess = newWebSocketSession(nil, node, func() {
+			node.wg.Done()
+		})
+		node.NetTCPSocketOption.Init()
+		return node
+	})
+}

+ 21 - 0
RO_Server_Trunk-branch_0.1.39/rocommon/socket/websocket/roreuse_linux.go

@@ -0,0 +1,21 @@
+package websocket
+
+import (
+	"golang.org/x/sys/unix"
+	"syscall"
+)
+
+func Control(network, addr string, c syscall.RawConn) (err error) {
+	ret := c.Control(func(fd uintptr) {
+		if err = unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_REUSEADDR, 1); err != nil {
+			panic(err)
+		}
+		if err = unix.SetsockoptInt(int(fd), unix.SOL_SOCKET, unix.SO_REUSEPORT, 1); err != nil {
+			panic(err)
+		}
+	})
+	if ret != nil {
+		return ret
+	}
+	return
+}

+ 17 - 0
RO_Server_Trunk-branch_0.1.39/rocommon/socket/websocket/roreuse_windows.go

@@ -0,0 +1,17 @@
+package websocket
+
+import (
+	"syscall"
+)
+
+func Control(network, addr string, c syscall.RawConn) (err error) {
+	ret := c.Control(func(fd uintptr) {
+		if err = syscall.SetsockoptInt(syscall.Handle(fd), syscall.SOL_SOCKET, syscall.SO_REUSEADDR, 1); err != nil {
+			return
+		}
+	})
+	if ret != nil {
+		return ret
+	}
+	return
+}

+ 287 - 0
RO_Server_Trunk-branch_0.1.39/rocommon/socket/websocket/session.go

@@ -0,0 +1,287 @@
+package websocket
+
+import (
+	"rocommon"
+	"rocommon/socket"
+	tcpBase "rocommon/socket/tcp"
+	"rocommon/util"
+	"runtime/debug"
+	"sync"
+	"sync/atomic"
+
+	"github.com/gorilla/websocket"
+)
+
+//Session interface def.go
+type wsSession struct {
+	sync.Mutex
+	tcpBase.SessionIdentify //添加到SessionManager中时会设置tcpSession的ID属性
+	*socket.NetProcessorRPC //事件处理相关 procrpc.go
+	socket.NetContextSet    //记录session绑定信息 nodeproperty.go
+	node                    rocommon.ServerNode
+
+	//net.Conn
+	conn      *websocket.Conn
+	sendQueue chan interface{}
+
+	exitWg      sync.WaitGroup
+	endCallback func()
+	closeInt    int64
+
+	aesMutex      sync.RWMutex
+	aesStr        []byte
+	handCodeMutex sync.RWMutex
+	handCodeStr   string
+
+	sessionOpt     socket.NetTCPSocketOption
+	optMutex       sync.RWMutex
+	sessionOptFlag bool //是否启用无读无写超时处理
+
+	sendQueueMaxLen int
+}
+
+func (this *wsSession) GetSessionOpt() interface{} {
+	return &this.sessionOpt
+}
+func (this *wsSession) GetSessionOptFlag() bool {
+	this.optMutex.RLock()
+	defer this.optMutex.RUnlock()
+
+	return this.sessionOptFlag
+}
+func (this *wsSession) SetSessionOptFlag(flag bool) {
+	this.optMutex.Lock()
+	defer this.optMutex.Unlock()
+
+	this.sessionOptFlag = flag
+}
+
+func (this *wsSession) setConn(c *websocket.Conn) {
+	this.Lock()
+	defer this.Unlock()
+	this.conn = c
+}
+
+func (this *wsSession) GetConn() *websocket.Conn {
+	this.Lock()
+	defer this.Unlock()
+	return this.conn
+}
+
+func (this *wsSession) Raw() interface{} {
+	return this.GetConn()
+}
+
+func (this *wsSession) Node() rocommon.ServerNode {
+	return this.node
+}
+
+func (this *wsSession) GetAES() *[]byte {
+	this.aesMutex.RLock()
+	defer this.aesMutex.RUnlock()
+	return &this.aesStr
+}
+
+func (this *wsSession) SetAES(aes string) {
+	this.aesMutex.Lock()
+	defer this.aesMutex.Unlock()
+	this.aesStr = []byte(aes)
+	//log.Println("SetAES:", aes)
+}
+
+func (this *wsSession) GetHandCode() string {
+	this.handCodeMutex.RLock()
+	defer this.handCodeMutex.RUnlock()
+	return this.handCodeStr
+}
+
+func (this *wsSession) SetHandCode(code string) {
+	this.handCodeMutex.Lock()
+	defer this.handCodeMutex.Unlock()
+	this.handCodeStr = code
+	//log.Println("SetAES:", aes)
+}
+func (this *wsSession) IncRecvPingNum(incNum int) {
+}
+func (this *wsSession) RecvPingNum() int {
+	return 0
+}
+
+var sendQueueMaxLen = 2000
+var sendQueuePool = sync.Pool{
+	New: func() interface{} {
+		return make(chan interface{}, sendQueueMaxLen+1)
+	},
+}
+
+func (this *wsSession) Start() {
+	atomic.StoreInt64(&this.closeInt, 0)
+
+	//重置发送队列
+	this.sendQueueMaxLen = sendQueueMaxLen
+	if this.node.(rocommon.ServerNodeProperty).GetName() == "gate" {
+		this.sendQueueMaxLen = 200
+	}
+	this.sendQueue = make(chan interface{}, this.sendQueueMaxLen+1)
+	//this.sendQueue = make(chan interface{}, 32) //todo..暂时默认发送队列长度2000
+	//this.sendQueue = make(chan interface{}, sendQueueMaxLen+1) //todo..暂时默认发送队列长度2000
+	//this.sendQueue = sendQueuePool.Get().(chan interface{})
+
+	this.exitWg.Add(2)
+	//this.node tcpAcceptor
+	this.node.(socket.SessionManager).Add(this) //添加到session管理器中
+	if this.node.TypeOfName() == "wsAcceptor" {
+
+		//log.Println("sessionMagNum:", this.node.(socket.SessionManager).SessionNum())
+	}
+	go func() {
+		this.exitWg.Wait()
+		//结束操作处理
+		close(this.sendQueue)
+		//sendQueuePool.Put(this.sendQueue)
+
+		this.node.(socket.SessionManager).Remove(this)
+		if this.endCallback != nil {
+			this.endCallback()
+		}
+		//debug.FreeOSMemory()
+	}()
+
+	go this.RunRecv()
+	go this.RunSend()
+}
+
+func (this *wsSession) Close() {
+	//已经关闭
+	if ok := atomic.SwapInt64(&this.closeInt, 1); ok != 0 {
+		return
+	}
+
+	conn := this.GetConn()
+	if conn != nil {
+		//conn.Close()
+		//关闭读
+		conn.Close()
+		conn.CloseHandler()
+	}
+	//util.InfoF("close session")
+}
+
+func (this *wsSession) Send(msg interface{}) {
+	//已经关闭
+	if atomic.LoadInt64(&this.closeInt) != 0 {
+		return
+	}
+
+	//this.sendQueue <- msg
+
+	sendLen := len(this.sendQueue)
+	if sendLen < sendQueueMaxLen {
+		this.sendQueue <- msg
+		return
+	}
+	util.ErrorF("SendLen-sendQueue=%v addr=%v", sendLen, this.conn.LocalAddr())
+}
+
+//服务器进程之前启用ping操作
+func (this *wsSession) HeartBeat(msg interface{}) {
+	//已经关闭
+	if atomic.LoadInt64(&this.closeInt) != 0 {
+		return
+	}
+}
+
+func (this *wsSession) RunRecv() {
+	// util.DebugF("start RunRecv goroutine")
+	defer func() {
+		//打印奔溃信息
+		//if err := recover(); err != nil {
+		//	this.onError(err)
+		//}
+		//util.InfoF("Stack---:\n%s\n", string(debug.Stack()))
+		//打印堆栈信息
+		if err := recover(); err != nil {
+			debug.PrintStack()
+		}
+	}()
+
+	for {
+		msg, seqId, err := this.ReadMsg(this) //procrpc.go
+		if err != nil {
+			util.ErrorF("Readmsg-RunRecv error=%v", err)
+
+			//这边需要加锁,避免主线程继续在closInt还未设置成断开时还继续往session写数据,导致多线程冲突
+			//this.Lock()
+			//做关闭处理,发送数据时已经无法进行发送
+			atomic.StoreInt64(&this.closeInt, 1)
+			//close(this.sendQueue) //用来退出写协程
+			this.sendQueue <- nil //用来退出写协程
+			//this.Unlock()
+
+			//抛出错误事件
+			this.ProcEvent(&rocommon.RecvMsgEvent{Sess: this, Message: &rocommon.SessionClosed{}, Err: err})
+
+			//todo...或者通过关闭sendQueue来实现关闭
+			break
+		}
+		//接收数据事件放到队列中(需要放到队列中,否则会有线程冲突)
+		this.ProcEvent(&rocommon.RecvMsgEvent{Sess: this, Message: msg, Err: nil, MsgSeqId: seqId, KvTime: util.GetTimeMilliseconds()})
+		//this.ProcEvent(&rocommon.RecvMsgEvent{Sess: this, Message: msg, Err: nil, MsgSeqId: seqId})
+	}
+
+	util.DebugF("exit RunRecv goroutine addr=%v", this.conn.LocalAddr())
+	this.exitWg.Done()
+}
+
+func (this *wsSession) RunSend() {
+	//util.DebugF("start RunSend goroutine")
+	defer func() {
+		//打印奔溃信息
+		//if err := recover(); err != nil {
+		//	this.onError(err)
+		//}
+		//util.InfoF("Stack---:\n%s\n", string(debug.Stack()))
+		//打印堆栈信息
+		if err := recover(); err != nil {
+			debug.PrintStack()
+		}
+	}()
+
+	//放到另外的队列中
+	for data := range this.sendQueue {
+		if data == nil {
+			break
+		}
+		err := this.SendMsg(&rocommon.SendMsgEvent{Sess: this, Message: data})
+		//err := this.SendMsg(this, data) //procrpc.go
+		if err != nil {
+			util.ErrorF("SendMsg RunSend error %v", err)
+			break
+		}
+	}
+
+	util.DebugF("exit RunSend goroutine addr=%v", this.conn.LocalAddr())
+	c := this.GetConn()
+	if c != nil {
+		c.Close()
+	}
+
+	this.exitWg.Done()
+}
+
+///////////////////////
+//acceptor中获取到连接后创建session使用
+
+func newWebSocketSession(conn *websocket.Conn, node rocommon.ServerNode, endCallback func()) *wsSession {
+	session := &wsSession{
+		conn:        conn,
+		node:        node,
+		endCallback: endCallback,
+		NetProcessorRPC: node.(interface {
+			GetRPC() *socket.NetProcessorRPC
+		}).GetRPC(), //使用外层node的RPC处理接口
+	}
+	node.(socket.SocketOption).CopyOpt(&session.sessionOpt)
+
+	return session
+}

+ 51 - 0
RO_Server_Trunk-branch_0.1.39/rocommon/syncrecv.go

@@ -0,0 +1,51 @@
+package rocommon
+
+import (
+	"sync"
+)
+
+type NetSyncRecv struct {
+	eventCh chan ProcEvent
+	cb      func(ev ProcEvent)
+	sess    Session
+}
+
+func NewNetSyncRecv(node ServerNode) *NetSyncRecv {
+	this := &NetSyncRecv{
+		eventCh: make(chan ProcEvent),
+	}
+	this.cb = func(ev ProcEvent) {
+		this.eventCh <- ev
+	}
+	return this
+}
+
+func (this *NetSyncRecv) EventCB() EventCallBack {
+	return this.cb
+}
+
+func (this *NetSyncRecv) Recv(cb EventCallBack) *NetSyncRecv {
+	cb(<-this.eventCh)
+	return this
+}
+
+func (this *NetSyncRecv) WaitMsg(msg interface{}) {
+	var wg sync.WaitGroup
+
+	wg.Add(1)
+	this.Recv(func(ev ProcEvent) {
+		//msgType := reflect.TypeOf(msg)
+		switch ev.Msg().(type) {
+		case *SessionConnected:
+			msg = ev.Msg()
+			this.sess = ev.Session()
+			wg.Done()
+		}
+	})
+	wg.Wait()
+	return
+}
+
+func (this *NetSyncRecv) Session() Session {
+	return this.sess
+}

+ 36 - 0
RO_Server_Trunk-branch_0.1.39/rocommon/sysmsg.go

@@ -0,0 +1,36 @@
+package rocommon
+
+import "fmt"
+
+// hooker中使用 上层消息队列通过该消息类型来确定当前是创建了连接
+//连接成功事件
+type SessionConnected struct {
+	ConnectedSId string
+}
+
+func (this *SessionConnected) String() string {
+	return fmt.Sprintf("%+v", *this)
+}
+
+//连接出错事件
+type SessionConnectError struct{}
+
+func (this *SessionConnectError) String() string {
+	return fmt.Sprintf("%+v", *this)
+}
+
+//接收其他服务器/客户端的连接
+type SessionAccepted struct{}
+
+func (this *SessionAccepted) String() string {
+	return fmt.Sprintf("%+v", *this)
+}
+
+//session关闭
+type SessionClosed struct {
+	CloseSId string
+}
+
+func (this *SessionClosed) String() string {
+	return fmt.Sprintf("%+v", *this)
+}

+ 77 - 0
RO_Server_Trunk-branch_0.1.39/rocommon/util/bitmap.go

@@ -0,0 +1,77 @@
+package util
+
+import "fmt"
+
+type BitMap struct {
+	bites  []byte
+	max    uint32
+	curNum int32
+}
+
+func NewBitMap(max uint32) *BitMap {
+	b := make([]byte, (max>>3)+1)
+	return &BitMap{bites: b, max: max}
+}
+
+func (this *BitMap) Add(num uint32) {
+	if this.max < num {
+		return
+	}
+	index := num >> 3
+	pos := num & 0x07
+	this.bites[index] |= 1 << pos
+
+	this.curNum++
+}
+
+func (this *BitMap) IsExist(num uint32) bool {
+	if this.max < num {
+		return false
+	}
+	index := num >> 3
+	pos := num & 0x07
+	return this.bites[index]&(1<<pos) != 0
+}
+func (this *BitMap) Remove(num uint32) {
+	if this.max < num {
+		return
+	}
+	index := num >> 3
+	pos := num & 0x07
+	this.bites[index] = this.bites[index] & ^(1 << pos)
+
+	this.curNum--
+}
+func (this *BitMap) Max() uint32 {
+	return this.max
+}
+func (this *BitMap) Bites() []byte {
+	return this.bites
+}
+
+//清空原先数据
+func (this *BitMap) SetBites(b []byte) {
+	this.bites = b
+	this.cntNumProcess()
+}
+func (this *BitMap) String() string {
+	return fmt.Sprint(this.bites)
+}
+func (this *BitMap) CurNum() int32 {
+	return this.curNum
+}
+func (this *BitMap) cntNumProcess() {
+	this.curNum = 0
+	for idx := 0; idx < len(this.bites); idx++ {
+		tmpVal := this.bites[idx]
+		for {
+			if tmpVal <= 0 {
+				break
+			}
+			if (tmpVal & 1) > 0 {
+				this.curNum++
+			}
+			tmpVal >>= 1
+		}
+	}
+}

+ 227 - 0
RO_Server_Trunk-branch_0.1.39/rocommon/util/dfa_filter.go

@@ -0,0 +1,227 @@
+package util
+
+import "strings"
+
+const (
+	INIT_TRIE_CHILDREN_NUM = 128 // Since we need to deal all kinds of language, so we use 128 instead of 26
+)
+
+// trieNode data structure
+// trieNode itself doesn't have any value. The value is represented on the path
+type trieNode struct {
+	// if this node is the end of a word
+	isEndOfWord bool
+
+	// the collection of children of this node
+	children map[rune]*trieNode
+}
+
+// Create new trieNode
+func newtrieNode() *trieNode {
+	return &trieNode{
+		isEndOfWord: false,
+		children:    make(map[rune]*trieNode, INIT_TRIE_CHILDREN_NUM),
+	}
+}
+
+// Match index object
+type matchIndex struct {
+	start int // start index
+	end   int // end index
+}
+
+// Construct from scratch
+func newMatchIndex(start, end int) *matchIndex {
+	return &matchIndex{
+		start: start,
+		end:   end,
+	}
+}
+
+// Construct from existing match index object
+func buildMatchIndex(obj *matchIndex) *matchIndex {
+	return &matchIndex{
+		start: obj.start,
+		end:   obj.end,
+	}
+}
+
+// dfa util
+type DFAUtil struct {
+	// The root node
+	root *trieNode
+}
+
+func (this *DFAUtil) insertWord(word []rune) {
+	currNode := this.root
+	for _, c := range word {
+		if cildNode, exist := currNode.children[c]; !exist {
+			cildNode = newtrieNode()
+			currNode.children[c] = cildNode
+			currNode = cildNode
+		} else {
+			currNode = cildNode
+		}
+	}
+
+	currNode.isEndOfWord = true
+}
+
+// Check if there is any word in the trie that starts with the given prefix.
+func (this *DFAUtil) startsWith(prefix []rune) bool {
+	currNode := this.root
+	for _, c := range prefix {
+		if cildNode, exist := currNode.children[c]; !exist {
+			return false
+		} else {
+			currNode = cildNode
+		}
+	}
+
+	return true
+}
+
+// Searc and make sure if a word is existed in the underlying trie.
+func (this *DFAUtil) searcWord(word []rune) bool {
+	currNode := this.root
+	for _, c := range word {
+		if cildNode, exist := currNode.children[c]; !exist {
+			return false
+		} else {
+			currNode = cildNode
+		}
+	}
+
+	return currNode.isEndOfWord
+}
+
+// Searc a whole sentence and get all the matcing words and their indices
+// Return:
+// A list of all the matc index object
+func (this *DFAUtil) searcSentence(sentence string) (matchIndexList []*matchIndex) {
+	start, end := 0, 1
+	sentenceRuneList := []rune(sentence)
+
+	// Iterate the sentence from the beginning to the end.
+	startsWith := false
+	for end <= len(sentenceRuneList) {
+		// Check if a sensitive word starts with word range from [start:end)
+		// We find the longest possible path
+		// Then we check any sub word is the sensitive word from long to short
+		if this.startsWith(sentenceRuneList[start:end]) {
+			startsWith = true
+			end += 1
+		} else {
+			if startsWith == true {
+				// Check any sub word is the sensitive word from long to short
+				for index := end - 1; index > start; index-- {
+					if this.searcWord(sentenceRuneList[start:index]) {
+						matchIndexList = append(matchIndexList, newMatchIndex(start, index-1))
+						break
+					}
+				}
+			}
+			start, end = end-1, end+1
+			startsWith = false
+		}
+	}
+
+	// If finishing not because of unmatching, but reaching the end, we need to
+	// check if the previous startsWith is true or not.
+	// If it's true, we need to check if there is any candidate?
+	if startsWith {
+		for index := end - 1; index > start; index-- {
+			if this.searcWord(sentenceRuneList[start:index]) {
+				matchIndexList = append(matchIndexList, newMatchIndex(start, index-1))
+				break
+			}
+		}
+	}
+
+	return
+}
+
+// Judge if input sentence contains some special caracter
+// Return:
+// Matc or not
+func (this *DFAUtil) IsMatch(sentence string) bool {
+	sentence = strings.TrimSpace(sentence)
+	sentence = strings.Replace(sentence, " ", "", -1)
+	sentence = strings.Replace(sentence, "&", "", -1)
+	return len(this.searcSentence(sentence)) > 0
+}
+
+// Handle sentence. Use specified caracter to replace those sensitive caracters.
+// input: Input sentence
+// replaceCh: candidate
+// Return:
+// Sentence after manipulation
+func (this *DFAUtil) HandleWord(sentence string, replaceCh rune) string {
+	sentence1 := sentence
+	sentence = strings.TrimSpace(sentence)
+	sentence = strings.Replace(sentence, " ", "", -1)
+	sentence = strings.Replace(sentence, "&", "", -1)
+	matchIndexList := this.searcSentence(sentence)
+	if len(matchIndexList) == 0 {
+		return sentence1
+	}
+
+	// Manipulate
+	sentenceList := []rune(sentence)
+	for _, matchIndexObj := range matchIndexList {
+		for index := matchIndexObj.start; index <= matchIndexObj.end; index++ {
+			sentenceList[index] = replaceCh
+		}
+	}
+
+	return string(sentenceList)
+}
+
+// Create new DfaUtil object
+// wordList:word list
+func NewDFAUtil(wordList []string) *DFAUtil {
+	this := &DFAUtil{
+		root: newtrieNode(),
+	}
+
+	for _, word := range wordList {
+		wordRuneList := []rune(word)
+		if len(wordRuneList) > 0 {
+			this.insertWord(wordRuneList)
+		}
+	}
+
+	return this
+}
+
+func DFAInsertWord(dfa *DFAUtil, wordList []string) {
+	for _, word := range wordList {
+		wordRuneList := []rune(word)
+		if len(wordRuneList) > 0 {
+			dfa.insertWord(wordRuneList)
+		}
+	}
+}
+
+//
+//func TestIsMatch(t *testing.T) {
+//	sensitiveList := []string{"中国", "中国人"}
+//	input := "我来自中国cd"
+//
+//	util := NewDFAUtil(sensitiveList)
+//	if util.IsMatch(input) == false {
+//		t.Errorf("Expected true, but got false")
+//	}
+//}
+//
+//func TestHandleWord(t *testing.T) {
+//	sensitiveList := []string{"中国", "中国人"}
+//	input := "我来自中国cd"
+//
+//	util := NewDFAUtil(sensitiveList)
+//	newInput := util.HandleWord(input, '*')
+//	expected := "我来自**cd"
+//	if newInput != expected {
+//		t.Errorf("Expected %s, but got %s", expected, newInput)
+//	}
+//}

+ 38 - 0
RO_Server_Trunk-branch_0.1.39/rocommon/util/ioutil.go

@@ -0,0 +1,38 @@
+package util
+
+import (
+	"io"
+	"reflect"
+	"unsafe"
+)
+
+func WriteFull(writer io.Writer, buf []byte) error {
+	total := len(buf)
+	for pos := 0; pos < total; {
+		n, err := writer.Write(buf[pos:])
+		if err != nil {
+			return err
+		}
+		pos += n
+	}
+	return nil
+}
+
+func String2Bytes(s string) []byte {
+	stringHeader := (*reflect.StringHeader)(unsafe.Pointer(&s))
+	bh := reflect.SliceHeader{
+		Data: stringHeader.Data,
+		Len:  stringHeader.Len,
+		Cap:  stringHeader.Len,
+	}
+	return *(*[]byte)(unsafe.Pointer(&bh))
+}
+
+func Bytes2String(b []byte) string {
+	sliceHeader := (*reflect.SliceHeader)(unsafe.Pointer(&b))
+	sh := reflect.StringHeader{
+		Data: sliceHeader.Data,
+		Len:  sliceHeader.Len,
+	}
+	return *(*string)(unsafe.Pointer(&sh))
+}

+ 299 - 0
RO_Server_Trunk-branch_0.1.39/rocommon/util/loghelper.go

@@ -0,0 +1,299 @@
+package util
+
+import (
+	"bytes"
+	"log"
+	"os"
+	"runtime"
+	"strconv"
+	"sync"
+	"time"
+)
+
+const (
+	Trace = iota
+	Debug
+	Info
+	Warning
+	Error
+	Fatal
+)
+const Max_File_Bites = 1024 * 1024 * 500 //500M
+
+var logger *log.Logger
+var uniLogger *log.Logger
+
+//var (
+//	logMu          sync.Mutex
+//	path           string = "./log"
+//	prefix         string
+//	fileName       string
+//	uniLogFileName string
+//	level          int
+//	fileLogging    *os.File
+//	fileIndex      int
+//	logMaxSize     int64
+//)
+
+type LogStInfo struct {
+	logMu       sync.Mutex
+	path        string
+	prefix      string
+	fileName    string
+	level       int
+	fileLogging *os.File
+	fileIndex   int
+	logMaxSize  int64
+}
+
+var commonLogInfo *LogStInfo
+var uniLogInfo *LogStInfo
+
+func logFileName(index int, info *LogStInfo) string {
+	//format格式説明https://segmentfault.com/q/1010000010976398/a-1020000010982052
+	if index == 0 {
+		loc := GetLoc()
+		strbuf := bytes.NewBufferString(info.path)
+		strbuf.WriteString("/")
+		strbuf.WriteString(info.prefix)
+		strbuf.WriteString(time.Now().In(loc).Format("2006010215"))
+		strbuf.WriteString(".log")
+		return strbuf.String()
+		//return fmt.Sprintf("%v/%v%v.log", path, prefix, time.Now().Format("2006010215"))
+	} else {
+		loc := GetLoc()
+		strbuf := bytes.NewBufferString(info.path)
+		strbuf.WriteString("/")
+		strbuf.WriteString(info.prefix)
+		strbuf.WriteString(time.Now().In(loc).Format("2006010215"))
+		strbuf.WriteString("_")
+		strbuf.WriteString(strconv.Itoa(index))
+		strbuf.WriteString(".log")
+		return strbuf.String()
+
+		//return fmt.Sprintf("%v/%v%v_%v.log", path, prefix, time.Now().Format("2006010215"),index)
+	}
+}
+
+func pathExist(path string) (bool, error) {
+	_, err := os.Stat(path)
+	ret := err == nil
+	if err != nil && os.IsNotExist(err) {
+		err = nil
+	}
+	return ret, nil
+}
+
+func InitLog(logLevel, maxSize int, pathStr, prefixStr string, uniPathStr string) error {
+	if pathStr != "" {
+		if ret, err := pathExist(pathStr); !ret {
+			if err != nil {
+				return err
+			}
+			err := os.MkdirAll(pathStr, os.ModePerm)
+			if err != nil {
+				return err
+			}
+		}
+	}
+	if uniPathStr != "" {
+		if ret, err := pathExist(uniPathStr); !ret {
+			if err != nil {
+				return err
+			}
+			err := os.MkdirAll(uniPathStr, os.ModePerm)
+			if err != nil {
+				return err
+			}
+		}
+	}
+
+	commonLogInfo = &LogStInfo{}
+	commonLogInfo.path = pathStr
+	commonLogInfo.prefix = prefixStr
+	commonLogInfo.level = logLevel
+	commonLogInfo.fileName = logFileName(0, commonLogInfo)
+	commonLogInfo.fileIndex = 0
+	commonLogInfo.logMaxSize = int64(maxSize) * 1024 * 1024
+	if commonLogInfo.logMaxSize <= 0 {
+		commonLogInfo.logMaxSize = Max_File_Bites
+	}
+
+	uniLogInfo = &LogStInfo{}
+	uniLogInfo.path = uniPathStr
+	uniLogInfo.prefix = "gamestatistic_" + prefixStr
+	uniLogInfo.fileName = logFileName(0, uniLogInfo)
+	uniLogInfo.fileIndex = 0
+	uniLogInfo.logMaxSize = int64(maxSize) * 1024 * 1024
+	if uniLogInfo.logMaxSize <= 0 {
+		uniLogInfo.logMaxSize = Max_File_Bites
+	}
+	//path = pathStr
+	//prefix = prefixStr
+	//level = logLevel
+	//fileName = logFileName(0)
+	//fileIndex = 0
+	//logMaxSize = int64(maxSize) * 1024 * 1024
+	//if logMaxSize <= 0 {
+	//	logMaxSize = Max_File_Bites
+	//}
+
+	newLogger()
+	if uniPathStr != "" {
+		newUniLogger()
+	}
+	return nil
+}
+
+func newLogger() {
+	var err error = nil
+	commonLogInfo.fileLogging, err = os.OpenFile(commonLogInfo.fileName, os.O_CREATE|os.O_RDWR|os.O_APPEND, 0644)
+	//fileLogging, err = os.OpenFile(fileName, os.O_CREATE|os.O_RDWR|os.O_APPEND, 0660)
+	if err != nil {
+		panic(err)
+	}
+	logger = log.New(commonLogInfo.fileLogging, "", log.LstdFlags)
+}
+func newUniLogger() {
+	var err error = nil
+	uniLogInfo.fileLogging, err = os.OpenFile(uniLogInfo.fileName, os.O_CREATE|os.O_RDWR|os.O_APPEND, 0644)
+	//fileLogging, err = os.OpenFile(uniLogFileName, os.O_CREATE|os.O_RDWR|os.O_APPEND, 0660)
+	if err != nil {
+		panic(err)
+	}
+	uniLogger = log.New(uniLogInfo.fileLogging, "", log.LUTC)
+}
+
+func DebugF(fmt string, v ...interface{}) {
+	writeLog(commonLogInfo, Debug, fmt, v...)
+}
+func InfoF(fmt string, v ...interface{}) {
+	writeLog(commonLogInfo, Info, fmt, v...)
+}
+func WarnF(fmt string, v ...interface{}) {
+	writeLog(commonLogInfo, Warning, fmt, v...)
+}
+func ErrorF(fmt string, v ...interface{}) {
+	writeLog(commonLogInfo, Error, fmt, v...)
+}
+func FatalF(fmt string, v ...interface{}) {
+	writeLog(commonLogInfo, Fatal, fmt, v...)
+}
+func PanicF(fmt string, v ...interface{}) {
+	writeLog(commonLogInfo, Fatal, fmt, v...)
+	panic(v)
+}
+func SpecialF(fmt string, v ...interface{}) {
+	specialWriteLog(uniLogInfo, Info, fmt, v...)
+}
+
+func writeLog(info *LogStInfo, logLevel int, logFmt string, v ...interface{}) {
+	if logLevel < info.level {
+		return
+	}
+
+	info.logMu.Lock()
+	newFileName := logFileName(0, info)
+	if info.fileName != newFileName {
+		if info.fileLogging != nil {
+			info.fileLogging.Close()
+		}
+		info.fileName = newFileName
+		info.fileIndex = 0
+		newLogger()
+	} else {
+		for {
+			fi, err := info.fileLogging.Stat()
+			if err == nil {
+				if fi.Size() >= info.logMaxSize {
+					info.fileIndex++
+					info.fileLogging.Close()
+					info.fileName = logFileName(info.fileIndex, info)
+					newLogger()
+				} else {
+					break
+				}
+			} else {
+				break
+			}
+		}
+	}
+	//info.logMu.Unlock()
+
+	switch logLevel {
+	case Trace:
+		logger.SetPrefix("[TRACE] ")
+	case Debug:
+		logger.SetPrefix("[DEBUG] ")
+	case Info:
+		logger.SetPrefix("[INFO] ")
+	case Warning:
+		logger.SetPrefix("[WARN] ")
+	case Error:
+		logger.SetPrefix("[ERROR] ")
+	case Fatal:
+		logger.SetPrefix("[FATAL] ")
+	}
+	info.logMu.Unlock()
+
+	_, file, line, ok := runtime.Caller(2)
+	if !ok {
+		file = "???"
+		line = 0
+	}
+	//logMu.Lock()
+
+	strbuf := bytes.NewBufferString(file)
+	strbuf.WriteString(":")
+	strbuf.WriteString(strconv.Itoa(line))
+	strbuf.WriteString(" ")
+	strbuf.WriteString(logFmt)
+	logFmt = strbuf.String()
+
+	//logFmt = fmt.Sprintf("%v:%v %v",file, line, logFmt)
+
+	//logMu.Unlock()
+	logger.Printf(logFmt, v...)
+
+	//for console
+	//log.SetPrefix(logger.Prefix())
+	log.Printf(logFmt, v...)
+}
+
+func specialWriteLog(info *LogStInfo, logLevel int, logFmt string, v ...interface{}) {
+	if info.path == "" {
+		return
+	}
+	info.logMu.Lock()
+	newFileName := logFileName(0, info)
+	if info.fileName != newFileName {
+		if info.fileLogging != nil {
+			info.fileLogging.Close()
+		}
+		info.fileName = newFileName
+		info.fileIndex = 0
+		newUniLogger()
+	} else {
+		for {
+			fi, err := info.fileLogging.Stat()
+			if err == nil {
+				if fi.Size() >= info.logMaxSize {
+					info.fileIndex++
+					info.fileLogging.Close()
+					info.fileName = logFileName(info.fileIndex, info)
+					newUniLogger()
+				} else {
+					break
+				}
+			} else {
+				break
+			}
+		}
+	}
+	info.logMu.Unlock()
+
+	uniLogger.SetPrefix("")
+	uniLogger.Printf(logFmt, v...)
+
+	log.Printf(logFmt, v...)
+}

+ 388 - 0
RO_Server_Trunk-branch_0.1.39/rocommon/util/timer.go

@@ -0,0 +1,388 @@
+package util
+
+import (
+	"time"
+)
+
+//定时器接口
+type ServerTimer interface {
+	//测试是否过期
+	IsExpired(ms uint64) bool
+
+	//重置
+	Reset(ms uint64, duration time.Duration, fireNow bool)
+
+	Cancel()
+	Canceled() bool
+
+	Suspend()
+	Resume()
+	IsStart() bool
+}
+
+const DATE_FORMAT = "2006-01-02 15:04:05"
+const DATE_FORMAT_T = "2006-01-02T15:04:05"
+const DATE_FORMAT1 = "2006-01-02"
+const DATE_FORMAT2 = "15:04:05"
+const DATE_FORMAT3 = "15:04"
+
+var gameLoc *time.Location = nil
+
+func GetLoc() *time.Location {
+	if gameLoc == nil {
+		loc, err := time.LoadLocation("Asia/Shanghai")
+		if err != nil {
+			gameLoc = time.Local
+		} else {
+			gameLoc = loc
+		}
+	}
+	return gameLoc
+}
+
+//return ms
+func GetCurrentTime() uint64 {
+	t1 := GetCurrentTimeNow()
+	return uint64(t1.UnixNano() / 1e6)
+}
+func GetCurrentTimeNow() time.Time {
+	loc := GetLoc()
+	t1 := time.Now()
+	return t1.In(loc)
+}
+func GetTimeMilliseconds() uint64 {
+	return GetCurrentTime()
+}
+func GetTimeSeconds() int64 {
+	return GetCurrentTimeNow().Unix()
+}
+
+func GetTimeByStr(timeStr string) time.Time {
+	tempTime, _ := time.ParseInLocation(DATE_FORMAT, timeStr, GetLoc())
+	return tempTime
+}
+func GetTimeByUint64(uTime uint64) time.Time {
+	timeS := int64(uTime / 1000)
+	timeMS := int64(uTime % 1000)
+	return time.Unix(timeS, timeMS).In(GetLoc())
+}
+func GetTimeByUint32(uTime uint32) time.Time {
+	return time.Unix(int64(uTime), 0).In(GetLoc())
+}
+func GetHourByTime(uTime uint64) time.Time {
+	loc := GetLoc()
+	if uTime <= 0 {
+		tempTimeStr := GetCurrentTimeNow().Format(DATE_FORMAT2)
+		tempTime, _ := time.ParseInLocation(DATE_FORMAT2, tempTimeStr, loc)
+		return tempTime
+	} else {
+		tempTimeStr := GetTimeByUint64(uTime).Format(DATE_FORMAT2)
+		tempTime, _ := time.ParseInLocation(DATE_FORMAT2, tempTimeStr, loc)
+		return tempTime
+	}
+}
+
+func GetHourByTimeStr(timeStr string) string {
+	loc := GetLoc()
+	tempTime, _ := time.ParseInLocation(DATE_FORMAT, timeStr, loc)
+	tempTime1 := tempTime.Format(DATE_FORMAT2)
+	return tempTime1
+}
+func GetHourByTimeStr1(timeStr string) time.Time {
+	loc := GetLoc()
+	hTime, _ := time.ParseInLocation(DATE_FORMAT2, timeStr, loc)
+	return hTime
+}
+func GetDayByTimeStr(timeStr string) string {
+	loc := GetLoc()
+	sTime, _ := time.ParseInLocation(DATE_FORMAT, timeStr, loc)
+	return sTime.Format(DATE_FORMAT1)
+}
+func GetDayByTimeStr1(timeStr string) time.Time {
+	loc := GetLoc()
+	dTime, _ := time.ParseInLocation(DATE_FORMAT1, timeStr, loc)
+	return dTime
+}
+func GetDayByTimeStr2(timeMs uint64) time.Time {
+	loc := GetLoc()
+	tempTimeStr := GetTimeByUint64(timeMs).Format(DATE_FORMAT1)
+	tempTime, _ := time.ParseInLocation(DATE_FORMAT1, tempTimeStr, loc)
+	return tempTime
+}
+func GetDayAndHourByTimeStr(timeStr string) (string, string) {
+	loc := GetLoc()
+	tempTime, _ := time.ParseInLocation(DATE_FORMAT, timeStr, loc)
+	hourStr := tempTime.Format(DATE_FORMAT2)
+	dayStr := tempTime.Format(DATE_FORMAT1)
+	return dayStr, hourStr
+}
+func GetDayAndHourByTime(timeStr string) (time.Time, time.Time) {
+	loc := GetLoc()
+	tempTime, _ := time.ParseInLocation(DATE_FORMAT, timeStr, loc)
+	dayStr := tempTime.Format(DATE_FORMAT1)
+	d, _ := time.ParseInLocation(DATE_FORMAT1, dayStr, loc)
+	hourStr := tempTime.Format(DATE_FORMAT2)
+	h, _ := time.ParseInLocation(DATE_FORMAT2, hourStr, loc)
+	return d, h
+}
+
+//获取最近一天5点更新时间(结束时间戳)
+func GetLatest5Hour() uint64 {
+	loc := GetLoc()
+	nowTime := GetCurrentTimeNow()
+	if nowTime.Hour() < 5 {
+		dayTimeStr := nowTime.Format(DATE_FORMAT1)
+		tempDayTime, _ := time.ParseInLocation(DATE_FORMAT1, dayTimeStr, loc)
+		tempDayTime = tempDayTime.Add(time.Hour * 5)
+
+		return uint64(tempDayTime.UnixNano() / 1e6)
+	} else {
+		dayTimeStr := nowTime.Format(DATE_FORMAT1)
+		tempDayTime, _ := time.ParseInLocation(DATE_FORMAT1, dayTimeStr, loc)
+		tempDayTime = tempDayTime.Add(time.Hour * 24)
+
+		dayTimeStr = tempDayTime.Format(DATE_FORMAT1)
+		tempDayTime, _ = time.ParseInLocation(DATE_FORMAT1, dayTimeStr, loc)
+		tempDayTime = tempDayTime.Add(time.Hour * 5)
+		return uint64(tempDayTime.UnixNano() / 1e6)
+	}
+}
+
+//获取最近周一5点更新时间(结束时间戳)
+func GetLatestWeek5Hour(ms uint64) uint64 {
+	loc := GetLoc()
+	nowTime := GetCurrentTimeNow()
+	if ms > 0 {
+		nowTime = GetTimeByUint64(ms)
+	}
+	curWeekDay := nowTime.Weekday()
+	if curWeekDay == 0 {
+		curWeekDay = 7
+	}
+	delDay := 7 - curWeekDay + 1
+	if curWeekDay == 1 {
+		if nowTime.Hour() >= 5 {
+			delDay = 7
+		} else {
+			delDay = 0
+		}
+	}
+
+	nowTime = nowTime.AddDate(0, 0, int(delDay))
+	dayTimeStr := nowTime.Format(DATE_FORMAT1)
+	tempDayTime, _ := time.ParseInLocation(DATE_FORMAT1, dayTimeStr, loc)
+	tempDayTime = tempDayTime.Add(time.Hour * 5)
+	return uint64(tempDayTime.UnixNano() / 1e6)
+}
+
+func GetLatestMonth5Hour() uint64 {
+	loc := GetLoc()
+	nowTime := GetCurrentTimeNow()
+	year, month, day := nowTime.Date()
+
+	//如果是每个月的1号5点之前
+	if day == 1 && nowTime.Hour() < 5 {
+		return GetLatest5Hour()
+	}
+
+	//如果是一个月的1号5点之后
+	thisMonth := time.Date(year, month, 1, 0, 0, 0, 0, time.Local)
+	nextMonth := thisMonth.AddDate(0, 1, 0)
+	dayTimeStr := nextMonth.Format(DATE_FORMAT1)
+
+	tempDayTime, _ := time.ParseInLocation(DATE_FORMAT1, dayTimeStr, loc)
+	tempDayTime = tempDayTime.Add(time.Hour * 5)
+	return uint64(tempDayTime.UnixNano() / 1e6)
+}
+
+//获取两个时间的持续天数
+func GetDurationDay(t1, t2 string) int64 {
+	loc := GetLoc()
+	t1DayStr := GetDayByTimeStr(t1)
+	t2DayStr := GetDayByTimeStr(t2)
+
+	sTime1, _ := time.ParseInLocation(DATE_FORMAT1, t1DayStr, loc)
+	eTime1, _ := time.ParseInLocation(DATE_FORMAT1, t2DayStr, loc)
+	return eTime1.Unix() - sTime1.Unix()
+}
+
+//t1, t2 (ms) t2 > t1
+func GetDurationDay1(t1, t2 uint64) int32 {
+	loc := GetLoc()
+	tmpT1 := GetTimeByUint64(t1)
+	tmpT2 := GetTimeByUint64(t2)
+
+	dayT1Str := tmpT1.Format(DATE_FORMAT1)
+	dayT1, _ := time.ParseInLocation(DATE_FORMAT1, dayT1Str, loc)
+	dayT2Str := tmpT2.Format(DATE_FORMAT1)
+	dayT2, _ := time.ParseInLocation(DATE_FORMAT1, dayT2Str, loc)
+	return int32(dayT2.Sub(dayT1).Hours() / 24)
+}
+
+//以5点位分割线 t2 > t1
+func GetDurationDay2(t1, t2 uint64) int32 {
+	loc := GetLoc()
+	tmpT1 := GetTimeByUint64(t1)
+	tmpT2 := GetTimeByUint64(t2)
+
+	dayT1Str := tmpT1.Format(DATE_FORMAT1)
+	dayT1, _ := time.ParseInLocation(DATE_FORMAT1, dayT1Str, loc)
+	dayT2Str := tmpT2.Format(DATE_FORMAT1)
+	dayT2, _ := time.ParseInLocation(DATE_FORMAT1, dayT2Str, loc)
+	deltaDay := int32(dayT2.Sub(dayT1).Hours() / 24)
+
+	if tmpT1.Hour() < 5 {
+		deltaDay += 1
+	}
+	if tmpT2.Hour() >= 5 {
+		deltaDay += 1
+	}
+	return deltaDay
+}
+
+//t1 < t2
+func IsInSameWeek(t1, t2 uint64) bool {
+	if t2 < t1 {
+		return false
+	}
+
+	tmpT1 := GetLatestWeek5Hour(t1)
+	if t1 <= tmpT1 && t2 > tmpT1 {
+		return true
+	}
+	return false
+}
+
+type baseTimer struct {
+	ts        uint64 //上一次时间戳
+	duration  uint64 //持续时间
+	cancel    bool   //取消标记
+	suspend   bool   //是否暂停
+	resetTime uint64 //剩余时间 暂停后会用到
+}
+
+func (this *baseTimer) Cancel() {
+	this.cancel = true
+	this.ts = 0
+	this.duration = 0
+	this.suspend = false
+	this.resetTime = 0
+}
+
+func (this *baseTimer) Canceled() bool {
+	return this.cancel
+}
+
+func (this *baseTimer) Suspend() {
+	this.suspend = true
+	deltaT := this.duration - (GetCurrentTime() - this.ts)
+	if deltaT >= this.duration {
+		this.resetTime = 0
+	} else {
+		this.resetTime = this.duration - this.ts
+	}
+}
+
+func (this *baseTimer) Resume() {
+	this.suspend = false
+	this.ts = GetCurrentTime()
+}
+
+func (this *baseTimer) IsStart() bool {
+	return this.ts != 0
+}
+
+//只运行一次的定时器
+type OnceTimer struct {
+	baseTimer
+}
+
+func NewOnceTimer(ms uint64, duration time.Duration) ServerTimer {
+	t := &OnceTimer{
+		baseTimer: baseTimer{
+			ts:        ms,
+			duration:  uint64(duration),
+			cancel:    false,
+			suspend:   false,
+			resetTime: 0,
+		},
+	}
+	return t
+}
+
+func (this *OnceTimer) IsExpired(ms uint64) bool {
+	if this.cancel || this.suspend {
+		return false
+	}
+
+	if this.resetTime > 0 {
+		if (this.ts + this.resetTime) < ms {
+			this.resetTime = 0
+			return true
+		} else {
+			return false
+		}
+	}
+	return (this.ts + this.duration) < ms
+}
+
+func (this *OnceTimer) Reset(ms uint64, duration time.Duration, fireNow bool) {
+	this.ts = ms
+	this.duration = uint64(duration)
+	this.cancel = false
+}
+
+//运行无限次定时器
+type DurationTimer struct {
+	baseTimer
+	fireNow      bool  //建立后可以立即被触发无论是否过期
+	expiredTimes int32 //过期次数
+}
+
+func NewDurationTimer(ms uint64, duration time.Duration) ServerTimer {
+	t := &DurationTimer{
+		fireNow:      false,
+		expiredTimes: 0,
+		baseTimer: baseTimer{
+			ts:        ms,
+			duration:  uint64(duration),
+			cancel:    false,
+			suspend:   false,
+			resetTime: 0,
+		},
+	}
+	return t
+}
+
+func (this *DurationTimer) IsExpired(ms uint64) bool {
+	if this.cancel || this.suspend {
+		return false
+	}
+
+	if this.resetTime > 0 {
+		if (this.ts + this.resetTime) < ms {
+			this.resetTime = 0
+			this.Reset(ms, time.Duration(this.duration), true)
+			return true
+		} else {
+			return false
+		}
+	}
+	ret := (this.ts + this.duration) < ms
+	if ret {
+		this.expiredTimes++
+		this.ts = ms
+	}
+	if this.fireNow {
+		this.fireNow = false
+		return true
+	}
+	return ret
+}
+
+func (this *DurationTimer) Reset(ms uint64, duration time.Duration, fireNow bool) {
+	this.ts = ms
+	this.duration = uint64(duration)
+	this.cancel = false
+	this.fireNow = fireNow
+}

+ 149 - 0
RO_Server_Trunk-branch_0.1.39/rocommon/util/timewheel.go

@@ -0,0 +1,149 @@
+package util
+
+import (
+	"container/list"
+)
+
+//	https://github.com/ouqiang/timewheel/blob/master/timewheel.go
+type TimeWheel struct {
+	interval uint64
+	//tick     *time.Ticker
+	slots []*list.List //后续优化跳表实现
+	//[key定时器唯一标识,slotnum定时器所在槽位]
+	timer      map[interface{}]int
+	currentIdx int //当前指针所在槽位
+	slotNum    int
+	Callback   func(twTask *TWTask, ms uint64)
+
+	oldMs uint64
+}
+
+const (
+	TWTASK_TYPE_Save = 1 //role save操作
+)
+
+type TWTask struct {
+	Delay    uint64
+	circle   int
+	Key      interface{}
+	Data     interface{}
+	Callback func(interface{})
+
+	Uid          uint64
+	CallbackType int32
+	Repeated     bool
+}
+
+//	interval ms
+func NewTimeWheel(interval uint64, slotNum int) *TimeWheel {
+	if interval <= 0 {
+		return nil
+	}
+
+	tw := &TimeWheel{
+		interval:   interval,
+		slots:      make([]*list.List, slotNum),
+		currentIdx: 0,
+		slotNum:    slotNum,
+		timer:      map[interface{}]int{},
+	}
+	tw.initSlots()
+	return tw
+}
+
+func (this *TimeWheel) initSlots() {
+	for idx := 0; idx < this.slotNum; idx++ {
+		this.slots[idx] = list.New()
+	}
+}
+
+//func (this *TimeWheel) Start() {
+//	//this.tick = time.NewTicker(this.interval)
+//	//this.Start()
+//}
+
+func (this *TimeWheel) Update(ms uint64) {
+	if this.oldMs <= 0 {
+		this.oldMs = ms
+		return
+	}
+	for {
+		if this.oldMs > ms {
+			this.oldMs = ms
+		}
+		delaTime := ms - this.oldMs
+		if delaTime < this.interval {
+			return
+		}
+		this.oldMs += this.interval
+		this.update(ms)
+	}
+}
+
+func (this *TimeWheel) update(ms uint64) {
+	slotIdxList := this.slots[this.currentIdx]
+	for item := slotIdxList.Front(); item != nil; {
+		task := item.Value.(*TWTask)
+		if task.circle > 0 {
+			task.circle--
+			item = item.Next()
+			continue
+		}
+		this.Callback(task, ms)
+		next := item.Next()
+		if task.Key != nil {
+			delete(this.timer, task.Key)
+			//添加到新的槽位节点上,继续触发事件
+			slotIdxList.Remove(item)
+			if task.Repeated {
+				this.AddTask(task)
+			}
+		}
+		item = next
+	}
+
+	if this.currentIdx >= this.slotNum-1 {
+		this.currentIdx = 0
+	} else {
+		this.currentIdx++
+	}
+}
+
+func (this *TimeWheel) AddTask(task *TWTask) bool {
+	_, ok := this.timer[task.Key]
+	if ok {
+		return false
+	}
+
+	idx, circle := this.getIdxAndCircle(task.Delay)
+	task.circle = circle
+
+	this.slots[idx].PushBack(task)
+	if task.Key != nil {
+		this.timer[task.Key] = idx
+	}
+	return true
+}
+
+func (this *TimeWheel) getIdxAndCircle(taskDuration uint64) (int, int) {
+	tmpVal := int(taskDuration / this.interval)
+	circle := int(tmpVal / this.slotNum)
+	idx := (this.currentIdx + tmpVal) % this.slotNum
+	return idx, circle
+}
+
+func (this *TimeWheel) RemoveTask(key interface{}) {
+	idx, ok := this.timer[key]
+	if !ok {
+		return
+	}
+	slotIdxList := this.slots[idx]
+	for item := slotIdxList.Front(); item != nil; {
+		task := item.Value.(*TWTask)
+		if task.Key == key {
+			delete(this.timer, task.Key)
+			slotIdxList.Remove(item)
+		}
+		item = item.Next()
+	}
+}

+ 62 - 0
RO_Server_Trunk-branch_0.1.39/roserver/auth/main.go

@@ -0,0 +1,62 @@
+package main
+
+import (
+	"io/ioutil"
+	"os"
+	"rocommon"
+	"rocommon/service"
+	_ "rocommon/socket"
+	_ "rocommon/socket/http"
+	_ "rocommon/socket/tcp"
+	authModel "roserver/auth/model"
+	"roserver/baseserver"
+	"roserver/baseserver/model"
+	"runtime"
+	"strconv"
+	"syscall"
+)
+
+func main() {
+	//记录gate pid用来做关闭操作
+	sysType := runtime.GOOS
+	if sysType != "windows" {
+		if pid := syscall.Getpid(); pid != 1 {
+			fileName := "auth_server.pid" + strconv.Itoa(pid)
+			ioutil.WriteFile(fileName, []byte(strconv.Itoa(pid)), 0777)
+			defer os.Remove(fileName)
+		}
+	}
+
+	//prof := profile.Start(profile.CPUProfile, profile.ProfilePath("./pprof/auth.pprof"), profile.NoShutdownHook)
+
+	baseserver.Init(model.SERVICE_NODE_TYPE_AUTH_STR, nil, &authModel.AuthUpdate{})
+	//baseserver.Init(model.SERVICE_NODE_TYPE_AUTH_STR, nil, nil)
+
+	//先建立服务器对应的连接,再监听客户端
+	sConfig := service.GetServiceConfig()
+
+	//创建服务器之间的监听
+	var acceNode rocommon.ServerNode = nil
+	if sConfig.Node.Addr != "" {
+		acceNode = baseserver.CreateAcceptor(baseserver.ServiceParam{
+			ServiceType: "tcpAcceptor",
+			ServiceName: model.SERVICE_NODE_TYPE_AUTH_STR,
+			ProcName:    "auth.backend",
+			LisAddr:     sConfig.Node.Addr,
+		}, sConfig)
+	}
+
+	//sdk http
+	authModel.SetHttpNodeParam(&baseserver.ServiceParam{
+		ServiceType: "httpConnector",
+		ServiceName: "game",
+		//LisAddr:     "serverlist.wtgame.cn:8088",
+		//LisAddr: sConfig.Node.ServerList,
+	})
+
+	baseserver.Wait()
+
+	//prof.Stop()
+
+	baseserver.Exit(acceNode)
+}

+ 139 - 0
RO_Server_Trunk-branch_0.1.39/roserver/auth/model/auth_check_manager.go

@@ -0,0 +1,139 @@
+package model
+
+import (
+	"rocommon"
+)
+
+type AuthCheckMag struct {
+	rocommon.UpdateModule
+
+	authHttpList chan interface{}
+}
+
+func NewAuthCheckMag() *AuthCheckMag {
+	mag := &AuthCheckMag{}
+	mag.authHttpList = make(chan interface{}, 2000)
+	return mag
+}
+
+func (this *AuthCheckMag) AddCheckList(response interface{}) {
+	this.authHttpList <- response
+}
+
+func (this *AuthCheckMag) Update(ms uint64) {
+	for {
+		select {
+		case msg := <-this.authHttpList:
+			switch t := msg.(type) {
+			case *SDKQuickLoginAuthCheckResp:
+				DoLoginQuickVerifySign(t)
+			case *SDKNBLoginAuthCheckResp:
+				DoLoginNBSDKVerifySign(t)
+			case *SDKUniLoginAuthCheckResp:
+				DoLoginUniSDKVerifySign(t)
+			case *SDKHwQuickLoginAuthCheckResp:
+				DoLoginHwQuickVerifySign(t)
+			}
+		default:
+			return
+		}
+	}
+}
+
+// //response of http
+type CommonInfo struct {
+	ClintId         uint64 //
+	GateServiceNode string
+}
+type LoginCheckResponse struct {
+	CInfo     CommonInfo
+	errorCode int32
+	platform  string
+	openId    string
+}
+type LoginCheckRequest struct {
+	CommonInfo
+}
+
+// SDK Quick
+type SDKQuickLoginAuthCheckReq struct {
+	Token        string
+	Product_code string
+	Uid          string //从客户端接口获取到的渠道原始uid,无需任何加工如拼接渠道ID等(openid)
+}
+type SDKQuickLoginAuthCheckResp struct {
+	RetCode   string
+	ClientId  uint64
+	ServiceId string
+	OpenId    string
+	Platform  string
+}
+
+// SDK NB
+type SDKNBLoginAuthCheckResp struct {
+	RetCode   string
+	ClientId  uint64
+	ServiceId string
+	OpenId    string
+	Platform  string
+}
+
+// SDK UniSDK
+type SDKUniLoginAuthCheckReq struct {
+	KVList map[string]interface{}
+	//GameId       string `json:"gameid""`       //游戏id(手游即游戏代号,小写)
+	//HostId       int    `json:"hostid"`        //大于等于0, 游戏服务器id(指游戏划分的区服),如果有则传,没有传0
+	//LoginChannel string `json:"login_channel"` //登录渠道( 如用网易sdk登录login_channel=netease,苹果支付pay_chan nel=app_store)
+	//AppChannel   string `json:"app_channel"`   //发行(分发)渠道,支持多级结构,通过UniSDK获取。格式如:netease.gs.123456
+	//Platform     string `json:"platform"`      //平台名
+	//Ip           string `json:"ip"`            //游戏登录时客户端用户ip, 形如255.255.255.255
+	//SdkUid       string `json:"sdkuid"`        //渠道uid,不需要包含域名, 有些渠道的uid中包含有@符号 | wechat_mp_vr渠道传openid
+	//SessionId    string `json:"sessionid"`     //sdk返回的session
+	//SDKVersion   string `json:"sdk_version"`   //接入渠道sdk的版本号,从UniSDK获取
+	//Udid         string `json:"udid"`          //玩家登录的移动设备号,通过UniSDK提供的接口获取
+}
+type SDKUniLoginAuthCheckResp struct {
+	Code            int    `json:"code"`    //接口返回码
+	SubCode         int    `json:"subcode"` //接口返回子码
+	Status          string `json:"status"`  //接口调用状态
+	UniSDKLoginJson string `json:"unisdk_login_json"`
+
+	RetCode   string
+	ClientId  uint64
+	ServiceId string
+	OpenId    string
+	Platform  string
+}
+type UniSDKLoginJsonSt struct {
+	Aid         string `json:"aid"`
+	Sdkuid      string `json:"sdkUid"`
+	Username    string `json:"username"`
+	AccessToken string `json:"access_token"`
+	ExpiresIn   string `json:"expires_in"`
+}
+type SDKCheckUserInfo struct {
+	Code         int    `json:"code"`
+	Aid          string `json:"aid"`
+	ExpireTime   uint64 `json:"expiretime"`
+	LoginChannel string `json:"login_channel"` //登录渠道( 如用网易sdk登录login_channel=netease,苹果支付pay_chan nel=app_store)
+	AppChannel   string `json:"app_channel"`   //发行(分发)渠道,支持多级结构,通过UniSDK获取。格式如:netease.gs.123456
+	EnterSN      string `json:"enter_sn"`
+}
+
+// SDK Quick海外
+type SDKHwQuickLoginAuthCheckReq struct {
+	Token        string
+	Product_code string
+	Uid          string //从客户端接口获取到的渠道原始uid,无需任何加工如拼接渠道ID等(openid)
+}
+type SDKHwQuickLoginAuthCheckResp struct {
+	RetCode   string
+	ClientId  uint64
+	ServiceId string
+	OpenId    string
+	Platform  string
+	Status    bool        `json:"status"`
+	Message   string      `json:"message"`
+	Data      interface{} `json:"data"`
+	Uid       string      `json:"uid"`
+}

+ 49 - 0
RO_Server_Trunk-branch_0.1.39/roserver/auth/model/auth_model.go

@@ -0,0 +1,49 @@
+package model
+
+import (
+	"rocommon"
+	"roserver/baseserver"
+	"sync"
+)
+
+var (
+	updateList []interface{}
+
+	httpParamMutex sync.RWMutex
+	HttpNodeParam  *baseserver.ServiceParam
+
+	authCheckMag *AuthCheckMag
+)
+
+type AuthUpdate struct {
+	rocommon.UpdateModule //eventqueue.go
+}
+
+func (this *AuthUpdate) Init() {
+	authCheckMag = NewAuthCheckMag()
+	updateList = append(updateList, authCheckMag)
+}
+
+func (this *AuthUpdate) Update(ms uint64) {
+	//对管理器进行更新操作
+	for _, data := range updateList {
+		data.(rocommon.UpdateLogic).Update(ms)
+	}
+}
+
+func GetAuthCheckMag() *AuthCheckMag {
+	return authCheckMag
+}
+
+func GetHttpNodeParam() baseserver.ServiceParam {
+	httpParamMutex.RLock()
+	defer httpParamMutex.RUnlock()
+
+	return *HttpNodeParam
+}
+func SetHttpNodeParam(param *baseserver.ServiceParam) {
+	httpParamMutex.Lock()
+	defer httpParamMutex.Unlock()
+
+	HttpNodeParam = param
+}

+ 491 - 0
RO_Server_Trunk-branch_0.1.39/roserver/auth/model/auth_msg.go

@@ -0,0 +1,491 @@
+package model
+
+import (
+	"encoding/base64"
+	"encoding/json"
+	"rocommon"
+	"rocommon/rpc"
+	"rocommon/service"
+	"rocommon/util"
+	"roserver/baseserver"
+	"roserver/baseserver/model"
+	"roserver/serverproto"
+	"runtime/debug"
+	"strings"
+)
+
+var connInfoTimeOut int64 = 31 * 60
+
+func init() {
+	serverproto.Handle_AUTH_CSLoginReq = model.HandleBackendMessage(func(ev rocommon.ProcEvent, cliId model.ClientID) {
+		msg := ev.Msg().(*serverproto.CSLoginReq)
+
+		util.InfoF("msg Platform:%s, token:%s, openID:%s", msg.Platform, msg.PlatformToken, msg.OpenId)
+		if !checkOpenIdValid(msg.OpenId) {
+			LoginRet(ev, int32(serverproto.ErrorCode_ERROR_FAIL))
+			return
+		}
+		//todo...
+		// 1,获取服务器状态,例如维护中不允许登陆
+		if serverStatus := checkServerStatus(); serverStatus != int32(serverproto.ErrorCode_ERROR_OK) {
+			LoginRet(ev, int32(serverproto.ErrorCode_ERROR_FAIL))
+			return
+		}
+		//做sdk登陆验证处理
+		if msg.Platform != model.SDKPlatform_PC && msg.Platform != "" {
+			switch msg.Platform {
+			case model.SDKPlatform_Quick:
+				LoginVerifySign(cliId.SessID, cliId.ServiceID, msg.Platform, msg.PlatformToken, msg.OpenId)
+			case model.SDKPlatform_Hw_Quick:
+				LoginVerifyHwQuickSign(cliId.SessID, cliId.ServiceID, msg.Platform, msg.PlatformToken, msg.OpenId)
+			case model.SDKPlatform_NBSDK:
+				LoginVerifySignNBSDK(cliId.SessID, cliId.ServiceID, msg.Platform, msg.PlatformToken, msg.OpenId)
+			case model.SDKPlatform_YouYi:
+				fallthrough
+			case model.SDKPlatform_YouYi_IOS:
+				fallthrough
+			case model.SDKPlatform_UniSDK:
+				//对quick海外做适配
+				LoginVerifyHwQuickSign(cliId.SessID, cliId.ServiceID, msg.Platform, msg.PlatformToken, msg.OpenId)
+
+				// //LoginVerifySignUniSDK(cliId.SessID, cliId.ServiceID, msg.Platform, msg.PlatformToken, msg.OpenId, msg.Ip)
+				// ret := serverproto.ErrorCode_ERROR_SDK_LOGIN_FAILED
+				// if msg.Platform == model.SDKPlatform_YouYi || msg.Platform == model.SDKPlatform_YouYi_IOS {
+				// 	ret, _ = LoginVerifySignYouYiSDKJWT(msg.Platform, msg.PlatformToken, msg.OpenId)
+				// } else if msg.Platform == model.SDKPlatform_UniSDK {
+				// 	ret, _ = LoginVerifySignUniSDKJWT(msg.Platform, msg.PlatformToken, msg.OpenId)
+				// }
+				// if ret == serverproto.ErrorCode_ERROR_OK {
+				// 	//获取用户上次登录连接信息
+				// 	var connInfo serverproto.UserConnectInfo
+				// 	if !initUserConnInfo(&connInfo, msg.OpenId, msg.Platform) {
+				// 		LoginRet(ev, int32(serverproto.ErrorCode_ERROR_FAIL))
+				// 		return
+				// 	}
+
+				// 	loginNtf := &serverproto.SSLoginNtf{}
+				// 	loginNtf.Error = int32(serverproto.ErrorCode_ERROR_OK)
+				// 	loginNtf.ClientId = cliId.SessID
+				// 	loginNtf.ConnInfo = &connInfo
+				// 	//if loginNtf.ConnInfo.TimeStamp+connInfoTimeOut < util.GetTimeSeconds() {
+				// 	//	loginNtf.ConnInfo.LogicNode = ""
+				// 	//	util.InfoF("connect timeout openid=%v", msg.OpenId)
+				// 	//}
+				// 	ev.Session().Send(loginNtf)
+				// } else {
+				// 	LoginRet(ev, int32(serverproto.ErrorCode_ERROR_SDK_LOGIN_FAILED))
+				// }
+			}
+			return
+
+			//util.InfoF("need sdk check")
+			//LoginRet(ev, int32(serverproto.ErrorCode_ERROR_FAIL))
+			//return
+		} else if msg.Platform == model.SDKPlatform_PC {
+			//获取用户上次登录连接信息
+			var connInfo serverproto.UserConnectInfo
+			if !initUserConnInfo(&connInfo, msg.OpenId, "") {
+				LoginRet(ev, int32(serverproto.ErrorCode_ERROR_FAIL))
+				return
+			}
+
+			loginNtf := &serverproto.SSLoginNtf{}
+			loginNtf.Error = int32(serverproto.ErrorCode_ERROR_OK)
+			loginNtf.ClientId = cliId.SessID
+			loginNtf.ConnInfo = &connInfo
+			//if loginNtf.ConnInfo.TimeStamp+connInfoTimeOut < util.GetTimeSeconds() {
+			//	loginNtf.ConnInfo.LogicNode = ""
+			//	util.InfoF("connect timeout openid=%v", msg.OpenId)
+			//}
+			util.InfoF("loginNtf ClientId: %v,ConnInfo: %v", loginNtf.ClientId, *loginNtf.ConnInfo)
+			ev.Session().Send(loginNtf)
+		} else {
+			LoginRet(ev, int32(serverproto.ErrorCode_ERROR_ROLE_PLATFORM_EMPTY))
+		}
+	})
+
+	serverproto.Handle_AUTH_SSSaveUserConnectInfo = model.HandleBackendMessage(func(ev rocommon.ProcEvent, cliId model.ClientID) {
+		msg := ev.Msg().(*serverproto.SSSaveUserConnectInfo)
+		saveUserConnInfo(msg.ConnInfo, msg.OpenId, msg.Platform)
+	})
+}
+
+func LoginVerifySign(clientId uint64, GateServiceNode string, platform string, token string, openId string) {
+	authHttpAddr := ""
+	urlPath := ""
+	go func() {
+		defer func() {
+			//打印奔溃信息
+			if err := recover(); err != nil {
+				util.InfoF("onError data=%v \n%s\n", err, string(debug.Stack()))
+			}
+		}()
+
+		tmpRequest := &rocommon.HTTPRequest{}
+		tmpRequest.ReqCodecName = "httpform"
+		if platform == model.SDKPlatform_Quick {
+			authHttpAddr = service.GetServiceConfig().SDKConfig.QuickHttpAddr
+			urlPath = service.GetServiceConfig().SDKConfig.QuickHttpAuth
+
+			urlPath += "?token=" + token + "&product_code=" + service.GetServiceConfig().SDKConfig.QuickProductCode
+			urlPath += "&uid=" + openId
+
+			tmpRequest.ResMsg = &SDKQuickLoginAuthCheckResp{}
+		}
+		parm := GetHttpNodeParam()
+		parm.LisAddr = authHttpAddr
+		httpNode := baseserver.CreateHttpConnector(parm)
+		err := httpNode.(rocommon.HTTPConnector).Request("GET", urlPath, tmpRequest)
+
+		tmpResMsg := tmpRequest.ResMsg
+		tmpResMsg.(*SDKQuickLoginAuthCheckResp).ClientId = clientId
+		tmpResMsg.(*SDKQuickLoginAuthCheckResp).ServiceId = GateServiceNode
+		tmpResMsg.(*SDKQuickLoginAuthCheckResp).OpenId = openId
+		tmpResMsg.(*SDKQuickLoginAuthCheckResp).Platform = platform
+		if err != nil {
+			tmpRequest.ResMsg.(*SDKQuickLoginAuthCheckResp).RetCode = "0"
+			util.InfoF("uid=%v http Request openid=%v err=%v", clientId, openId, err)
+		}
+		GetAuthCheckMag().AddCheckList(tmpRequest.ResMsg)
+	}()
+}
+
+func DoLoginQuickVerifySign(res *SDKQuickLoginAuthCheckResp) {
+	util.InfoF("openid=%v DoLoginQuickVerifySign retCode=%v", res.OpenId, res.RetCode)
+
+	gateSession := model.GetServiceNode(res.ServiceId)
+	if gateSession == nil {
+		return
+	}
+
+	//1验证成功,其他数据验证失败
+	if res.RetCode == "1" {
+		//获取用户上次登录连接信息
+		var connInfo serverproto.UserConnectInfo
+		if !initUserConnInfo(&connInfo, res.OpenId, res.Platform) {
+			LoginRetSDK(gateSession, res.ClientId, int32(serverproto.ErrorCode_ERROR_FAIL))
+			return
+		}
+
+		loginNtf := &serverproto.SSLoginNtf{}
+		loginNtf.Error = int32(serverproto.ErrorCode_ERROR_OK)
+		loginNtf.ClientId = res.ClientId
+		loginNtf.ConnInfo = &connInfo
+		gateSession.Send(loginNtf)
+	} else {
+		LoginRetSDK(gateSession, res.ClientId, int32(serverproto.ErrorCode_ERROR_FAIL))
+	}
+}
+
+func LoginVerifySignNBSDK(clientId uint64, GateServiceNode string, platform string, token string, openId string) {
+	authHttpAddr := ""
+	urlPath := ""
+	go func() {
+		defer func() {
+			//打印奔溃信息
+			if err := recover(); err != nil {
+				util.InfoF("onError data=%v \n%s\n", err, string(debug.Stack()))
+			}
+		}()
+
+		tmpRequest := &rocommon.HTTPRequest{}
+		tmpRequest.ReqCodecName = "httpform"
+		if platform == model.SDKPlatform_NBSDK {
+			authHttpAddr = service.GetServiceConfig().SDKConfig.NbHttpAddr
+			urlPath = service.GetServiceConfig().SDKConfig.NbHttpAuth
+			urlPath += "?uid=" + openId + "&token=" + token
+
+			tmpRequest.ResMsg = &SDKNBLoginAuthCheckResp{}
+		}
+		parm := GetHttpNodeParam()
+		parm.LisAddr = authHttpAddr
+		httpNode := baseserver.CreateHttpConnector(parm)
+		err := httpNode.(rocommon.HTTPConnector).Request("GET", urlPath, tmpRequest)
+
+		tmpResMsg := tmpRequest.ResMsg
+		tmpResMsg.(*SDKNBLoginAuthCheckResp).ClientId = clientId
+		tmpResMsg.(*SDKNBLoginAuthCheckResp).ServiceId = GateServiceNode
+		tmpResMsg.(*SDKNBLoginAuthCheckResp).OpenId = openId
+		tmpResMsg.(*SDKNBLoginAuthCheckResp).Platform = platform
+		if err != nil {
+			tmpRequest.ResMsg.(*SDKNBLoginAuthCheckResp).RetCode = "0"
+			util.InfoF("uid=%v http Request openid=%v err=%v", clientId, openId, err)
+		}
+		GetAuthCheckMag().AddCheckList(tmpRequest.ResMsg)
+	}()
+}
+
+func DoLoginNBSDKVerifySign(res *SDKNBLoginAuthCheckResp) {
+	util.InfoF("openid=%v DoLoginNBSDKVerifySign retCode=%v", res.OpenId, res.RetCode)
+
+	gateSession := model.GetServiceNode(res.ServiceId)
+	if gateSession == nil {
+		return
+	}
+
+	//1验证成功,其他数据验证失败
+	if res.RetCode == "success" || !strings.Contains(res.RetCode, "fail") {
+		//获取用户上次登录连接信息
+		var connInfo serverproto.UserConnectInfo
+		if !initUserConnInfo(&connInfo, res.OpenId, res.Platform) {
+			LoginRetSDK(gateSession, res.ClientId, int32(serverproto.ErrorCode_ERROR_FAIL))
+			return
+		}
+
+		loginNtf := &serverproto.SSLoginNtf{}
+		loginNtf.Error = int32(serverproto.ErrorCode_ERROR_OK)
+		loginNtf.ClientId = res.ClientId
+		loginNtf.ConnInfo = &connInfo
+		gateSession.Send(loginNtf)
+	} else {
+		LoginRetSDK(gateSession, res.ClientId, int32(serverproto.ErrorCode_ERROR_FAIL))
+	}
+}
+
+var sdkUniSignAesKey = []byte("wenting123456789")
+
+func LoginVerifySignUniSDKJWT(platform, token, openId string) (serverproto.ErrorCode, string) {
+	tokenList := strings.Split(token, ".") //userinfo.signinfo
+	if len(tokenList) < 2 {
+		return serverproto.ErrorCode_ERROR_FAIL, ""
+	}
+
+	if tokenList[0] == "" || tokenList[1] == "" {
+		return serverproto.ErrorCode_ERROR_FAIL, ""
+	}
+
+	//签名匹配
+	userInfoData, err := base64.StdEncoding.DecodeString(tokenList[0])
+	if err != nil {
+		util.InfoF("LoginVerifySignUniSDKJWT userInfoData decode failed openId=%v err=%v", openId, err)
+		return serverproto.ErrorCode_ERROR_SDK_LOGIN_FAILED, ""
+	}
+	signInfoData, err := base64.StdEncoding.DecodeString(tokenList[1])
+	if err != nil {
+		util.InfoF("LoginVerifySignUniSDKJWT signInfoData decode failed openId=%v err=%v", openId, err)
+		return serverproto.ErrorCode_ERROR_SDK_LOGIN_FAILED, ""
+	}
+
+	singInfo, err := rpc.AESCtrDecrypt(signInfoData, sdkUniSignAesKey, sdkUniSignAesKey...)
+	if err != nil {
+		util.InfoF("LoginVerifySignUniSDKJWT sign failed openId=%v err=%v", openId, err)
+		return serverproto.ErrorCode_ERROR_SDK_LOGIN_FAILED, ""
+	}
+	if string(singInfo) != string(userInfoData) {
+		util.InfoF("LoginVerifySignUniSDKJWT sign failed openId=%v err=%v", openId, err)
+		return serverproto.ErrorCode_ERROR_SDK_LOGIN_FAILED, ""
+	}
+
+	//openid匹配
+	checkUserInfo := &SDKCheckUserInfo{}
+	err = json.Unmarshal(userInfoData, checkUserInfo)
+	if err != nil {
+		util.InfoF("LoginVerifySignUniSDKJWT sign failed openId=%v err=%v", openId, err)
+		return serverproto.ErrorCode_ERROR_SDK_LOGIN_FAILED, ""
+	}
+	if checkUserInfo.Aid != openId {
+		util.InfoF("LoginVerifySignUniSDKJWT openid not match openId=%v err=%v", openId, err)
+		return serverproto.ErrorCode_ERROR_SDK_LOGIN_FAILED, ""
+	}
+	//过期时间处理(单位s)
+	if checkUserInfo.ExpireTime < uint64(util.GetTimeSeconds()) {
+		util.InfoF("LoginVerifySignUniSDKJWT expired openId=%v err=%v", openId, err)
+		return serverproto.ErrorCode_ERROR_SDK_LOGIN_EXPIRE, ""
+	}
+	return serverproto.ErrorCode_ERROR_OK, checkUserInfo.AppChannel
+}
+
+func LoginVerifySignUniSDK(clientId uint64, GateServiceNode string, platform, token, openId, ip string) {
+	authHttpAddr := ""
+	urlPath := ""
+	go func() {
+		defer func() {
+			//打印奔溃信息
+			if err := recover(); err != nil {
+				util.InfoF("onError data=%v \n%s\n", err, string(debug.Stack()))
+			}
+		}()
+
+		tmpRequest := &rocommon.HTTPRequest{}
+		tmpRequest.ReqCodecName = "httpjson"
+
+		authHttpAddr = service.GetServiceConfig().SDKConfig.UniHttpAddr
+
+		tmpKVList := map[string]interface{}{}
+		err := json.Unmarshal([]byte(token), &tmpKVList)
+		if err != nil {
+			util.InfoF("uid=%v LoginVerifySignUniSDK openid=%v err=%v", clientId, openId, err)
+			return
+		}
+		tmpKVList["hostid"] = service.GetServiceConfig().Node.Zone
+		ipStrList := strings.Split(ip, ":")
+		if len(ipStrList) > 0 {
+			tmpKVList["ip"] = ipStrList[0]
+		}
+		tmpRequest.ReqMsg = tmpKVList
+		tmpRequest.ResMsg = &SDKUniLoginAuthCheckResp{}
+
+		parm := GetHttpNodeParam()
+		parm.LisAddr = authHttpAddr
+		httpNode := baseserver.CreateHttpConnector(parm)
+		err = httpNode.(rocommon.HTTPConnector).Request("POST", urlPath, tmpRequest)
+
+		tmpResMsg := tmpRequest.ResMsg
+		tmpResMsg.(*SDKUniLoginAuthCheckResp).ClientId = clientId
+		tmpResMsg.(*SDKUniLoginAuthCheckResp).ServiceId = GateServiceNode
+		tmpResMsg.(*SDKUniLoginAuthCheckResp).OpenId = openId
+		tmpResMsg.(*SDKUniLoginAuthCheckResp).Platform = platform
+		if err != nil {
+			tmpRequest.ResMsg.(*SDKUniLoginAuthCheckResp).RetCode = "0"
+			util.InfoF("uid=%v http Request openid=%v err=%v", clientId, openId, err)
+		}
+		GetAuthCheckMag().AddCheckList(tmpRequest.ResMsg)
+	}()
+}
+
+func DoLoginUniSDKVerifySign(res *SDKUniLoginAuthCheckResp) {
+	util.InfoF("openid=%v DoLoginQuickVerifySign res=%v", res.OpenId, res)
+
+	gateSession := model.GetServiceNode(res.ServiceId)
+	if gateSession == nil {
+		return
+	}
+
+	if res.Code == 200 && res.Status == "ok" {
+		//获取用户上次登录连接信息
+		var connInfo serverproto.UserConnectInfo
+		if !initUserConnInfo(&connInfo, res.OpenId, res.Platform) {
+			LoginRetSDK(gateSession, res.ClientId, int32(serverproto.ErrorCode_ERROR_FAIL))
+			return
+		}
+
+		loginNtf := &serverproto.SSLoginNtf{}
+		loginNtf.Error = int32(serverproto.ErrorCode_ERROR_OK)
+		loginNtf.ClientId = res.ClientId
+		loginNtf.ConnInfo = &connInfo
+		loginNtf.SdkParam = res.UniSDKLoginJson
+		gateSession.Send(loginNtf)
+	} else {
+		LoginRetSDK(gateSession, res.ClientId, int32(serverproto.ErrorCode_ERROR_FAIL))
+	}
+}
+
+func LoginVerifySignYouYiSDKJWT(platform, token, openId string) (serverproto.ErrorCode, string) {
+	tokenList := strings.Split(token, ".") //userinfo.signinfo
+	if len(tokenList) < 2 {
+		return serverproto.ErrorCode_ERROR_FAIL, ""
+	}
+
+	if tokenList[0] == "" || tokenList[1] == "" {
+		return serverproto.ErrorCode_ERROR_FAIL, ""
+	}
+
+	//签名匹配
+	userInfoData, err := base64.StdEncoding.DecodeString(tokenList[0])
+	if err != nil {
+		util.InfoF("LoginVerifySignUniSDKJWT userInfoData decode failed openId=%v err=%v", openId, err)
+		return serverproto.ErrorCode_ERROR_SDK_LOGIN_FAILED, ""
+	}
+	signInfoData, err := base64.StdEncoding.DecodeString(tokenList[1])
+	if err != nil {
+		util.InfoF("LoginVerifySignUniSDKJWT signInfoData decode failed openId=%v err=%v", openId, err)
+		return serverproto.ErrorCode_ERROR_SDK_LOGIN_FAILED, ""
+	}
+
+	singInfo, err := rpc.AESCtrDecrypt(signInfoData, sdkUniSignAesKey, sdkUniSignAesKey...)
+	if err != nil {
+		util.InfoF("LoginVerifySignUniSDKJWT sign failed openId=%v err=%v", openId, err)
+		return serverproto.ErrorCode_ERROR_SDK_LOGIN_FAILED, ""
+	}
+	if string(singInfo) != string(userInfoData) {
+		util.InfoF("LoginVerifySignUniSDKJWT sign failed openId=%v err=%v", openId, err)
+		return serverproto.ErrorCode_ERROR_SDK_LOGIN_FAILED, ""
+	}
+
+	//openid匹配
+	checkUserInfo := &SDKCheckUserInfo{}
+	err = json.Unmarshal(userInfoData, checkUserInfo)
+	if err != nil {
+		util.InfoF("LoginVerifySignUniSDKJWT sign failed openId=%v err=%v", openId, err)
+		return serverproto.ErrorCode_ERROR_SDK_LOGIN_FAILED, ""
+	}
+	if checkUserInfo.Aid != openId {
+		util.InfoF("LoginVerifySignUniSDKJWT openid not match openId=%v err=%v", openId, err)
+		return serverproto.ErrorCode_ERROR_SDK_LOGIN_FAILED, ""
+	}
+	////过期时间处理(单位s)
+	//if checkUserInfo.ExpireTime < uint64(util.GetTimeSeconds()) {
+	//	util.InfoF("LoginVerifySignUniSDKJWT expired openId=%v err=%v", openId, err)
+	//	return serverproto.ErrorCode_ERROR_SDK_LOGIN_EXPIRE, ""
+	//}
+	return serverproto.ErrorCode_ERROR_OK, checkUserInfo.AppChannel
+}
+
+// 海外quick
+func LoginVerifyHwQuickSign(clientId uint64, GateServiceNode string, platform string, token string, openId string) {
+	authHttpAddr := ""
+	urlPath := ""
+	go func() {
+		defer func() {
+			//打印奔溃信息
+			if err := recover(); err != nil {
+				util.InfoF("onError data=%v \n%s\n", err, string(debug.Stack()))
+			}
+		}()
+
+		tmpRequest := &rocommon.HTTPRequest{}
+		tmpRequest.ReqCodecName = "httpjson"
+		//为海外quick做适配
+		// if platform == model.SDKPlatform_Hw_Quick {
+		if true {
+			authHttpAddr = "http://pxqg.hkhappygame.com"
+			urlPath = "/webapi/checkUserInfo?token=" + token + "&uid=" + openId
+			tmpRequest.ResMsg = &SDKHwQuickLoginAuthCheckResp{}
+			util.InfoF("urlPath=%v", urlPath)
+		}
+		parm := GetHttpNodeParam()
+		parm.LisAddr = authHttpAddr
+		httpNode := baseserver.CreateHttpConnector(parm)
+		err := httpNode.(rocommon.HTTPConnector).Request("GET", urlPath, tmpRequest)
+
+		tmpResMsg := tmpRequest.ResMsg
+		util.InfoF("tmpRequest.ResMsg:%v", tmpRequest.ResMsg)
+		tmpResMsg.(*SDKHwQuickLoginAuthCheckResp).ClientId = clientId
+		tmpResMsg.(*SDKHwQuickLoginAuthCheckResp).ServiceId = GateServiceNode
+		tmpResMsg.(*SDKHwQuickLoginAuthCheckResp).OpenId = openId
+		tmpResMsg.(*SDKHwQuickLoginAuthCheckResp).Platform = platform
+		if err != nil {
+			tmpRequest.ResMsg.(*SDKHwQuickLoginAuthCheckResp).Status = false
+			util.InfoF("uid=%v http Request openid=%v err=%v", clientId, openId, err)
+		}
+		GetAuthCheckMag().AddCheckList(tmpRequest.ResMsg)
+	}()
+}
+
+// SDKUniLoginAuthCheckResp
+func DoLoginHwQuickVerifySign(res *SDKHwQuickLoginAuthCheckResp) {
+	util.InfoF("openid=%v DoLoginHWQuickVerifySign retCode=%v", res.OpenId, res.RetCode)
+	gateSession := model.GetServiceNode(res.ServiceId)
+	if gateSession == nil {
+		return
+	}
+
+	//1验证成功,其他数据验证失败
+	if res.Status {
+		util.InfoF("验证通过")
+		//获取用户上次登录连接信息
+		var connInfo serverproto.UserConnectInfo
+		if !initUserConnInfo(&connInfo, res.OpenId, res.Platform) {
+			LoginRetSDK(gateSession, res.ClientId, int32(serverproto.ErrorCode_ERROR_FAIL))
+			return
+		}
+
+		loginNtf := &serverproto.SSLoginNtf{}
+		loginNtf.Error = int32(serverproto.ErrorCode_ERROR_OK)
+		loginNtf.ClientId = res.ClientId
+		loginNtf.ConnInfo = &connInfo
+		gateSession.Send(loginNtf)
+	} else {
+		LoginRetSDK(gateSession, res.ClientId, int32(serverproto.ErrorCode_ERROR_FAIL))
+	}
+}

+ 84 - 0
RO_Server_Trunk-branch_0.1.39/roserver/auth/model/auth_proc.go

@@ -0,0 +1,84 @@
+package model
+
+import (
+	"rocommon"
+	"rocommon/rpc"
+	"rocommon/service"
+	"rocommon/util"
+	"roserver/baseserver/model"
+	"roserver/serverproto"
+)
+
+const (
+	PlatformOpenIdConnectInfoPrefix = "pp_conn_" //openid对应的连接信息
+)
+
+//透传给client
+func LoginRet(ev rocommon.ProcEvent, ret int32) {
+	loginAck := &serverproto.SCLoginAck{
+		Error: ret,
+	}
+	model.ServiceReplay(ev, loginAck)
+}
+
+//sdk返回以后的透传client操作
+func LoginRetSDK(session rocommon.Session, clientId uint64, ret int32) {
+	loginAck := &serverproto.SCLoginAck{
+		Error: ret,
+	}
+	data, info, err := rpc.EncodeMessage(loginAck)
+	if err != nil {
+		util.ErrorF("replay msg encode err=%v", err)
+		return
+	}
+	//透传给gate服务器,然后再发送给客户端
+	session.Send(&serverproto.ServiceTransmitAck{
+		MsgId:    uint32(info.ID),
+		MsgData:  data,
+		ClientId: clientId,
+	})
+}
+
+func checkOpenIdValid(openId string) bool {
+	if openId == "" {
+		return false
+	}
+	return true
+}
+
+func checkServerStatus() int32 {
+	return int32(serverproto.ErrorCode_ERROR_OK)
+}
+
+func initUserConnInfo(connInfo *serverproto.UserConnectInfo, openId, platform string) bool {
+	// 区分不同平台
+	openId = model.ConvertPlatform(openId, platform)
+	keyStr := PlatformOpenIdConnectInfoPrefix + openId
+	ret, err := service.GetRedis().Exists(keyStr).Result()
+	if err != nil && err != service.NIL {
+		util.InfoF("initUserConnInfo openid=%v err=%v", openId, err)
+		return false
+	}
+
+	if ret != 0 {
+		err := model.GetMessageFromRedis(PlatformOpenIdConnectInfoPrefix, openId, connInfo)
+		if err != nil {
+			util.WarnF("initUserConnInfo openid=%v err=%v", openId, err)
+			return false
+		}
+	}
+	return true
+}
+
+func saveUserConnInfo(connInfo *serverproto.UserConnectInfo, openId, platform string) {
+	// 区分不同平台
+	openId = model.ConvertPlatform(openId, platform)
+	err := model.SetMessageToRedis(PlatformOpenIdConnectInfoPrefix, openId, connInfo)
+	if err != nil {
+		util.WarnF("[initUserConnInfo] save userConnectionInfo err:%v", err)
+	}
+}
+
+func checkAuthMode(activeCode string) {
+
+}

+ 580 - 0
RO_Server_Trunk-branch_0.1.39/roserver/baseserver/aoi/aoi.go

@@ -0,0 +1,580 @@
+package aoi
+
+//"gopkg.in/fatih/set.v0"
+import (
+	"math"
+	"rocommon/util"
+	"roserver/baseserver/set"
+	"sort"
+	"sync"
+	"time"
+)
+
+const (
+	LISTTYPE_X = 1
+	LISTTYPE_Y = 2
+
+	FIND_NUM_MAX = 10
+)
+
+type AoiVector2 struct {
+	X float32
+	Y float32
+	Z float32
+}
+
+//set https://studygolang.com/articles/16224?fr=sidebar
+//https://github.com/qq362946/AOI
+type aoiInfo struct {
+	MoveSet      set.Interface
+	MoveOnlySet  set.Interface
+	EnterSet     set.Interface
+	LeaveSet     set.Interface
+	MoveNoNtfSet set.Interface
+}
+type aoiLinkNode struct {
+	Next *AoiObject
+	Pre  *AoiObject
+}
+
+type AoiObject struct {
+	Id          uint64
+	Pos         *AoiVector2
+	AoiInfo     *aoiInfo
+	node        *Node
+	updateCount int32
+
+	rect *QuadBounds
+}
+
+func NewAoiObject(id uint64, x, y float32, z float32) *AoiObject {
+	obj := new(AoiObject)
+	obj.Id = id
+	obj.Pos = &AoiVector2{X: x, Y: y, Z: z}
+	obj.updateCount = 0
+	obj.AoiInfo = &aoiInfo{}
+	obj.AoiInfo.MoveSet = set.New(set.NonThreadSafe)
+	obj.AoiInfo.MoveOnlySet = set.New(set.NonThreadSafe)
+	obj.AoiInfo.EnterSet = set.New(set.NonThreadSafe)
+	obj.AoiInfo.LeaveSet = set.New(set.NonThreadSafe)
+	obj.AoiInfo.MoveNoNtfSet = set.New(set.NonThreadSafe)
+
+	return obj
+}
+
+func (this *AoiObject) SetNode(node *Node) {
+	this.node = node
+}
+
+func (this *AoiObject) SetPosition(x, y float32) {
+	this.Pos.X = x
+	this.Pos.Y = y
+}
+
+func (this *AoiObject) GetMoveSize() int32 {
+	return int32(this.AoiInfo.MoveSet.Size())
+}
+
+///////////////////////
+type Aoi struct {
+	nodes     map[uint64]*AoiObject
+	xNodeList *SkipList
+	yNodeList *SkipList
+
+	AoiArea *AoiVector2
+
+	quadTree *QuadTreeNode
+}
+
+var newNodePool = sync.Pool{
+	New: func() interface{} {
+		node := &Node{Forward: make([]*Node, SKIPLIST_MAXLEVEL)}
+		node.ValueList = make(map[uint64]*AoiObject)
+		//v.(*AoiObject).SetNode(node)
+		//node.addValue(v.(*AoiObject))
+		return node
+	},
+}
+
+func NewAoi() *Aoi {
+	aoi := &Aoi{}
+	aoi.nodes = make(map[uint64]*AoiObject)
+	aoi.xNodeList = NewSkipList(LISTTYPE_X)
+	aoi.yNodeList = NewSkipList(LISTTYPE_Y)
+	aoi.quadTree = NewQuadTree(8, &QuadBounds{-10000, -10000, 10000, 10000})
+
+	aoi.AoiArea = &AoiVector2{10, 10, 0}
+	return aoi
+}
+
+func (this *Aoi) GetNode(uid uint64) *AoiObject {
+	if data, ok := this.nodes[uid]; ok {
+		return data
+	}
+	return nil
+}
+
+func (this *Aoi) GetAllNode() map[uint64]*AoiObject {
+	return this.nodes
+}
+
+func (this *Aoi) PrintStackList() {
+	this.xNodeList.PrintSkipList()
+}
+
+/**
+新加入AOI
+*/
+func (this *Aoi) Enter(uid uint64, callback func(*AoiObject), x, y, z float32, forceUpdate bool, isMaster bool) *AoiObject {
+	if data, ok := this.nodes[uid]; ok {
+		return data
+	}
+
+	//todo...可以使用pool
+	obj := NewAoiObject(uid, x, y, z)
+
+	this.xNodeList.Insert(obj)
+	//this.yNodeList.Insert(obj)
+
+	this.nodes[uid] = obj
+	if obj.node == nil {
+		util.InfoF("enter error") //insert操作失败
+	}
+
+	this.updateWithArea(obj, callback, *this.AoiArea, x, y, forceUpdate, isMaster)
+
+	//this.PrintStackList()
+	return obj
+}
+
+var profileTime time.Duration
+var nowTime = util.GetCurrentTimeNow()
+var profileCount int32 = 0
+
+//更新节点
+func (this *Aoi) Update(id uint64, callback func(*AoiObject), area AoiVector2, x, y float32, isMaster bool) (*AoiObject, bool) {
+	if data, ok := this.nodes[id]; ok {
+		profileCount++
+		//nowTime := time.Now()
+		obj, ret := this.updateWithArea(data, callback, area, x, y, false, isMaster)
+		//this.PrintStackList()
+		//return this.updateWithArea(data, area,x ,y)
+		//profileTime += time.Now().Sub(nowTime)
+		if util.GetCurrentTimeNow().Sub(nowTime) > time.Second {
+			nowTime = util.GetCurrentTimeNow()
+			/*
+				oobb := this.nodes[6735728018393727041]
+				log.Println("aoiUpdate[1000]:", oobb.Id,profileTime,
+					len(oobb.AoiInfo.MoveSet.List()),
+					len(oobb.AoiInfo.EnterSet.List()),
+					len(oobb.AoiInfo.LeaveSet.List()),
+					len(oobb.AoiInfo.MoveOnlySet.List()))
+			*/
+
+			profileCount = 0
+			profileTime = 0
+		}
+		return obj, ret
+	}
+	return nil, false
+}
+
+//callback 处理必须可见玩家列表(目前只包括情侣)
+func (this *Aoi) updateWithArea(obj *AoiObject, callback func(*AoiObject), area AoiVector2, x, y float32, forceUpdate bool, isMaster bool) (*AoiObject, bool) {
+	//移动到新的位置
+	this.move(obj, x, y)
+
+	//减少更新频率,发3次移动包,做一次视野更新
+	//obj.updateCount++
+	//if obj.updateCount%3 != 0 && !forceUpdate {
+	//	return obj, false
+	//}
+	//obj.updateCount = 0
+
+	//把AOI节点转换到旧的节点里
+	tempMoveSet := obj.AoiInfo.MoveSet.Copy()
+	//obj.AoiInfo.MoveOnlySet = obj.AoiInfo.MoveSet.Copy()
+
+	//ghost不做处理
+	if !isMaster {
+		return obj, true
+	}
+
+	//查找范围坐标
+	this.find(obj, area)
+	if callback != nil {
+		callback(obj)
+	}
+
+	//差集计算(属于MoveSet,不属于MoveOnlySet)
+	obj.AoiInfo.EnterSet = set.Difference(obj.AoiInfo.MoveSet, tempMoveSet)
+	//属于MoveSet,不属于EnterSet
+	obj.AoiInfo.MoveOnlySet = set.Difference(obj.AoiInfo.MoveSet, obj.AoiInfo.EnterSet)
+
+	obj.AoiInfo.LeaveSet = set.Difference(tempMoveSet, obj.AoiInfo.MoveOnlySet)
+
+	/*
+		//差集计算(属于MoveSet,不属于MoveOnlySet)
+		//obj.AoiInfo.EnterSet = set.Difference(obj.AoiInfo.MoveSet, obj.AoiInfo.MoveOnlySet)
+
+		//obj.AoiInfo.LeaveSet = set.Difference(obj.AoiInfo.MoveOnlySet, obj.AoiInfo.MoveSet)
+
+		//属于MoveSet,不属于EnterSet
+		obj.AoiInfo.MoveOnlySet = set.Difference(obj.AoiInfo.MoveSet, obj.AoiInfo.EnterSet)
+	*/
+
+	//把自己加入别的玩家的进入列表中,否则别的玩家移动时如果离开你的视野不会发送离开消息
+	//可以用主动跟新自己的方式来避免
+	for _, data := range obj.AoiInfo.EnterSet.List() {
+		otherNode := this.GetNode(data.(uint64))
+		if otherNode != nil {
+			if otherNode.GetMoveSize() >= FIND_NUM_MAX {
+				//obj.AoiInfo.MoveNoNtfSet.Add(otherNode.Id)
+				otherNode.AoiInfo.MoveNoNtfSet.Add(obj.Id) //用来标记当前玩家的移动不需要发送给otherNode玩家
+			}
+			otherNode.AoiInfo.MoveSet.Add(obj.Id)
+		}
+	}
+
+	return obj, true
+}
+
+//更新节点
+func (this *Aoi) UpdateNew(id uint64, callback func(*AoiObject), area AoiVector2, x, y float32, isMaster bool) (*AoiObject, bool) {
+	if data, ok := this.nodes[id]; ok {
+		profileCount++
+		//nowTime := time.Now()
+		obj, ret := this.updateWithAreaNew(data, callback, area, x, y, false, isMaster)
+		//this.PrintStackList()
+		//return this.updateWithArea(data, area,x ,y)
+		//profileTime += time.Now().Sub(nowTime)
+		if util.GetCurrentTimeNow().Sub(nowTime) > time.Second {
+			nowTime = util.GetCurrentTimeNow()
+			/*
+				oobb := this.nodes[6735728018393727041]
+				log.Println("aoiUpdate[1000]:", oobb.Id,profileTime,
+					len(oobb.AoiInfo.MoveSet.List()),
+					len(oobb.AoiInfo.EnterSet.List()),
+					len(oobb.AoiInfo.LeaveSet.List()),
+					len(oobb.AoiInfo.MoveOnlySet.List()))
+			*/
+
+			profileCount = 0
+			profileTime = 0
+		}
+		return obj, ret
+	}
+	return nil, false
+}
+
+func (this *Aoi) updateWithAreaNew(obj *AoiObject, callback func(*AoiObject), area AoiVector2, x, y float32, forceUpdate bool, isMaster bool) (*AoiObject, bool) {
+	//移动到新的位置
+	this.move(obj, x, y)
+
+	//减少更新频率,发3次移动包,做一次视野更新
+	//obj.updateCount++
+	//if obj.updateCount%3 != 0 && !forceUpdate {
+	//	return obj, false
+	//}
+	//obj.updateCount = 0
+
+	//把AOI节点转换到旧的节点里
+	tempMoveSet := obj.AoiInfo.MoveSet.Copy()
+	//obj.AoiInfo.MoveOnlySet = obj.AoiInfo.MoveSet.Copy()
+
+	//ghost不做处理
+	if !isMaster {
+		return obj, true
+	}
+
+	//查找范围坐标
+	this.find(obj, area)
+	if callback != nil {
+		callback(obj)
+	}
+
+	//差集计算(属于MoveSet,不属于MoveOnlySet)
+	obj.AoiInfo.EnterSet = set.Difference(obj.AoiInfo.MoveSet, tempMoveSet)
+	//属于MoveSet,不属于EnterSet
+	obj.AoiInfo.MoveOnlySet = set.Difference(obj.AoiInfo.MoveSet, obj.AoiInfo.EnterSet)
+
+	obj.AoiInfo.LeaveSet = set.Difference(tempMoveSet, obj.AoiInfo.MoveOnlySet)
+
+	/*
+		//差集计算(属于MoveSet,不属于MoveOnlySet)
+		//obj.AoiInfo.EnterSet = set.Difference(obj.AoiInfo.MoveSet, obj.AoiInfo.MoveOnlySet)
+
+		//obj.AoiInfo.LeaveSet = set.Difference(obj.AoiInfo.MoveOnlySet, obj.AoiInfo.MoveSet)
+
+		//属于MoveSet,不属于EnterSet
+		obj.AoiInfo.MoveOnlySet = set.Difference(obj.AoiInfo.MoveSet, obj.AoiInfo.EnterSet)
+	*/
+
+	//把自己加入别的玩家的进入列表中,否则别的玩家移动时如果离开你的视野不会发送离开消息
+	//可以用主动跟新自己的方式来避免
+	//for _, data := range obj.AoiInfo.EnterSet.List() {
+	//	otherNode := this.GetNode(data.(uint64))
+	//	if otherNode != nil {
+	//		if otherNode.GetMoveSize() >= FIND_NUM_MAX {
+	//			//obj.AoiInfo.MoveNoNtfSet.Add(otherNode.Id)
+	//			otherNode.AoiInfo.MoveNoNtfSet.Add(obj.Id) //用来标记当前玩家的移动不需要发送给otherNode玩家
+	//		}
+	//		otherNode.AoiInfo.MoveSet.Add(obj.Id)
+	//	}
+	//}
+
+	return obj, true
+}
+
+func (this *Aoi) move(obj *AoiObject, x, y float32) {
+	//移动x
+	this.moveX(obj, x)
+
+	//移动y
+	//this.moveY(obj, y)
+
+	obj.SetPosition(x, y)
+}
+
+func (this *Aoi) moveX(obj *AoiObject, x float32) {
+	if math.Abs(float64(obj.Pos.X-x)) <= 0 {
+		return
+	}
+
+	this.xNodeList.RemoveNode(obj)
+	obj.Pos.X = x
+	this.xNodeList.Insert(obj)
+}
+
+func (this *Aoi) moveY(obj *AoiObject, y float32) {
+	if math.Abs(float64(obj.Pos.Y-y)) <= 0 {
+		return
+	}
+
+	this.yNodeList.RemoveNode(obj)
+	obj.Pos.Y = y
+	this.yNodeList.Insert(obj)
+}
+
+func (this *Aoi) find(obj *AoiObject, area AoiVector2) *AoiObject {
+	obj.AoiInfo.MoveSet.Clear()
+
+	//查找X轴时会考虑Y轴的数值,所有这边只需要找X轴即可
+	this.findX(obj, area)
+
+	//this.findY(obj, area)
+
+	//当前节点列表(节点上所在的玩家列表)
+	if len(obj.node.ValueList) > 1 {
+		for id, _ := range obj.node.ValueList {
+			if id == obj.Id {
+				continue
+			}
+			if !obj.AoiInfo.MoveSet.Has(id) {
+				obj.AoiInfo.MoveSet.Add(id)
+			}
+		}
+	}
+
+	return obj
+}
+
+type aoiDistance struct {
+	objUid uint64
+	dis    float32
+}
+
+func (this *Aoi) findX(obj *AoiObject, area AoiVector2) {
+	bNextOut := false
+	bPreOut := false
+	findNum := FIND_NUM_MAX
+
+	//查找过程中扫描个数上限
+	//processLimitNum := findNum
+	processLimitNumPre := findNum
+	processLimitNumNext := findNum
+
+	var rangeDisList []*aoiDistance
+	//向后查找
+	curNext := obj.node.Forward[0]
+	//向前查找
+	curPre := obj.node.Pre
+	for {
+		if !bNextOut {
+			if curNext == nil || curNext.Value == nil {
+				bNextOut = true
+				continue
+			}
+			if this.getDeltaValue(obj.Pos.X, curNext.Value.Pos.X) > area.X {
+				bNextOut = true
+				continue
+			} else {
+				if len(curNext.ValueList) > 1 {
+					for id, tmpObj := range curNext.ValueList {
+						//todo...后续添加做好友处理
+						tmpDis := this.distance(obj.Pos, tmpObj.Pos)
+						rangeDisList = append(rangeDisList, &aoiDistance{objUid: id, dis: tmpDis})
+						processLimitNumNext--
+						if processLimitNumNext <= 0 {
+							break
+						}
+						//obj.AoiInfo.MoveSet.Add(id)
+						//findNum--
+						//if findNum <= 0 {
+						//	break
+						//}
+					}
+				} else {
+					dis := this.distance(obj.Pos, curNext.Value.Pos)
+					if dis <= area.X {
+						rangeDisList = append(rangeDisList, &aoiDistance{objUid: curNext.Value.Id, dis: dis})
+						processLimitNumNext--
+						//obj.AoiInfo.MoveSet.Add(curNext.Value.Id)
+						//findNum--
+					}
+				}
+			}
+			curNext = curNext.Forward[0]
+			if processLimitNumNext <= 0 {
+				break
+			}
+		}
+
+		if !bPreOut {
+			//id==0为header节点
+			if curPre == nil || curPre.Value == nil || curPre.Value.Id <= 0 {
+				bPreOut = true
+				continue
+			}
+			if this.getDeltaValue(obj.Pos.X, curPre.Value.Pos.X) > area.X {
+				bPreOut = true
+				continue
+			} else {
+				if len(curPre.ValueList) > 1 {
+					for id, tmpObj := range curPre.ValueList {
+						tmpDis := this.distance(obj.Pos, tmpObj.Pos)
+						rangeDisList = append(rangeDisList, &aoiDistance{objUid: id, dis: tmpDis})
+						processLimitNumPre--
+						if processLimitNumPre <= 0 {
+							break
+						}
+						//obj.AoiInfo.MoveSet.Add(id)
+						//findNum--
+						//if findNum <= 0 {
+						//	break
+						//}
+					}
+				} else {
+					dis := this.distance(obj.Pos, curPre.Value.Pos)
+					if dis <= area.X {
+						rangeDisList = append(rangeDisList, &aoiDistance{objUid: curPre.Value.Id, dis: dis})
+						processLimitNumPre--
+						//obj.AoiInfo.MoveSet.Add(curPre.Value.Id)
+						//findNum--
+					}
+				}
+			}
+			curPre = curPre.Pre
+			if processLimitNumPre <= 0 {
+				break
+			}
+		}
+
+		if bNextOut && bPreOut {
+			break
+		}
+	}
+
+	if len(rangeDisList) > 0 {
+		sort.Slice(rangeDisList, func(i, j int) bool {
+			if math.Abs(float64(rangeDisList[i].dis-rangeDisList[j].dis)) < 0.0001 {
+				return rangeDisList[i].objUid < rangeDisList[j].objUid
+			} else {
+				return rangeDisList[i].dis < rangeDisList[j].dis
+			}
+		})
+
+		tmpLen := len(rangeDisList)
+		if tmpLen > findNum {
+			tmpLen = findNum
+		}
+		for idx := 0; idx < tmpLen; idx++ {
+			obj.AoiInfo.MoveSet.Add(rangeDisList[idx].objUid)
+		}
+	}
+
+	//test
+	//this.PrintStackList()
+}
+
+func (this *Aoi) findY(obj *AoiObject, area AoiVector2) {
+	//向后查找
+	curNext := obj.node.Forward[0]
+	for {
+		if curNext == nil || curNext.Value == nil {
+			break
+		}
+		if this.getDeltaValue(obj.Pos.Y, curNext.Value.Pos.Y) > area.Y {
+			break
+		} else if this.getDeltaValue(obj.Pos.X, curNext.Value.Pos.X) <= area.X {
+			if this.distance(obj.Pos, curNext.Value.Pos) <= area.Y {
+				for id, _ := range curNext.ValueList {
+					obj.AoiInfo.MoveSet.Add(id)
+				}
+			}
+		}
+		curNext = curNext.Forward[0]
+	}
+	//向前查找
+	curPre := obj.node.Pre
+	for {
+		if curPre == nil || curPre.Value == nil || curPre.Value.Id <= 0 {
+			break
+		}
+		if this.getDeltaValue(obj.Pos.Y, curPre.Value.Pos.Y) > area.Y {
+			break
+		} else if this.getDeltaValue(obj.Pos.X, curPre.Value.Pos.X) <= area.X {
+			if this.distance(obj.Pos, curPre.Value.Pos) <= area.Y {
+				for id, _ := range curPre.ValueList {
+					obj.AoiInfo.MoveSet.Add(id)
+				}
+			}
+		}
+		curPre = curPre.Pre
+	}
+}
+
+func (this *Aoi) LeaveNode(uid uint64) []interface{} {
+	node := this.GetNode(uid)
+	if node == nil {
+		return nil
+	}
+
+	this.xNodeList.RemoveNode(node)
+	//this.yNodeList.RemoveNode(node)
+	delete(this.nodes, uid)
+
+	for _, data := range node.AoiInfo.MoveSet.List() {
+		if otherNode := this.GetNode(data.(uint64)); otherNode != nil {
+			otherNode.AoiInfo.LeaveSet.Add(uid)
+		}
+	}
+
+	return node.AoiInfo.MoveSet.List()
+}
+
+func (this *Aoi) distance(a, b *AoiVector2) float32 {
+	deltaX := a.X - b.X
+	deltaY := a.Y - b.Y
+	//使用近似距离
+	//return float32(math.Abs(float64(deltaX)) + math.Abs(float64(deltaY)))
+	return float32(math.Sqrt(float64(deltaX*deltaX + deltaY*deltaY)))
+}
+
+func (this *Aoi) getDeltaValue(f1, f2 float32) float32 {
+	deltaValue := f1 - f2
+	if deltaValue <= 0 {
+		return -deltaValue
+	}
+	return deltaValue
+}

+ 126 - 0
RO_Server_Trunk-branch_0.1.39/roserver/baseserver/aoi/aoi_quadtree.go

@@ -0,0 +1,126 @@
+package aoi
+
+import (
+	"math"
+	"roserver/baseserver/set"
+)
+
+func (this *Aoi) EnterWithQuadtree(uid uint64, x, y float32, z float32, forceUpdate bool, isMaster bool) *AoiObject {
+	if data, ok := this.nodes[uid]; ok {
+		return data
+	}
+
+	obj := NewAoiObject(uid, x, y, z)
+	obj.rect = &QuadBounds{x, y, float32(10), float32(10)}
+	this.quadTree.Insert(obj)
+
+	this.nodes[uid] = obj
+
+	this.updateWithAreaQuadtree(obj, x, y, forceUpdate, isMaster)
+	return obj
+}
+
+func (this *Aoi) UpdateQuadtree(id uint64, x, y float32, isMaster bool) (*AoiObject, bool) {
+	if obj, ok := this.nodes[id]; ok {
+		profileCount++
+		//nowTime := time.Now()
+		obj, ret := this.updateWithAreaQuadtree(obj, x, y, false, isMaster)
+		//this.PrintStackList()
+		//return this.updateWithArea(data, area,x ,y)
+		//profileTime += time.Now().Sub(nowTime)
+
+		//if util.GetCurrentTimeNow().Sub(nowTime) > time.Second {
+		//	nowTime = util.GetCurrentTimeNow()
+		//	/*
+		//		oobb := this.nodes[6735728018393727041]
+		//		log.Println("aoiUpdate[1000]:", oobb.Id,profileTime,
+		//			len(oobb.AoiInfo.MoveSet.List()),
+		//			len(oobb.AoiInfo.EnterSet.List()),
+		//			len(oobb.AoiInfo.LeaveSet.List()),
+		//			len(oobb.AoiInfo.MoveOnlySet.List()))
+		//	*/
+		//
+		//	profileCount = 0
+		//	profileTime = 0
+		//}
+		return obj, ret
+	}
+	return nil, false
+}
+
+func (this *Aoi) updateWithAreaQuadtree(obj *AoiObject, x, y float32, forceUpdate bool, isMaster bool) (*AoiObject, bool) {
+	this.moveQuadtree(obj, x, y)
+
+	//把AOI节点转换到旧的节点里
+	tempMoveSet := obj.AoiInfo.MoveSet.Copy()
+	//obj.AoiInfo.MoveOnlySet = obj.AoiInfo.MoveSet.Copy()
+
+	//查找范围坐标
+	this.findQuadtree(obj)
+
+	//ghost不做处理
+	if !isMaster {
+		return obj, true
+	}
+
+	//差集计算(属于MoveSet,不属于MoveOnlySet)
+	obj.AoiInfo.EnterSet = set.Difference(obj.AoiInfo.MoveSet, tempMoveSet)
+	//属于MoveSet,不属于EnterSet
+	obj.AoiInfo.MoveOnlySet = set.Difference(obj.AoiInfo.MoveSet, obj.AoiInfo.EnterSet)
+
+	obj.AoiInfo.LeaveSet = set.Difference(tempMoveSet, obj.AoiInfo.MoveOnlySet)
+
+	/*
+		//差集计算(属于MoveSet,不属于MoveOnlySet)
+		//obj.AoiInfo.EnterSet = set.Difference(obj.AoiInfo.MoveSet, obj.AoiInfo.MoveOnlySet)
+
+		//obj.AoiInfo.LeaveSet = set.Difference(obj.AoiInfo.MoveOnlySet, obj.AoiInfo.MoveSet)
+
+		//属于MoveSet,不属于EnterSet
+		obj.AoiInfo.MoveOnlySet = set.Difference(obj.AoiInfo.MoveSet, obj.AoiInfo.EnterSet)
+	*/
+
+	//把自己加入别的玩家的进入列表中,否则别的玩家移动时如果离开你的视野不会发送离开消息
+	//可以用主动跟新自己的方式来避免
+	for _, data := range obj.AoiInfo.EnterSet.List() {
+		otherNode := this.GetNode(data.(uint64))
+		if otherNode != nil {
+			if otherNode.GetMoveSize() >= FIND_NUM_MAX {
+				//obj.AoiInfo.MoveNoNtfSet.Add(otherNode.Id)
+				otherNode.AoiInfo.MoveNoNtfSet.Add(obj.Id) //用来标记当前玩家的移动不需要发送给otherNode玩家
+			}
+			otherNode.AoiInfo.MoveSet.Add(obj.Id)
+		}
+	}
+
+	return obj, true
+}
+
+func (this *Aoi) moveQuadtree(obj *AoiObject, x, y float32) {
+	if math.Abs(float64(obj.Pos.X-x)) <= 0 {
+		return
+	}
+
+	this.quadTree.Remove(obj)
+	obj.rect.X = x
+	obj.rect.Y = y
+	this.quadTree.Insert(obj)
+}
+
+func (this *Aoi) findQuadtree(obj *AoiObject) *AoiObject {
+	obj.AoiInfo.MoveSet.Clear()
+
+	var objList []*AoiObject
+	this.quadTree.Retrieve(obj, &objList)
+
+	findNum := FIND_NUM_MAX
+	tmpLen := len(objList)
+	if tmpLen > findNum {
+		tmpLen = findNum
+	}
+	for idx := 0; idx < tmpLen; idx++ {
+		obj.AoiInfo.MoveSet.Add(objList[idx].Id)
+	}
+
+	return obj
+}

+ 361 - 0
RO_Server_Trunk-branch_0.1.39/roserver/baseserver/aoi/quad_tree.go

@@ -0,0 +1,361 @@
+package aoi
+
+import (
+	"github.com/fogleman/gg"
+	"log"
+	"math/rand"
+	"rocommon/util"
+	"strconv"
+	"time"
+)
+
+//四叉树碰撞检测
+var dc = gg.NewContext(800, 800)
+var MaxObjNum int32 = 2
+
+type QuadBounds struct {
+	X      float32
+	Y      float32
+	Width  float32
+	Height float32
+}
+type QuadTreeNode struct {
+	MaxObjNum int32 //split之前最大能存储的节点数量
+	MaxLevels int32 //最大深度
+	Level     int32 //当前深度
+
+	Rect    *QuadBounds     //当前节点的bound
+	ObjList []*AoiObject    //当前节点存储的对象数量
+	Nodes   []*QuadTreeNode //子节点
+}
+
+func newQuadTreeNode(level int32, maxLevel int32, rect *QuadBounds) *QuadTreeNode {
+	node := &QuadTreeNode{
+		MaxLevels: maxLevel,
+		Level:     level,
+		Rect:      rect,
+		MaxObjNum: MaxObjNum,
+	}
+	return node
+}
+
+func NewQuadTree(maxLevel int32, rect *QuadBounds) *QuadTreeNode {
+	root := &QuadTreeNode{
+		MaxLevels: maxLevel,
+		Rect:      rect,
+		MaxObjNum: MaxObjNum,
+	}
+
+	return root
+}
+
+func (this *QuadTreeNode) Clear() {
+	this.ObjList = []*AoiObject{}
+	for idx := 0; idx < len(this.Nodes); idx++ {
+		this.Nodes[idx].Clear()
+	}
+	this.Nodes = []*QuadTreeNode{}
+	this.Level = 0
+}
+
+//split当前节点成4个子节点
+func (this *QuadTreeNode) Split() {
+	subWidth := this.Rect.Width * 0.5
+	subHeight := this.Rect.Height * 0.5
+	x := this.Rect.X
+	y := this.Rect.Y
+
+	//-------
+	//|2 | 3| top
+	//-------
+	//|1 | 0| bottom
+	//-------
+	//^
+	//|(y)
+	//|
+	//|
+	//|——————————>(x)
+	this.Nodes = append(this.Nodes, newQuadTreeNode(this.Level+1, this.MaxLevels,
+		&QuadBounds{X: x + subWidth, Y: y, Width: subWidth, Height: subHeight}))
+	this.Nodes = append(this.Nodes, newQuadTreeNode(this.Level+1, this.MaxLevels,
+		&QuadBounds{X: x, Y: y, Width: subWidth, Height: subHeight}))
+	this.Nodes = append(this.Nodes, newQuadTreeNode(this.Level+1, this.MaxLevels,
+		&QuadBounds{X: x, Y: y + subHeight, Width: subWidth, Height: subHeight}))
+	this.Nodes = append(this.Nodes, newQuadTreeNode(this.Level+1, this.MaxLevels,
+		&QuadBounds{X: x + subWidth, Y: y + subWidth, Width: subWidth, Height: subHeight}))
+
+	//dc.SetLineWidth(float64(0.2))
+	//dc.DrawRectangle(float64(x+subWidth), float64(y), float64(subWidth), float64(subHeight))
+	//dc.DrawRectangle(float64(x), float64(y), float64(subWidth), float64(subHeight))
+	//dc.DrawRectangle(float64(x), float64(y+subHeight), float64(subWidth), float64(subHeight))
+	//dc.DrawRectangle(float64(x+subWidth), float64(y+subHeight), float64(subWidth), float64(subHeight))
+	//dc.Stroke()
+}
+
+//获取包含rect的节点序号0-3
+func (this *QuadTreeNode) GetIndexes(rect *QuadBounds) []int32 {
+	var indexList []int32
+	verticalMidPoint := this.Rect.X + this.Rect.Width*0.5
+	horizonMidPoint := this.Rect.Y + this.Rect.Height*0.5
+
+	//判断上下边界
+	topQuadrant := rect.Y >= horizonMidPoint
+	bottomQuadrant := rect.Y-rect.Height <= horizonMidPoint
+	topAndBottomQuadrant := rect.Y+rect.Height >= horizonMidPoint && rect.Y <= horizonMidPoint
+
+	if topAndBottomQuadrant {
+		bottomQuadrant = false
+		topQuadrant = false
+	}
+	//判断是否同时在左右两边
+	if rect.X+rect.Width >= verticalMidPoint && rect.X <= verticalMidPoint {
+		if topQuadrant {
+			indexList = append(indexList, 2, 3)
+		} else if bottomQuadrant {
+			indexList = append(indexList, 0, 1)
+		} else if topAndBottomQuadrant {
+			indexList = append(indexList, 0, 1, 2, 3)
+		}
+	} else if rect.X >= verticalMidPoint {
+		//判断只在右边
+		if topQuadrant {
+			indexList = append(indexList, 3)
+		} else if bottomQuadrant {
+			indexList = append(indexList, 0)
+		} else if topAndBottomQuadrant {
+			indexList = append(indexList, 0, 3)
+		}
+
+	} else if rect.X+rect.Width <= verticalMidPoint {
+		//判断只在左边
+		if topQuadrant {
+			indexList = append(indexList, 2)
+		} else if bottomQuadrant {
+			indexList = append(indexList, 1)
+		} else if topAndBottomQuadrant {
+			indexList = append(indexList, 1, 2)
+		}
+	}
+	return indexList
+}
+
+func (this *QuadTreeNode) Insert(obj *AoiObject) {
+	if len(this.Nodes) > 0 {
+		indexList := this.GetIndexes(obj.rect)
+		if len(indexList) > 0 {
+			for idx := 0; idx < len(indexList); idx++ {
+				this.Nodes[indexList[idx]].Insert(obj)
+			}
+			return
+		}
+	}
+	this.ObjList = append(this.ObjList, obj)
+	if len(this.ObjList) > int(this.MaxObjNum) && this.Level < this.MaxLevels {
+		//split
+		if len(this.Nodes) <= 0 {
+			this.Split()
+		}
+
+		idx := 0
+		for idx < len(this.ObjList) {
+			indexList := this.GetIndexes(this.ObjList[idx].rect)
+			if len(indexList) > 0 {
+				for k := 0; k < len(indexList); k++ {
+					this.Nodes[indexList[k]].Insert(this.ObjList[idx])
+				}
+				this.ObjList = append(this.ObjList[:idx], this.ObjList[idx+1:]...)
+			} else {
+				idx++
+			}
+		}
+	}
+}
+
+func (this *QuadTreeNode) Remove(obj *AoiObject) {
+	indexList := this.GetIndexes(obj.rect)
+	if len(this.Nodes) > 0 {
+		for idx := 0; idx < len(indexList); idx++ {
+			this.Nodes[indexList[idx]].Remove(obj)
+		}
+		//for idx := 0; idx < len(this.Nodes); idx++ {
+		//	if len(this.Nodes[idx].ObjList) > 0 {
+		//		return
+		//	}
+		//}
+		//this.Nodes = nil
+	} else {
+		for idx := 0; idx < len(this.ObjList); idx++ {
+			if this.ObjList[idx].Id == obj.Id {
+				this.ObjList = append(this.ObjList[:idx], this.ObjList[idx+1:]...)
+				break
+			}
+		}
+		if len(this.ObjList) <= 0 {
+			this.Nodes = nil
+		}
+	}
+}
+
+func (this *QuadTreeNode) Retrieve(obj *AoiObject, ObjList *[]*AoiObject) {
+	indexList := this.GetIndexes(obj.rect)
+
+	if len(this.ObjList) > 0 {
+		*ObjList = append(*ObjList, this.ObjList...)
+	}
+	if len(this.Nodes) > 0 {
+		if len(indexList) > 0 {
+			for idx := 0; idx < len(indexList); idx++ {
+				this.Nodes[indexList[idx]].Retrieve(obj, ObjList)
+			}
+		} else {
+			for idx := 0; idx < len(this.Nodes); idx++ {
+				this.Nodes[idx].Retrieve(obj, ObjList)
+			}
+		}
+	}
+}
+
+func TestQuadtreePng() {
+	rand.Seed(int64(util.GetTimeMilliseconds()))
+	dc.SetRGB(0, 0, 0)
+	dc.Clear()
+
+	r := rand.Float64()
+	g := rand.Float64()
+	b := rand.Float64()
+	ww := 0.2
+	dc.SetRGBA(r, g, b, float64(1))
+	dc.SetLineWidth(float64(ww))
+
+	quadTest := NewQuadTree(10, &QuadBounds{0, 0, 800, 800})
+
+	var allObjList []*AoiObject
+	//nowTime := time.Now()
+	var grid float32 = 10.0
+	gridh := quadTest.Rect.Width / grid
+	gridv := quadTest.Rect.Height / grid
+	for idx := 0; idx < 100; idx++ {
+		x := float32(rand.Int31n(int32(gridh))) * grid
+		y := float32(rand.Int31n(int32(gridv))) * grid
+		w := float32(rand.Intn(4)+1) * grid
+		h := float32(rand.Intn(4)+1) * grid
+		//w := 1
+		//h := 1
+		obj := &AoiObject{
+			rect: &QuadBounds{x, y, float32(w), float32(h)},
+		}
+
+		//a := rand.Float64()*0.5 + 0.5
+		ww := 1
+		dc.SetRGBA(1, 1, 1, float64(100))
+		dc.SetLineWidth(float64(ww))
+		dc.DrawRectangle(float64(x), float64(y), float64(w), float64(h))
+		dc.Stroke()
+
+		quadTest.Insert(obj)
+
+		allObjList = append(allObjList, obj)
+	}
+	//log.Printf("time=%v", time.Now().Sub(nowTime).String())
+
+	for ii := 0; ii < 50; ii++ {
+		dc.SetRGB(0, 0, 0)
+		dc.Clear()
+		var returnObjList []*AoiObject
+		//nowTime = time.Now()
+		//for idx := 0; idx < len(allObjList); idx++ {
+		//	quadTest.Retrieve(allObjList[idx], returnObjList)
+		//}
+
+		r = rand.Float64()
+		g = rand.Float64()
+		b = rand.Float64()
+		returnObjList = returnObjList[:0]
+		tmpObj := &AoiObject{
+			rect: &QuadBounds{
+				X:      float32(r)*200 + float32(ii)*5,
+				Y:      float32(g)*200 + float32(ii)*5,
+				Width:  400,
+				Height: 400,
+			}}
+		nowTime := time.Now()
+		quadTest.Retrieve(tmpObj, &returnObjList)
+		log.Printf("time=%v", time.Now().Sub(nowTime).String())
+		x := tmpObj.rect.X
+		y := tmpObj.rect.Y
+		w := tmpObj.rect.Width
+		h := tmpObj.rect.Height
+		dc.SetRGBA(r+22, g, b, float64(10))
+		dc.SetLineWidth(float64(2))
+		dc.DrawRectangle(float64(x), float64(y), float64(w), float64(h))
+		dc.Stroke()
+
+		r = rand.Float64()
+		g = rand.Float64()
+		b = rand.Float64()
+		for idx := 0; idx < len(returnObjList); idx++ {
+			x := returnObjList[idx].rect.X
+			y := returnObjList[idx].rect.Y
+			w := returnObjList[idx].rect.Width
+			h := returnObjList[idx].rect.Height
+			ww := 1
+			dc.SetRGB(r+100, g+100, b+100)
+			dc.SetLineWidth(float64(ww))
+			dc.DrawRectangle(float64(x), float64(y), float64(w), float64(h))
+			dc.Stroke()
+		}
+		//log.Printf("time1=%v", time.Now().Sub(nowTime).String())
+		dc.SavePNG("rect" + strconv.Itoa(ii) + ".png")
+	}
+}
+
+func TestQuadtree() {
+	rand.Seed(int64(util.GetTimeMilliseconds()))
+	quadTest := NewQuadTree(8, &QuadBounds{0, 0, 800, 800})
+
+	var allObjList []*AoiObject
+	nowTime := time.Now()
+	var totalTime time.Duration
+	var grid float32 = 10.0
+	gridh := quadTest.Rect.Width / grid
+	gridv := quadTest.Rect.Height / grid
+	for idx := 0; idx < 10000; idx++ {
+		x := float32(rand.Int31n(int32(gridh))) * grid
+		y := float32(rand.Int31n(int32(gridv))) * grid
+		//w := float32(rand.Intn(4)+1) * grid
+		//h := float32(rand.Intn(4)+1) * grid
+		w := 1
+		h := 1
+		obj := &AoiObject{
+			Id:   uint64(idx),
+			rect: &QuadBounds{x, y, float32(w), float32(h)},
+		}
+
+		nowTime1 := time.Now()
+		quadTest.Insert(obj)
+		totalTime += time.Now().Sub(nowTime1)
+
+		allObjList = append(allObjList, obj)
+	}
+	log.Printf("time=%v %v", time.Now().Sub(nowTime).String(), totalTime)
+
+	var retrieveTime time.Duration
+	for ii := 0; ii < len(allObjList); ii++ {
+		var returnObjList []*AoiObject
+
+		returnObjList = returnObjList[:0]
+		nowTime := time.Now()
+		quadTest.Retrieve(allObjList[ii], &returnObjList)
+		retrieveTime += time.Now().Sub(nowTime)
+	}
+	log.Printf("retrieveTime=%v", retrieveTime.String())
+
+	retrieveTime = 0
+	nowTime = time.Now()
+	for idx := 0; idx < len(allObjList); idx++ {
+		quadTest.Remove(allObjList[idx])
+	}
+	retrieveTime += time.Now().Sub(nowTime)
+
+	log.Printf("retrieveTime=%v", retrieveTime.String())
+}

+ 283 - 0
RO_Server_Trunk-branch_0.1.39/roserver/baseserver/aoi/skip_list.go

@@ -0,0 +1,283 @@
+package aoi
+
+import (
+	"fmt"
+	"math/rand"
+)
+
+const SKIPLIST_MAXLEVEL = 32 //8
+const SKIPLIST_P = 4
+
+//https://github.com/xcltapestry/xclpkg/tree/master/algorithm
+type Node struct {
+	Forward []*Node
+	//Value interface{}
+	Value     *AoiObject
+	ValueList map[uint64]*AoiObject
+
+	Pre *Node
+}
+
+func NewNode(v interface{}, level int) *Node {
+	//node := newNodePool.Get().(*Node)
+	node := &Node{Forward: make([]*Node, SKIPLIST_MAXLEVEL)}
+	node.ValueList = make(map[uint64]*AoiObject, 5)
+	/*
+		node.ValueList = make(map[uint64]*AoiObject)
+		for i := 0;i < len(node.Forward);i++ {
+			node.Forward[i] = nil
+		}
+		if len(node.ValueList) > 0{
+			node.ValueList = make(map[uint64]*AoiObject)
+		}
+	*/
+	v.(*AoiObject).SetNode(node)
+	node.addValue(v.(*AoiObject))
+	return node
+}
+
+func (this *Node) getValue() *AoiObject {
+	return this.Value
+}
+func (this *Node) addValue(obj *AoiObject) {
+	this.ValueList[obj.Id] = obj
+	if this.Value == nil {
+		this.Value = obj
+	}
+}
+func (this *Node) removeValue(uid uint64) bool {
+	if this.Value == nil {
+		return false
+	}
+
+	delete(this.ValueList, uid)
+	if this.Value.Id == uid {
+		this.Value = nil
+		for _, data := range this.ValueList {
+			if data != nil {
+				this.Value = data
+				break
+			}
+		}
+	}
+	return this.Value != nil
+}
+func (this *Node) getById(uid uint64) *AoiObject {
+	if data, ok := this.ValueList[uid]; ok {
+		return data
+	}
+	return nil
+}
+
+type SkipList struct {
+	Header      *Node
+	Level       int
+	compareType int
+}
+
+func NewSkipList(compareType int) *SkipList {
+	skipList := &SkipList{Level: 1, Header: NewNode(NewAoiObject(0, -9999, -9999, 0), SKIPLIST_MAXLEVEL)}
+	skipList.compareType = compareType
+	return skipList
+}
+
+func (skipList *SkipList) value(obj *AoiObject) float32 {
+	if skipList.compareType == LISTTYPE_X {
+		return obj.Pos.X
+	} else {
+		return obj.Pos.Y
+	}
+}
+
+func (skipList *SkipList) Insert(key *AoiObject) {
+	update := make(map[int]*Node)
+	node := skipList.Header
+
+	valueKey := skipList.value(key)
+	for i := skipList.Level - 1; i >= 0; i-- {
+		for {
+			if node.Forward[i] == nil {
+				break
+			}
+			value := node.Forward[i].getValue()
+			//if value != nil && value.Pos.x < key.Pos.x {
+			if value != nil && skipList.value(value) < valueKey {
+				node = node.Forward[i]
+			} else {
+				break
+			}
+		}
+		update[i] = node
+	}
+
+	//value := update[0].Forward[0].getValue()
+	//if value != nil && value.Pos.x == key.Pos.x {
+	if update[0] != nil {
+		if update[0].Forward[0] != nil {
+			value := update[0].Forward[0].getValue()
+			if value != nil && skipList.value(value) == valueKey {
+				update[0].Forward[0].addValue(key)
+				key.node = update[0].Forward[0]
+				return
+			}
+		}
+	}
+
+	level := skipList.Random_level()
+	if level > skipList.Level {
+		for i := skipList.Level; i < level; i++ {
+			update[i] = skipList.Header
+		}
+		skipList.Level = level
+	}
+
+	newNode := NewNode(key, level)
+	//多层更新节点导致,level=1的节点的pre指向出现问题,除非pre也做level层级操作
+	newNode.Pre = update[0]
+	for i := 0; i < level; i++ {
+		if update[i].Forward[i] != nil && i == 0 {
+			update[i].Forward[i].Pre = newNode
+		}
+		newNode.Forward[i] = update[i].Forward[i]
+		//if i == 0{
+		//	newNode.Pre = update[i]
+		//}
+		update[i].Forward[i] = newNode
+	}
+}
+
+func (skipList *SkipList) Random_level() int {
+	level := 1
+	for (rand.Int31()&0xFFFF)%SKIPLIST_P == 0 {
+		level += 1
+	}
+	if level < SKIPLIST_MAXLEVEL {
+		return level
+	} else {
+		return SKIPLIST_MAXLEVEL
+	}
+}
+
+func (skipList *SkipList) PrintSkipList() {
+
+	//fmt.Println("\nSkipList-------------------------------------------")
+	for i := skipList.Level - 1; i >= 0; i-- {
+		node := skipList.Header.Forward[i]
+		if i == 0 {
+			//fmt.Println("level:", i)
+		}
+		fmt.Println("level:", i)
+		for {
+			if node == nil {
+				break
+			}
+			value := node.getValue()
+			if value != nil {
+				//fmt.Printf("x:%v id:%v len:%v", value.Pos.x, value.Id, node.ValueList)
+				fmt.Printf("%v,%v	id:%v", value.Pos.X, value.Pos.Y, value.Id)
+				if node.Pre != nil {
+					fmt.Printf("|pref:%v", node.Pre.getValue().Id)
+				}
+				if node.Forward[0] != nil && node.Forward[0].getValue() != nil {
+					fmt.Printf(" next:%v", node.Forward[0].getValue().Id)
+				}
+				fmt.Printf("\n")
+				node = node.Forward[i]
+			} else {
+				break
+			}
+		}
+		fmt.Println("--------------------------------------------------------")
+	} //end for
+
+	fmt.Println("Current MaxLevel:", skipList.Level)
+}
+
+func (skipList *SkipList) Search(key float32, uid uint64) *Node {
+	node := skipList.Header
+	for i := skipList.Level - 1; i >= 0; i-- {
+		//fmt.Println("\n Search() Level=", i)
+		for {
+			if node.Forward[i] == nil {
+				break
+			}
+			value := node.Forward[i].getValue()
+			if value == nil {
+				break
+			}
+
+			//fmt.Printf("  %d ", node.Forward[i].Value)
+			//if value.Pos.x == key && node.Forward[i].getById(uid) != nil{
+			if skipList.value(value) == key && node.Forward[i].getById(uid) != nil {
+				//fmt.Println("\nFound level=", i, " key=", key)
+				return node.Forward[i]
+			}
+
+			//if  value.Pos.x <= key {
+			if skipList.value(value) <= key {
+				node = node.Forward[i]
+				continue
+			} else { // > key
+				break
+			}
+		} //end for find
+
+	} //end level
+	return nil
+}
+
+func (skipList *SkipList) RemoveNode(obj *AoiObject) {
+	//skipList.Remove(obj.Pos.x, obj.Id)
+	skipList.Remove(skipList.value(obj), obj.Id)
+}
+
+func (skipList *SkipList) Remove(key float32, uid uint64) {
+	update := make(map[int]*Node)
+	node := skipList.Header
+	for i := skipList.Level - 1; i >= 0; i-- {
+		for {
+			if node.Forward[i] == nil || node.Forward[i].getValue() == nil {
+				break
+			}
+
+			value := node.Forward[i].getValue()
+			valueKey := skipList.value(value)
+
+			//if value.Pos.x == key && node.Forward[i].getById(uid) != nil{
+			if valueKey == key && node.Forward[i].getById(uid) != nil {
+				//fmt.Println("Remove() level=", i, " key=", key)
+				update[i] = node
+				break
+			}
+
+			//if  value.Pos.x <= key {
+			if valueKey <= key {
+				node = node.Forward[i]
+				continue
+			} else { // > key
+				break
+			}
+
+		} //end for find
+
+	} //end level
+
+	for i, v := range update {
+		//if v == skipList.Header && skipList.Level > 1 {
+		//	skipList.Level --
+		//}
+		if v == skipList.Header && skipList.Level > 1 && v.Forward[i] == nil {
+			skipList.Level--
+		}
+		if v.Forward[i] != nil && !v.Forward[i].removeValue(uid) {
+			if v.Forward[i].Forward[i] != nil && i == 0 {
+				v.Forward[i].Forward[i].Pre = v
+				if v.Value.Id == 0 {
+					v.Value.Id = 0
+				}
+			}
+			//newNodePool.Put(v.Forward[i])
+			v.Forward[i] = v.Forward[i].Forward[i]
+		}
+	}
+}

+ 406 - 0
RO_Server_Trunk-branch_0.1.39/roserver/baseserver/hook_event.go

@@ -0,0 +1,406 @@
+package baseserver
+
+import (
+	"math"
+	"rocommon"
+	"rocommon/rpc"
+	"rocommon/service"
+	"rocommon/util"
+	"roserver/baseserver/model"
+	"roserver/baseserver/router"
+	"roserver/serverproto"
+	"strconv"
+)
+
+///////////////////////////////////////////ServerTCPEventHook
+//game.backend
+//服务器之间的消息处理派发
+type ServerTCPEventHook struct {
+	recvPingNum int32
+}
+
+//def.go EventHook interface
+func (this *ServerTCPEventHook) InEvent(in rocommon.ProcEvent) rocommon.ProcEvent {
+	util.InfoF("hook_event in_event msg=%v in=%v", in.Msg(), in)
+	switch msg := in.Msg().(type) {
+	case *serverproto.ServiceIdentifyACK: //来自其他服务器的连接确认信息
+		util.InfoF("[RecvServiceIdentifyACK]%v id=%v", msg.ServiceId, in.Session().ID())
+		// 重连时会有问题,重连上来时,但是上一个连接还未移除(正在移除中),导致重连失败(想连接的没连接上,该移除的正在移除)
+		// 通过PingReq超时断开连接,来触发断线重連
+		if serviceNode := model.GetServiceNode(msg.ServiceId); serviceNode == nil {
+			//添加连接上来的对端服务
+			model.AddServiceNode(in.Session(), msg.ServiceId, msg.ServiceName, "remote")
+
+			//服务器之间才启用heartbeat操作(只能反应ack端的send和发起连接端的recv是否正常) 5s
+			in.Session().HeartBeat(&serverproto.PingReq{NeedAck: true})
+		}
+	case *serverproto.PingReq:
+		{
+			//来自ack服务器的ping消息
+			ctx := in.Session().(rocommon.ContextSet)
+			var sid *service.ETCDServiceDesc
+			in.Session().IncRecvPingNum(1)
+			if in.Session().RecvPingNum() >= 10 { //50s打印一次,收到10次打印一次
+				in.Session().IncRecvPingNum(-1)
+				if ctx.RawContextData("ctx", &sid) {
+					util.InfoF("[RecvServicePing]Receive PingReq from session=%v node=%v", in.Session().ID(), sid.ID)
+				}
+			}
+			if msg.NeedAck {
+				in.Session().Send(&serverproto.PingReq{NeedAck: false})
+			}
+		}
+	case *rocommon.SessionConnected:
+		util.InfoF("[SessionConnected] node=%v id=%v", in.Session().Node(), in.Session().ID())
+		//连接上对应类型的服务器节点后,发送确认信息(ServiceIdentifyACK),告诉对端自己的服务器类型
+		ctx := in.Session().Node().(rocommon.ContextSet)
+		var sid *service.ETCDServiceDesc
+		//sid在CreateConnector中会指定
+		if ctx.RawContextData("sid", &sid) {
+			util.InfoF("[SessionConnected] endmsg before")
+			in.Session().Send(&serverproto.ServiceIdentifyACK{
+				//发送自身服务器节点的信息
+				ServiceName:     service.GetServiceName(), //service/init.go
+				ServiceId:       service.GetLocalServiceID(),
+				ServerStartTime: util.GetTimeMilliseconds(),
+			})
+
+			//添加远程的服务器节点到本地,sid服务器信息是从etcd中获取的
+			model.AddServiceNode(in.Session(), sid.ID, sid.Name, "local")
+			util.InfoF("[SendServiceIdentifyACK_local][%v]->[%v] id=%v", service.GetLocalServiceID(), sid.ID, in.Session().ID())
+		} else {
+			util.InfoF("connector not exist sid")
+		}
+	case *rocommon.SessionClosed:
+		closeSID := model.RemoveServiceNode(in.Session())
+		if closeSID != "" {
+			msg.CloseSId = closeSID
+		}
+		util.InfoF("[ServerTCPEventHook::InEvent] Readmsg error SessionClosed session=%v", in.Session().ID())
+	case *rocommon.SessionConnectError:
+		util.InfoF("[ServerTCPEventHook::InEvent] connector error=%v", msg.String())
+	}
+	return in
+}
+
+func (this *ServerTCPEventHook) OutEvent(out rocommon.ProcEvent) rocommon.ProcEvent {
+	return out
+}
+
+///////////////////////////////////////////BackendTCPEventHook
+type BackendTCPEventHook struct {
+	selectRouterIdx int
+}
+
+//def.go EventHook interface
+//后端服务器接收到来自gate/db/auth的消息
+func (this *BackendTCPEventHook) InEvent(in rocommon.ProcEvent) rocommon.ProcEvent {
+	util.InfoF("BackendTCPhook_event BackendTCPin_event msg=%v in=%v", in.Msg(), in)
+	switch inMsg := in.Msg().(type) {
+	case *serverproto.GateTransmitAck:
+		userMsg, _, err := rpc.DecodeMessage(int(inMsg.MsgId), inMsg.MsgData)
+		if err != nil {
+			util.WarnF("[BackendTCPEventHook::InEvent] msg decode err:%v msgId:%v", err.Error(), inMsg.MsgId)
+			return nil
+		}
+		//if inMsg.MsgId == 1173 {
+		//	util.DebugF("kvtime recv cli=%v deltime=%v", inMsg.ClientId, util.GetTimeMilliseconds()-inMsg.KvTime)
+		//}
+		//封装成来自gate的消息事件
+		//todo...这边需要添加gate和game的连接信息,否则game工作线程获取session时会有多线程冲突
+		return &model.RecvGateMsgEvent{
+			Sess:     in.Session(),
+			Message:  userMsg,
+			ClientID: inMsg.ClientId,
+			MsgSeqId: inMsg.SeqId,
+			KvTime:   inMsg.KvTime,
+		}
+	case *serverproto.ServiceTransmitAck:
+		//log.Println("[BackendTCPEventHook::InEvent] DBTransmitAck db to game", inMsg)
+		transmitMsg, _, err := rpc.DecodeMessage(int(inMsg.MsgId), inMsg.MsgData)
+		if err != nil {
+			util.WarnF("[BackendTCPEventHook::InEvent] msg decode err:%v msgId:%v", err.Error(), inMsg.MsgId)
+			return nil
+		}
+		//cross begin
+		//判断是否是跨服操作(针对于social服务器)
+		routeRule := router.GetRuleByMsgID(int(inMsg.MsgId))
+		if routeRule != nil {
+			var serviceNodeList []string
+			switch routeRule.CrossMode {
+			case router.CrossMode_Type_Section:
+				//转发给router服务器
+				serviceNodeList = model.GetAllServiceNodeByName(model.SERVICE_NODE_TYPE_CROSSROUTER_STR)
+			case router.CrossMode_Type_Global:
+				serviceNodeList = model.GetAllServiceNodeByName(model.SERVICE_NODE_TYPE_GLOBALCROSSROUTER_STR)
+			}
+			if len(serviceNodeList) > 0 {
+				this.selectRouterIdx++
+				if this.selectRouterIdx >= math.MaxInt32 {
+					this.selectRouterIdx = 0
+				}
+				selectIdx := this.selectRouterIdx % len(serviceNodeList)
+				serviceNode := model.GetServiceNode(serviceNodeList[selectIdx])
+				if serviceNode == nil {
+					return in
+				}
+				crossMsg := &serverproto.ServiceTransmitRouterNtf{
+					FromZone:          int32(service.GetServiceConfig().Node.Zone),
+					MsgId:             inMsg.MsgId,
+					MsgData:           inMsg.MsgData,
+					ClientId:          inMsg.ClientId,
+					TargetServiceNode: inMsg.TargetServiceNode,
+				}
+				serviceNode.Send(crossMsg)
+				return in
+			} else if routeRule.CrossMode > 0 {
+				util.FatalF("CrossNode Not Find corssMode=%v msgId=%v id=%v", routeRule.CrossMode, inMsg.MsgId, inMsg.ClientId)
+				return nil
+			}
+		}
+		//cross end
+
+		ctx := model.Session2Context(in.Session())
+		if ctx != nil {
+			return &model.RecvServiceMsgEvent{
+				Sess:         in.Session(),
+				Message:      transmitMsg,
+				ClientID:     inMsg.ClientId,
+				ClientIDList: inMsg.ClientIdList,
+				ServiceID:    ctx.ID, //当前session对应的服务器节点信息(game和db/social的连接)
+				IsMaster:     inMsg.IsMaster,
+			}
+		} else {
+			return &model.RecvServiceMsgEvent{
+				Sess:         in.Session(),
+				Message:      transmitMsg,
+				ClientID:     inMsg.ClientId,
+				ClientIDList: inMsg.ClientIdList,
+				//ServiceID: ctx.ID, //当前session对应的服务器节点信息(game和db/social的连接)
+				IsMaster: inMsg.IsMaster,
+			}
+		}
+
+	case *serverproto.ServiceTransmitRouterNtf:
+		//social不需要特殊处理的协议通过RecvRouterServiceMsgEvent,透传到上层进行转发
+		//log.Println("[BackendTCPEventHook::InEvent] DBTransmitAck db to game", inMsg)
+		transmitMsg, _, err := rpc.DecodeMessage(int(inMsg.MsgId), inMsg.MsgData)
+		if err != nil {
+			util.WarnF("[BackendTCPEventHook::InEvent] msg decode err:%v msgId:%v", err.Error(), inMsg.MsgId)
+			return nil
+		}
+		ctx := model.Session2Context(in.Session())
+		return &model.RecvRouterServiceMsgEvent{
+			Sess:         in.Session(),
+			Message:      transmitMsg,
+			ClientID:     inMsg.ClientId,
+			ClientIDList: inMsg.ClientIdList,
+			ServiceID:    ctx.ID, //当前session对应的服务器节点信息(game和db/social的连接)
+			IsMaster:     inMsg.IsMaster,
+			FromZone:     inMsg.FromZone,
+		}
+
+	case *serverproto.ClientClosedACK:
+		//todo...
+		// 客户端关闭做处理,game做离线处理 放到default中处理
+		//log.Println("ClientClosedACK", inMsg)
+	default:
+		return in
+	}
+	return in
+}
+
+//后端服务器发送到gate/db的消息
+func (this *BackendTCPEventHook) OutEvent(out rocommon.ProcEvent) rocommon.ProcEvent {
+	//todo...
+	switch out.Msg().(type) {
+	case *serverproto.ServiceTransmitAck:
+		//log.Println("[BackendTCPEventHook::OutEvent] ServiceTransmitAck game to gate/db", outMsg)
+	}
+	return out
+}
+
+///////////////////////////////////////////BackendTCPEventHook
+//跨服router节点处理
+//收到social节点的消息,或者收到跨服功能节点的消息
+type BackendTCPEventForCrossRouterHook struct {
+	selectRouterIdx int
+}
+
+func (this *BackendTCPEventForCrossRouterHook) InEvent(in rocommon.ProcEvent) rocommon.ProcEvent {
+	switch inMsg := in.Msg().(type) {
+	case *serverproto.ServiceTransmitRouterNtf:
+		msgId := int(inMsg.MsgId)
+		routeRule := router.GetRuleByMsgID(msgId)
+		var serviceNodeList []string
+		if routeRule == nil {
+			//router 返回给所有social服务器
+			if inMsg.FromZone <= 0 {
+				//发给所有social节点
+				util.InfoF("BackendTCPEventForCrossRouterHook fromzone<=0 msgid=%v to all zone", msgId)
+				serviceNodeList = model.GetAllZoneSocialServiceNode(model.SERVICE_NODE_TYPE_SOCIAL_STR)
+				for idx := 0; idx < len(serviceNodeList); idx++ {
+					serviceNode := model.GetServiceNode(serviceNodeList[idx])
+					if serviceNode == nil {
+						continue
+					}
+					serviceNode.Send(inMsg)
+				}
+				return in
+			}
+			//router 返回给对应zone服务器
+			serviceNodeList = model.GetAllSocialServiceNodeByZone(int(inMsg.FromZone), model.SERVICE_NODE_TYPE_SOCIAL_STR)
+		} else {
+			//表示发往router并需要router转发给其他功能服务器
+			//通过proto中的RouteRule来确定当前协议的功能服务器
+			if inMsg.TargetServiceNode != "" {
+				//发送到目地节点服务器
+				serviceNode := model.GetServiceNode(inMsg.TargetServiceNode)
+				if serviceNode != nil {
+					serviceNode.Send(inMsg)
+				}
+				return in
+			} else {
+				serviceNodeList = model.GetAllServiceNodeByName(routeRule.Mod)
+			}
+		}
+		if len(serviceNodeList) <= 0 {
+			util.ErrorF("BackendTCPEventForCrossRouterHook service node not exist nodename=%v msgid=%v fromZone=%V", routeRule, msgId, inMsg.FromZone)
+			return in
+		}
+		this.selectRouterIdx++
+		if this.selectRouterIdx >= math.MaxInt32 {
+			this.selectRouterIdx = 0
+		}
+		selectIdx := this.selectRouterIdx % len(serviceNodeList)
+		serviceNode := model.GetServiceNode(serviceNodeList[selectIdx])
+		if serviceNode == nil {
+			return in
+		}
+		serviceNode.Send(inMsg)
+	case *serverproto.ServiceTransmitAck:
+		transmitMsg, _, err := rpc.DecodeMessage(int(inMsg.MsgId), inMsg.MsgData)
+		if err != nil {
+			util.WarnF("[DBTCPEventHook::InEvent] msg decode err:%v msgId:%v", err.Error(), inMsg.MsgId)
+			return nil
+		}
+
+		//chybenchmark
+		//this.kvTimeMsgLog(int32(inMsg.MsgId))
+
+		//log.Println("[DBTCPEventHook::InEvent] DBTransmitAck", inMsg)
+		ctx := model.Session2Context(in.Session())
+		return &model.RecvServiceMsgEvent{
+			Sess:      in.Session(),
+			Message:   transmitMsg,
+			ClientID:  inMsg.ClientId,
+			ServiceID: ctx.ID, //当前session对应的服务器节点信息(game和db的连接)
+		}
+	}
+	return in
+}
+
+func (this *BackendTCPEventForCrossRouterHook) OutEvent(out rocommon.ProcEvent) rocommon.ProcEvent {
+	return out
+}
+
+///////////////////////////////////////////DBTCPEventHook
+//处理game和db之间的消息
+type ServiceTCPEventHook struct {
+	kvTimeMsgNumList []serverproto.KeyValueType
+	CurTime          uint64
+}
+
+func (this *ServiceTCPEventHook) kvTimeMsgLog(msgId int32) {
+	bChange := false
+	for idx := 0; idx < len(this.kvTimeMsgNumList); idx++ {
+		if this.kvTimeMsgNumList[idx].Key == msgId {
+			this.kvTimeMsgNumList[idx].Value++
+			bChange = true
+			break
+		}
+	}
+	if !bChange {
+		this.kvTimeMsgNumList = append(this.kvTimeMsgNumList,
+			serverproto.KeyValueType{Key: msgId, Value: 1})
+	}
+	nowTime := util.GetTimeMilliseconds()
+	if this.CurTime <= 0 {
+		this.CurTime = nowTime
+	} else if nowTime-this.CurTime > 1000 {
+		this.CurTime = nowTime
+		printfListStr := ""
+		for idx := 0; idx < len(this.kvTimeMsgNumList); idx++ {
+			printfListStr += "\n" +
+				strconv.Itoa(int(this.kvTimeMsgNumList[idx].Key)) + "-" +
+				strconv.Itoa(int(this.kvTimeMsgNumList[idx].Value))
+		}
+		util.DebugF("printfListStr=%v", printfListStr)
+	}
+}
+
+//db接收来自其他服务器的消息
+func (this *ServiceTCPEventHook) InEvent(in rocommon.ProcEvent) rocommon.ProcEvent {
+	switch inMsg := in.Msg().(type) {
+	case *serverproto.ServiceTransmitAck:
+		dbMsg, _, err := rpc.DecodeMessage(int(inMsg.MsgId), inMsg.MsgData)
+		if err != nil {
+			util.WarnF("[DBTCPEventHook::InEvent] msg decode err:%v msgId:%v", err.Error(), inMsg.MsgId)
+			return nil
+		}
+
+		//chybenchmark
+		//this.kvTimeMsgLog(int32(inMsg.MsgId))
+
+		//log.Println("[DBTCPEventHook::InEvent] DBTransmitAck", inMsg)
+		ctx := model.Session2Context(in.Session())
+		return &model.RecvServiceMsgEvent{
+			Sess:      in.Session(),
+			Message:   dbMsg,
+			ClientID:  inMsg.ClientId,
+			ServiceID: ctx.ID, //当前session对应的服务器节点信息(game和db的连接)
+		}
+	}
+	return in
+}
+
+//db发送到其他服务器的消息
+func (this *ServiceTCPEventHook) OutEvent(out rocommon.ProcEvent) rocommon.ProcEvent {
+	//todo...
+	switch out.Msg().(type) {
+	case *serverproto.ServiceTransmitAck:
+		//log.Println("[DBTCPEventHook::OutEvent] DBTransmitAck db to game...", outMsg)
+	}
+	return out
+}
+
+/*
+///////////////////////////////////////////AuthTCPEventHook
+//处理auth和其他服务器之间的消息
+type AuthTCPEventHook struct{
+}
+//auth接收到来自其他服务器的消息
+func (this *AuthTCPEventHook) InEvent(in rocommon.ProcEvent) rocommon.ProcEvent {
+	switch inMsg := in.Msg().(type) {
+	case *serverproto.ServiceTransmitAck:
+		gateMsg, _, err := rpc.DecodeMessage(int(inMsg.MsgId), inMsg.MsgData)
+		if err != nil {
+			util.WarnF("[AuthTCPEventHook::InEvent] msg decode err:%v msgId:%v", err.Error(), inMsg.MsgId)
+			return nil
+		}
+		ctx := model.Session2Context(in.Session())
+		return &model.RecvServiceMsgEvent{
+			Sess: in.Session(),
+			Message: gateMsg,
+			ClientID: inMsg.ClientId,
+			ServiceID: ctx.ID, //当前session对应的服务器节点信息(game和db的连接)
+		}
+	}
+	return in
+}
+//auth发送给其他服务器的消息
+func (this *AuthTCPEventHook) OutEvent(out rocommon.ProcEvent) rocommon.ProcEvent {
+	//todo...
+	return out
+}
+*/

+ 373 - 0
RO_Server_Trunk-branch_0.1.39/roserver/baseserver/init.go

@@ -0,0 +1,373 @@
+package baseserver
+
+import (
+	"rocommon"
+	_ "rocommon/rpc"
+	"rocommon/service"
+	"rocommon/socket"
+	"rocommon/util"
+	"roserver/baseserver/model"
+	"roserver/serverproto"
+	"runtime"
+	"sort"
+	"strconv"
+	"time"
+)
+
+var Queue rocommon.NetEventQueue
+
+type ServiceParam struct {
+	ServiceName          string
+	ServiceType          string //tcpAcceptor /tcpConnector
+	ProcName             string
+	LisAddr              string
+	DiscoveryServiceName string //用于服务器发现
+	DiscoveryServiceZone int    //用于服务器发现
+}
+
+//loadConfig是否需要加载配置文件, update是否有主循环
+func Init(serverName string, loadConfig func(), update rocommon.UpdateModule) {
+	//设置携程使用的线程数量(不会强制性生效)
+	//The GOMAXPROCS variable limits the number of operating system threads that can execute user-level Go code simultaneously.
+	// There is no limit to the number of threads that can be blocked in system calls on behalf of Go code; those do not count
+	// against the GOMAXPROCS limit. This package's GOMAXPROCS function queries and changes the limit.
+	runtime.GOMAXPROCS(runtime.NumCPU() / 2)
+
+	//dgnet -> init.go
+	service.Init(serverName)
+	util.InfoF("serverName serverName=%v finish", serverName)
+	util.InfoF("////////////////////////Service GameVersion=%v DebugMode=%v",
+		int32(serverproto.GameVersion_GameVersion_Main), service.DebugMode)
+
+	if loadConfig != nil {
+		loadConfig()
+	}
+
+	//事件回调队列
+	Queue = service.NewEventQueue()
+
+	//设置更新操作
+	if update != nil {
+		Queue.AttachUpdateModule(update)
+	}
+
+	Queue.StartQueue()
+
+	//链接服务器发现 etcd 在service.Init中已经实现
+	//log.Printf("server init ok...")
+	util.InfoF("server init ok...")
+
+}
+
+func Wait() {
+	//todo...
+
+	//监听退出信号
+	service.WaitExitSignal()
+
+	Queue.StopQueue()
+	Queue.Wait()
+}
+
+func Exit(node rocommon.ServerNode) {
+	//todo... 停止所有在监听的协程
+	util.InfoF("exit...")
+	//停止etcd
+	if node != nil {
+		node.Stop()
+		service.ETCDUnregister(node)
+	}
+	service.GetServiceDiscovery().Close()
+}
+
+var idxMap = map[int]*model.PerformKVTimeSt{}
+var performTime uint64 = 0
+
+func KVTimeTest(nowTime uint64) {
+	var printfList []model.PerformKVTimeSt
+	if performTime <= 0 {
+		performTime = nowTime
+	} else if nowTime-performTime >= 1000 {
+		performTime = nowTime
+		for _, val := range idxMap {
+			printfList = append(printfList, *val)
+		}
+	}
+
+	if len(printfList) > 0 {
+		sort.Slice(printfList, func(i, j int) bool {
+			return printfList[i].AckMsgId < printfList[j].AckMsgId
+		})
+		printfListStr := ""
+		for idx := 0; idx < len(printfList); idx++ {
+			//msgIdStr := strconv.Itoa(int(printfList[idx].AckMsgId))
+			tmpTime := float64(printfList[idx].TotalTime) / float64(printfList[idx].TotalNum)
+			tmpPerNum := printfList[idx].NowTime - printfList[idx].BeginTime
+			if tmpPerNum > 0 {
+				tmpPerNum = uint64(printfList[idx].TotalNum) * 1000 / tmpPerNum
+			} else {
+				tmpPerNum = uint64(printfList[idx].TotalNum)
+			}
+			printfListStr += "	\n" + printfList[idx].MsgName + ":" +
+				strconv.FormatInt(int64(tmpTime), 10) + "(ms) | " +
+				strconv.FormatInt(int64(tmpPerNum), 10) + "(req-ack/s) | " +
+				strconv.Itoa(int(printfList[idx].TotalNum)) + "(total)"
+		}
+		util.DebugF("printfListStr=%v", printfListStr)
+	}
+}
+
+func CreateAcceptor(param ServiceParam, serverConfig service.ConfigServerNode) rocommon.ServerNode {
+	if param.ServiceType == "" {
+		param.ServiceType = "tcpAcceptor"
+	}
+	node := socket.NewServerNode(param.ServiceType, param.ServiceName, param.LisAddr, Queue)
+
+	//消息处理函数,根据给定的服务器类型来获取,例如gate,game,db,auth
+	msgPrcFunc := serverproto.GetMessageHandler(param.ServiceName)
+	//通过QueueEventCall函数加入直接函数的回调队列中
+	socket.SetProcessorRPC(node, param.ProcName, func(e rocommon.ProcEvent) {
+		if msgPrcFunc != nil {
+			msgPrcFunc(e)
+
+			//nowTime := util.GetTimeMilliseconds()
+			//msgPrcFunc(e)
+			//nowTime1 := util.GetTimeMilliseconds()
+			//switch in := e.(type) {
+			//case *model.RecvGateMsgEvent:
+			//	//tmpInfo := rocommon.MessageInfoByMsg(in.Msg())
+			//	//if tmpInfo != nil && tmpInfo.ID == 1066 {
+			//	//  delTime := nowTime1 - nowTime
+			//	//	recvTime := nowTime - in.KvTime
+			//	//	util.DebugF("kvtime cid=%v idx=%v msg=%v deltime=%v recvtime=%v",
+			//	//		in.ClientID, idxMap[in.ClientID], tmpInfo.ID, delTime, recvTime)
+			//	//	//if delTime > 0 {
+			//	//	//	util.DebugF("kvtime cid=%v idx=%v deltime=%v msg=%T", in.ClientID, idxMap[in.ClientID], delTime, tmpInfo.ID)
+			//	//	//}
+			//	//}
+			//	tmpInfo := rocommon.MessageInfoByMsg(in.Msg())
+			//	if tmpInfo != nil {
+			//		gateGameTime := nowTime - in.KvTime
+			//		gateGameProcTime := nowTime1 - in.KvTime
+			//		idxItem, ok := idxMap[tmpInfo.ID]
+			//		if ok {
+			//			idxItem.TotalNum++
+			//			idxItem.TotalTime += gateGameProcTime + gateGameTime
+			//			idxItem.NowTime = nowTime1
+			//		} else {
+			//			idxItem = &model.PerformKVTimeSt{
+			//				TotalNum:  1,
+			//				TotalTime: gateGameProcTime + gateGameTime,
+			//				MsgName:   tmpInfo.Type.Name(),
+			//				BeginTime: nowTime1,
+			//				NowTime:   nowTime1,
+			//				AckMsgId:  int32(tmpInfo.ID),
+			//			}
+			//		}
+			//		idxMap[tmpInfo.ID] = idxItem
+			//		KVTimeTest(nowTime1)
+			//	}
+			//}
+		}
+	})
+
+	if opt, ok := node.(rocommon.TCPSocketOption); ok {
+		opt.SetSocketBuff(40960*1024, 40960*1024, true)
+	}
+
+	property := node.(rocommon.ServerNodeProperty)
+	//服务器类型节点,区号,区号中的当前编号
+	property.SetServerType(serverConfig.Node.Type)
+	property.SetZone(serverConfig.Node.Zone)
+	property.SetIndex(serverConfig.Node.Id)
+	//session uuid 创建时的key
+	node.(rocommon.SessionMagExport).SetUuidCreateKey(serverConfig.Node.Id)
+
+	node.Start()
+
+	//注册到服务器发现etcd中
+	service.ETCDRegister(node)
+
+	//todo...添加到总的服务器管理中
+	return node
+}
+
+func CreateConnector(param ServiceParam) rocommon.ServerNode {
+	if param.ServiceType == "" {
+		param.ServiceType = "tcpConnector"
+	}
+
+	//通过服务器发现ETCD来实现连接
+	service.DiscoveryService(param.DiscoveryServiceName, param.DiscoveryServiceZone,
+		func(mn service.MultiServerNode, sd *service.ETCDServiceDesc) {
+			//不连接自己
+			serviceCfg := service.GetServiceConfig()
+			if sd.Type == serviceCfg.Node.Type && sd.Zone == serviceCfg.Node.Zone && sd.Index == serviceCfg.Node.Id {
+				return
+			}
+			node := socket.NewServerNode(param.ServiceType, param.ServiceName, sd.Host, Queue)
+			msgPrcFunc := serverproto.GetMessageHandler(param.ServiceName)
+			socket.SetProcessorRPC(node, param.ProcName, func(e rocommon.ProcEvent) {
+				if msgPrcFunc != nil {
+					msgPrcFunc(e)
+
+					//nowTime := util.GetTimeMilliseconds()
+					//msgPrcFunc(e)
+					//delTime := util.GetTimeMilliseconds() - nowTime
+					//if delTime > 5 {
+					//	log.Printf("deltime=%v msg=%T", util.GetTimeMilliseconds()-nowTime, e.(rocommon.ProcEvent).Msg())
+					//}
+				}
+			})
+			if opt, ok := node.(rocommon.TCPSocketOption); ok {
+				opt.SetSocketBuff(40960*1024, 40960*1024, true)
+				//15s无读写断开,服务器之间已经添加心跳来位置读写(非调试模式启动)
+				if !service.DebugMode {
+					opt.SetSocketDeadline(time.Second*15, time.Second*15)
+				}
+			}
+			//通过etcd服务器发现来处理,如果发现重复的节点会解除当前正在重连或者执行的节点
+			node.(rocommon.TCPConnector).SetReconnectTime(3 * time.Second)
+
+			//如果连接的是服务器的节点那么需要加入当前本节点的信息,用来处理服务器节点之间的身份验证
+			// ServerTCPEventHook中会使用
+			node.(rocommon.ContextSet).SetContextData("sid", sd, "sid")
+			//添加到服务器发现管理器中
+			mn.AddNode(sd, node)
+
+			//util.DebugF("NewServerNode:%v", node.TypeOfName())
+			node.Start()
+
+			//todo...添加到总的服务器管理中
+		})
+	if param.ServiceName != model.SERVICE_NODE_TYPE_CROSSROUTER_STR &&
+		param.ServiceName != model.SERVICE_NODE_TYPE_CROSSSERVER_STR {
+		service.InitServiceStartupTime(param.DiscoveryServiceZone)
+	}
+
+	return nil
+}
+
+//gate监听客户端处理
+func CreateClientAcceptor(param ServiceParam, serverConfig service.ConfigServerNode) rocommon.ServerNode {
+	if param.ServiceType == "" {
+		param.ServiceType = "tcpAcceptor"
+	}
+	//不需要要消息处理队列
+	//node := socket.NewServerNode(param.ServiceType, param.ServiceName, param.LisAddr, nil)
+	node := socket.NewServerNode(param.ServiceType, param.ServiceName, param.LisAddr, Queue)
+	//没有具体的消息处理逻辑
+	//socket.SetProcessorRPC(node, param.ProcName, nil)
+	msgPrcFunc := serverproto.GetMessageHandler(param.ServiceName)
+	socket.SetProcessorRPC(node, param.ProcName, func(e rocommon.ProcEvent) {
+		if msgPrcFunc != nil {
+			msgPrcFunc(e)
+		}
+	})
+	if opt, ok := node.(rocommon.TCPSocketOption); ok {
+		opt.SetSocketBuff(40960, 40960, true)
+
+		//40秒无读,30秒无写断开 如果没有心跳了超时直接断开,调试期间可以不加
+		// 通过该方法来模拟心跳保持连接
+		if serverConfig.Node.Reconnect > 0 {
+			opt.SetSocketDeadline(time.Second*40, time.Second*40)
+			//读/写协程没有过滤超时事件,发生了操时操作就断开连接
+		}
+	}
+
+	property := node.(rocommon.ServerNodeProperty)
+	//服务器类型节点,区号,区号中的当前编号
+	property.SetServerType(serverConfig.Node.Type)
+	property.SetZone(serverConfig.Node.Zone)
+	property.SetIndex(serverConfig.Node.Id)
+
+	//session uuid 创建时的key
+	node.(rocommon.SessionMagExport).SetUuidCreateKey(serverConfig.Node.Id)
+
+	node.Start()
+
+	//外层通过该对象来获取监听器上接收的链接
+	model.ClientSessionMag = node.(socket.SessionManager)
+
+	//注册到服务器发现etcd中
+	service.ETCDRegister(node)
+
+	//todo...添加到总的服务器管理中
+	return node
+}
+
+func CreateHttpConnector(param ServiceParam) rocommon.ServerNode {
+	if param.ServiceType == "" {
+		param.ServiceType = "httpConnector"
+	}
+	node := socket.NewServerNode(param.ServiceType, param.ServiceName, param.LisAddr, nil)
+	return node
+}
+
+//func CreateHttpAcceptor(param ServiceParam, serverConfig service.ConfigServerNode) rocommon.ServerNode {
+//	if param.ServiceType == "" {
+//		param.ServiceType = "httpAcceptor"
+//	}
+//	node := socket.NewServerNode(param.ServiceType, param.ServiceName, param.LisAddr, Queue)
+//
+//	msgPrcFunc := serverproto.GetMessageHandler(param.ServiceName)
+//	socket.SetProcessorRPC(node, param.ProcName, func(e rocommon.ProcEvent) {
+//		if matcher, ok := e.Session().(http.RequestProc); ok {
+//			msg.WebGMMsgProcess(matcher, e)
+//		} else {
+//			msgPrcFunc(e)
+//		}
+//	})
+//
+//	node.Start()
+//
+//	return node
+//}
+
+//gate监听客户端处理
+func CreateWebSocketAcceptor(param ServiceParam, serverConfig service.ConfigServerNode) rocommon.ServerNode {
+	if param.ServiceType == "" {
+		param.ServiceType = "wsAcceptor"
+	}
+	//不需要要消息处理队列
+	//node := socket.NewServerNode(param.ServiceType, param.ServiceName, param.LisAddr, nil)
+	node := socket.NewServerNode(param.ServiceType, param.ServiceName, param.LisAddr, Queue)
+	//没有具体的消息处理逻辑
+	//socket.SetProcessorRPC(node, param.ProcName, nil)
+	msgPrcFunc := serverproto.GetMessageHandler(param.ServiceName)
+	socket.SetProcessorRPC(node, param.ProcName, func(e rocommon.ProcEvent) {
+		if msgPrcFunc != nil {
+			msgPrcFunc(e)
+		}
+	})
+	if opt, ok := node.(rocommon.TCPSocketOption); ok {
+		opt.SetSocketBuff(11264, 11264, true)
+
+		//40秒无读,30秒无写断开 如果没有心跳了超时直接断开,调试期间可以不加
+		// 通过该方法来模拟心跳保持连接
+		if serverConfig.Node.Reconnect > 0 {
+			opt.SetSocketDeadline(time.Second*40, time.Second*40)
+			//读/写协程没有过滤超时事件,发生了操时操作就断开连接
+		}
+	}
+
+	property := node.(rocommon.ServerNodeProperty)
+	//服务器类型节点,区号,区号中的当前编号
+	property.SetServerType(serverConfig.Node.Type)
+	property.SetZone(serverConfig.Node.Zone)
+	property.SetIndex(serverConfig.Node.Id)
+
+	//session uuid 创建时的key
+	node.(rocommon.SessionMagExport).SetUuidCreateKey(serverConfig.Node.Id)
+
+	node.Start()
+
+	//外层通过该对象来获取监听器上接收的链接
+	model.ClientSessionMag = node.(socket.SessionManager)
+
+	//注册到服务器发现etcd中
+	service.ETCDRegister(node)
+
+	//todo...添加到总的服务器管理中
+	return node
+}

+ 149 - 0
RO_Server_Trunk-branch_0.1.39/roserver/baseserver/init_hooker.go

@@ -0,0 +1,149 @@
+package baseserver
+
+import (
+	"log"
+	"rocommon"
+	"rocommon/socket"
+	gatemodel "roserver/gate/model"
+)
+
+func init() {
+	log.SetFlags(log.Lshortfile | log.LstdFlags)
+	log.Println("base server init hooker [RegisterProcessRPC]")
+
+	//gate处理前端
+	socket.RegisterProcessRPC("gate.frontend",
+		func(b rocommon.ProcessorRPCBundle, userCb rocommon.EventCallBack, arg ...interface{}) {
+			b.SetTransmitter(new(gatemodel.DirectTCPMessageProcessor)) //直接传递数据或者返回数据给client,例如pingack
+
+			b.SetHooker(socket.NewMultiTCPEventHook(
+				new(gatemodel.FrontendTCPEventHook), //gate消息处理
+				new(socket.TCPEventHook),            //基础消息处理
+			))
+			b.SetCallback(socket.QueueEventCall(userCb))
+		})
+	//gate websocket前端处理
+	socket.RegisterProcessRPC("gatews.frontend",
+		func(b rocommon.ProcessorRPCBundle, userCb rocommon.EventCallBack, arg ...interface{}) {
+			b.SetTransmitter(new(gatemodel.DirectWSMessageTransmitter)) //直接传递数据或者返回数据给client,例如pingack
+
+			b.SetHooker(socket.NewMultiTCPEventHook(
+				new(gatemodel.FrontendTCPEventHook), //gate消息处理
+				new(socket.TCPEventHook),            //基础消息处理
+			))
+			b.SetCallback(socket.QueueEventCall(userCb))
+		})
+
+	//gate连接后端的处理
+	socket.RegisterProcessRPC("gate.backend",
+		func(b rocommon.ProcessorRPCBundle, userCb rocommon.EventCallBack, arg ...interface{}) {
+			b.SetTransmitter(new(socket.TCPMessageProcessor)) //pb 解析数据
+
+			b.SetHooker(socket.NewMultiTCPEventHook(
+				new(ServerTCPEventHook),                //服务器间互联消息处理
+				new(gatemodel.BroadcasterTCPEventHook), //gate消息处理
+				new(socket.TCPEventHook),               //基础消息处理
+			))
+			b.SetCallback(socket.QueueEventCall(userCb))
+		})
+
+	//todo...
+	//回调处理器绑定
+	//后端服务器处理
+	socket.RegisterProcessRPC("game.backend",
+		func(b rocommon.ProcessorRPCBundle, userCb rocommon.EventCallBack, arg ...interface{}) {
+			b.SetTransmitter(new(socket.TCPMessageProcessor)) //pb解析数据
+
+			b.SetHooker(socket.NewMultiTCPEventHook(
+				new(ServerTCPEventHook),  //服务器间互联消息处理
+				new(BackendTCPEventHook), //game服务器处理gate透传过来的消息
+				new(socket.TCPEventHook), //基础消息处理
+			))
+			b.SetCallback(socket.QueueEventCall(userCb))
+		})
+
+	//todo...
+	//db处理game的请求
+	socket.RegisterProcessRPC("db.backend",
+		func(b rocommon.ProcessorRPCBundle, userCb rocommon.EventCallBack, arg ...interface{}) {
+			b.SetTransmitter(new(socket.TCPMessageProcessor))
+
+			b.SetHooker(socket.MultiTCPEventHook{
+				new(ServerTCPEventHook),  //服务器间互联消息处理
+				new(ServiceTCPEventHook), //和db服务器相关的协议处理
+				new(socket.TCPEventHook), //基础消息处理
+			})
+			b.SetCallback(socket.QueueEventCall(userCb))
+		})
+
+	//auth处理gate请求,后续的登陆验证
+	socket.RegisterProcessRPC("auth.backend",
+		func(b rocommon.ProcessorRPCBundle, userCb rocommon.EventCallBack, arg ...interface{}) {
+			b.SetTransmitter(new(socket.TCPMessageProcessor))
+
+			b.SetHooker(socket.MultiTCPEventHook{
+				new(ServerTCPEventHook),  //服务器间互联消息处理
+				new(BackendTCPEventHook), //和gate服务器相关的协议处理
+				new(socket.TCPEventHook), //基础消息处理
+			})
+			b.SetCallback(socket.QueueEventCall(userCb))
+		})
+
+	//social处理聊天,好友,邮件等信息
+	socket.RegisterProcessRPC("social.backend",
+		func(b rocommon.ProcessorRPCBundle, userCb rocommon.EventCallBack, arg ...interface{}) {
+			b.SetTransmitter(new(socket.TCPMessageProcessor))
+
+			b.SetHooker(socket.MultiTCPEventHook{
+				new(ServerTCPEventHook),  //服务器间互联消息处理
+				new(BackendTCPEventHook), //和game服务器相关的协议处理
+				new(socket.TCPEventHook), //基础消息处理
+			})
+			b.SetCallback(socket.QueueEventCall(userCb))
+		})
+
+	//aoi同步处理
+	socket.RegisterProcessRPC("aoi.backend",
+		func(b rocommon.ProcessorRPCBundle, userCb rocommon.EventCallBack, arg ...interface{}) {
+			b.SetTransmitter(new(socket.TCPMessageProcessor))
+
+			b.SetHooker(socket.MultiTCPEventHook{
+				new(ServerTCPEventHook), //服务器间互联消息处理
+				new(BackendTCPEventHook),
+				new(socket.TCPEventHook), //基础消息处理
+			})
+			b.SetCallback(socket.QueueEventCall(userCb))
+		})
+
+	//common
+	socket.RegisterProcessRPC("common.backend",
+		func(b rocommon.ProcessorRPCBundle, userCb rocommon.EventCallBack, arg ...interface{}) {
+			b.SetTransmitter(new(socket.TCPMessageProcessor))
+
+			b.SetHooker(socket.MultiTCPEventHook{
+				new(ServerTCPEventHook), //服务器间互联消息处理
+				new(BackendTCPEventHook),
+				new(socket.TCPEventHook), //基础消息处理
+			})
+			b.SetCallback(socket.QueueEventCall(userCb))
+		})
+
+	//webgm
+	socket.RegisterProcessRPC("http",
+		func(b rocommon.ProcessorRPCBundle, userCb rocommon.EventCallBack, arg ...interface{}) {
+			b.SetCallback(socket.QueueEventCall(userCb))
+		})
+
+	//corssrouter
+	socket.RegisterProcessRPC("crossrouter.backend",
+		func(b rocommon.ProcessorRPCBundle, userCb rocommon.EventCallBack, arg ...interface{}) {
+			b.SetTransmitter(new(socket.TCPMessageProcessor))
+
+			b.SetHooker(socket.MultiTCPEventHook{
+				new(ServerTCPEventHook), //服务器间互联消息处理
+				new(BackendTCPEventForCrossRouterHook),
+				new(socket.TCPEventHook), //基础消息处理
+			})
+			b.SetCallback(socket.QueueEventCall(userCb))
+		})
+}

+ 7493 - 0
RO_Server_Trunk-branch_0.1.39/roserver/baseserver/model/base_config.go

@@ -0,0 +1,7493 @@
+package model
+
+import (
+	"errors"
+	"math/rand"
+	"reflect"
+	"rocommon/service"
+	"rocommon/util"
+	"roserver/baseserver/set"
+	"roserver/serverproto"
+	"sort"
+	"strconv"
+	"strings"
+	"time"
+)
+
+func BaseConfigInit(sConfig service.ConfigServerNode) {
+	path := sConfig.Node.Config + "/"
+	//不同服务器类型做不同配置文件加载(game服务器加载所有配置文件),内存优化处理
+	switch sConfig.Node.Type {
+	case SERVICE_NODE_TYPE_BOSS: //battleboss
+		serverproto.WorldBossCfgLoad(path + "csv/")
+		serverproto.WorldBossChangePlayCfgLoad(path + "csv/")
+		serverproto.NpcCfgLoad(path + "csv/")
+		convertWorldBossCfg()
+
+	case SERVICE_NODE_TYPE_GUILD: //guild
+		serverproto.GuildBossCfgLoad(path + "csv/")
+		serverproto.GuildBossRewardCfgLoad(path + "csv/")
+		serverproto.GuildWarDojoCfgLoad(path + "csv/")
+		serverproto.GuildLvCfgLoad(path + "csv/")
+		serverproto.GlobalCfgLoad(path + "csv/")
+		serverproto.GuildDemonCfgLoad(path + "csv/")
+		serverproto.GuildWarBuffCfgLoad(path + "csv/")
+		convertGlobalCfg()          //通用全局属性加载
+		convertGuildLevelCfg()      //公会等级相关
+		convertGuildBosRewardsCfg() //公会BOSS奖励
+		convertGuildBattleCfg()     //公会战
+		convertGuildDemonCfg()      //公会魔王
+		convertGuildWarCfg()
+
+	case SERVICE_NODE_TYPE_DB: //db
+		serverproto.PetCfgLoad(path + "csv/")
+		convertPetCfg() //pet
+
+	case SERVICE_NODE_TYPE_WEBGM: //gmweb
+		//添加到热更新列表中
+		serverproto.CFGNameList["AdvertisingScreen"] = serverproto.AdvertisingScreenLoad
+		serverproto.CFGNameList["CombinedServiceCfg"] = serverproto.CombinedServiceCfgLoad
+
+	case SERVICE_NODE_TYPE_RANK: //rank
+		serverproto.CompetitionCfgLoad(path + "csv/")
+		serverproto.HundredDojoCfgLoad(path + "csv/")
+		serverproto.RobotCfgLoad(path + "csv/")
+		serverproto.RushListCfgLoad(path + "csv/")
+		serverproto.RushListTargetCfgLoad(path + "csv/")
+		serverproto.GlobalCfgLoad(path + "csv/")
+		convertGlobalCfg()      //通用全局属性加载
+		convertCompetitionCfg() //赛季玩法
+		convertRobotCfg()
+		convertDaoChang100Cfg() //百人道场
+		convertRushListCfg()    //冲榜相关
+
+	case SERVICE_NODE_TYPE_CROSSSERVER:
+		serverproto.TransportCfgLoad(path + "csv/")
+		convertYuanHangTrailCfg() //远航试炼
+	case SERVICE_NODE_TYPE_CROSSRANK: //跨服排行榜
+		serverproto.TopTowerCfgLevelLoad(path + "csv/")
+		serverproto.TopTowerCfgRewardLoad(path + "csv/")
+		convertTopTowerCfg()
+	case SERVICE_NODE_TYPE_GLOBALCROSSMAP:
+		//TODO...
+
+	default:
+		//这边添加需要加载的配置文件列表,每个服务器不一样需要手动添加
+		//热加载,需要加锁处理
+		serverproto.ConfigInit(path + "csv/")
+		convertGlobalCfg()       //通用全局属性加载
+		convertUIFuncUnLockCfg() //功能解锁问题
+
+		//处理配置表数据,提高使用效率
+		convertQualityPointCfg()
+		convertCardCfg()
+		convertDropCfg() //关卡掉落
+		convertTaskCfg() //任务数据解析
+		convertParterProgressCfg()
+		convertParterSkillTreeCfg()
+		convertRoleAttributeCfg()
+		convertJobAttrCfg()
+		convertPartnerAttrCfg()
+		convertFashionCfg()
+		convertCardAttCfg()
+		convertEquipCfg()
+		convertEquipRefineCfg()
+		convertFightPowerCfg()
+		convertEquipSuitCfg()
+		//convertSlotCfg() //寻宝数据解析
+		convertChangeJobCfg()
+		convertArenaCfg(int32(sConfig.Node.Zone)) //竞技场
+		convertRobotCfg()                         //匹配机器人
+		convertWorldBossCfg()                     //世界boss
+		convertSkillUpEffect()                    //被动技能
+		convertCompetitionCfg()                   //赛季玩法
+		convertCompetitionPrizeWheelCfg()         //第三赛季转盘
+		convertCardResetCfg()                     //卡片分解
+		convertShopCfg()                          //商店
+		convertActiveCodeCfg()                    //激活码
+		convertSignInCfg()                        //签到
+		convertMapCfg()                           //关卡数据
+		convertNatureCfg()                        //属性对抗处理
+		convertTowerCfg()                         //爬塔奖励
+		convertEvilCfg()                          //恶魔协会
+		convertCardCollectCfg()                   //收集卡片奖励
+		//	convertVIPCfg()                       //vip相关次数
+		convertPetCfg()                   //pet
+		convertGuildLevelCfg()            //公会等级相关
+		convertGuildBosRewardsCfg()       //公会BOSS奖励
+		convertGuildBattleCfg()           //公会战
+		convertExpeditionCfg()            //远征之门
+		convertActivitiesCfg()            //精彩活动
+		convertHeadFrameCfg()             //头像框
+		convertInvitationCfg()            //invitation邀请码
+		convertVipCfg()                   //VIP
+		convertSummonCfg()                //抽卡
+		convertRuneCfg()                  //卢恩商会
+		convertRushListCfg()              //冲榜
+		convertDaoChang100Cfg()           //百人道场
+		convertKeepSakeCfg()              //藏品
+		convertCardSuitNewCfg()           //卡片祝福
+		covertFashionLevelUpCfg()         //时装升级
+		convertFashionRandomCfg()         //时装洗练
+		converFashionSuitCfg()            //套装升级
+		convertRuneShopExploreCfg()       // 战令升级
+		convertRuneShopExploreRewardCfg() // 战令
+		convertGuildWarCfg()              //公会战
+		convertOnlineTimeRewardCfg()      //累计在线时间奖励获取
+		convertQualityFruitCfg()          // 潜力果实
+		convertJobChangeCfg()             // 职业转职
+		convertSysRewardCfg()             //系统补偿数据表
+		convertCompetitionDevineCfg()     //占卜
+		convertYuanHangTrailCfg()         //远航试炼
+		convertActivitiesKingTaskCfg()    // 国王悬赏 任务
+		convertSkillEquipCfg()            // 神器
+		convertHeadDataCfg()              // 称号系统
+		convertGuildDemonCfg()            //公会魔王
+		convertTopTowerCfg()              //巅峰之塔
+		convertActivitySignInCfg()        //活动签到
+		convertIdolSeasonCfg()            //粉丝馈赠
+		convertWishCfg()                  //许愿宝箱
+		ConvertCombinedServer()           //合服
+	}
+
+	util.InfoF("config load success!!!")
+}
+
+// todo...热加载使用
+func ReloadConfig() {
+	sConfig := service.GetServiceConfig()
+	BaseConfigInit(sConfig)
+	util.InfoF("config reloead success!!!")
+}
+func ReloadConfigByName(cfgName string) {
+	sConfig := service.GetServiceConfig()
+	path := sConfig.Node.Config + "/csv/"
+	fuc, ok := serverproto.CFGNameList[cfgName]
+	if ok {
+		fuc(path)
+		//转换数据部分
+		switch cfgName {
+		case "Transport":
+			convertYuanHangTrailCfg()
+		}
+	}
+}
+
+var AdvSensitiveUtil *util.DFAUtil = nil
+
+func LoadAdvSensitiveWords() {
+	AdvSensitiveUtil = util.NewDFAUtil(nil)
+	for _, val := range serverproto.AdvertisingScreenLoader {
+		//valList := strings.Split(val.Type, ",")
+		util.DFAInsertWord(AdvSensitiveUtil, []string{val.Type})
+	}
+}
+func ReloadAdvSensitiveWords(cfgName string) {
+	sConfig := service.GetServiceConfig()
+	path := sConfig.Node.Config + "/csv/"
+	fuc, ok := serverproto.CFGNameList[cfgName]
+	if ok {
+		serverproto.AdvertisingScreenLoader = map[int32]*serverproto.AdvertisingScreen{}
+		fuc(path)
+		LoadAdvSensitiveWords()
+	}
+}
+
+// 功能解锁问题
+func convertUIFuncUnLockCfg() {
+	if cfgData, ok := serverproto.UIFuncUnLockCfgLoader[62]; ok {
+		if len(cfgData.UnlockCond) <= 0 {
+			return
+		}
+		k, v := Str2Res(cfgData.UnlockCond[0])
+		if k <= 0 || v <= 0 {
+			return
+		}
+		if k == int32(serverproto.TaskType_Level_Battle_Count) {
+			GlobalDaoChangUnlockMapLevelId = v
+		}
+	}
+}
+
+// 转换后的属性点消耗
+var AttrConsumeList = map[int32]int32{}
+
+func convertQualityPointCfg() {
+	//QulityPointCfg
+	var idList []int32
+	for _, data := range serverproto.QualityPointCfgLoader {
+		idList = append(idList, data.Count)
+	}
+	sort.Slice(idList, func(i, j int) bool {
+		return idList[i] < idList[j]
+	})
+
+	var count int32 = 1
+	AttrConsumeList[count] = 0
+	for _, id := range idList {
+		cfgData, ok := serverproto.QualityPointCfgLoader[id]
+		if ok {
+			_, ok := AttrConsumeList[id]
+			if !ok {
+				util.PanicF("[QulityPointCfg] data error:%v", id-1)
+			}
+			AttrConsumeList[id+1] = AttrConsumeList[id] + cfgData.Cost
+		}
+	}
+}
+
+// 卡片数据
+type CardWeightDat struct {
+	CardCfgId int32
+	Weight    int32
+}
+
+var CardNormalCfgList []*CardWeightDat
+var CardMiniCfgList []*CardWeightDat
+var CardMvpCfgList []*CardWeightDat
+
+var CardNormalWeightList []int32
+var CardMiniWeightList []int32
+var CardMvpWeightList []int32
+var ConvertCardList = map[int32]*ConvertCardData{}
+
+const (
+	Card_Type_Normal = 1
+	Card_Type_Mini   = 2
+	Card_Type_MVP    = 3
+)
+
+type ConvertCardData struct {
+	CardCfgId       int32
+	AttrList        map[int32]float32
+	TriggerBuffList map[int32]*serverproto.TriggerBuffData
+	SourceCfgId     int32
+}
+type ConvertCardUnlockData struct {
+	CardSlotId    int32
+	ConditionList []*serverproto.KeyValueType
+}
+
+var ConvertCardUnlock = map[int32]*ConvertCardUnlockData{}
+
+func convertCardCfg() {
+	CardNormalCfgList = []*CardWeightDat{}
+	CardMiniCfgList = []*CardWeightDat{}
+	CardMvpCfgList = []*CardWeightDat{}
+	CardNormalWeightList = []int32{}
+	CardMiniWeightList = []int32{}
+	CardMvpWeightList = []int32{}
+	ConvertCardList = map[int32]*ConvertCardData{}
+
+	curWeight := map[int32]int32{}
+	for _, data := range serverproto.CardCfgLoader {
+		ConvertCardList[data.CardId] = &ConvertCardData{
+			CardCfgId:       data.CardId,
+			AttrList:        map[int32]float32{},
+			TriggerBuffList: map[int32]*serverproto.TriggerBuffData{},
+		}
+		for idx := range data.Attribute1 {
+			key, value := Str2Res(data.Attribute1[idx])
+			if key > 0 && value > 0 {
+				ConvertCardList[data.CardId].AttrList[key] = float32(value)
+			}
+		}
+		for idx := range data.BUFF {
+			buffId, rate, cd, triggType := Str2Res_4(data.BUFF[idx])
+			if buffId > 0 {
+				ConvertCardList[data.CardId].TriggerBuffList[buffId] = &serverproto.TriggerBuffData{
+					BuffId:       uint32(buffId),
+					TriggerRatio: float32(rate) * 0.01,
+					Cd:           float32(cd),
+					TriggerType:  triggType,
+				}
+			}
+		}
+
+		if data.CardLevel > 1 {
+			continue
+		}
+
+		weight, _ := curWeight[data.CardType]
+		weight += data.Pro
+		cardData := &CardWeightDat{
+			CardCfgId: data.CardId,
+			Weight:    weight,
+		}
+		switch data.CardType {
+		case Card_Type_Normal:
+			CardNormalCfgList = append(CardNormalCfgList, cardData)
+		case Card_Type_Mini:
+			CardMiniCfgList = append(CardMiniCfgList, cardData)
+		case Card_Type_MVP:
+			CardMvpCfgList = append(CardMvpCfgList, cardData)
+		}
+		curWeight[data.CardType] = weight
+	}
+
+	cfgData, ok := serverproto.GlobalCfgLoader[int32(serverproto.GlobalType_Global_Card_Normal)]
+	if ok && cfgData.SVal != "" {
+		valList := strings.Split(cfgData.SVal, "-")
+		for i, _ := range valList {
+			weightVal, _ := Str2Num(valList[i])
+			CardNormalWeightList = append(CardNormalWeightList, int32(weightVal))
+		}
+	}
+
+	cfgMiniData, ok := serverproto.GlobalCfgLoader[int32(serverproto.GlobalType_Global_Card_Mini)]
+	if ok && cfgMiniData.SVal != "" {
+		valList := strings.Split(cfgMiniData.SVal, "-")
+		for i, _ := range valList {
+			weightVal, _ := Str2Num(valList[i])
+			CardMiniWeightList = append(CardMiniWeightList, int32(weightVal))
+		}
+	}
+
+	cfgMvpData, ok := serverproto.GlobalCfgLoader[int32(serverproto.GlobalType_Global_Card_Mvp)]
+	if ok && cfgMvpData.SVal != "" {
+		valList := strings.Split(cfgMvpData.SVal, "-")
+		for i, _ := range valList {
+			weightVal, _ := Str2Num(valList[i])
+			CardMvpWeightList = append(CardMvpWeightList, int32(weightVal))
+		}
+	}
+
+	//CardUnlockCfg
+	for _, data := range serverproto.CardUnlockCfgLoader {
+		addData := &ConvertCardUnlockData{
+			CardSlotId: data.CardSlotID,
+		}
+		for idx := 0; idx < len(data.UnlockingCondition); idx++ {
+			k, v := Str2Res(data.UnlockingCondition[idx])
+			if k > 0 && v > 0 {
+				addData.ConditionList = append(addData.ConditionList,
+					&serverproto.KeyValueType{Key: k, Value: v})
+			}
+		}
+		ConvertCardUnlock[addData.CardSlotId] = addData
+	}
+
+	for _, data := range ConvertCardList {
+		cardCfg, ok := serverproto.CardCfgLoader[data.CardCfgId]
+		if !ok || cardCfg.CardType <= 2 {
+			continue
+		}
+		if cardCfg.CardLevel == 1 || cardCfg.FromCardId == 0 {
+			data.SourceCfgId = data.CardCfgId
+			continue
+		}
+
+		sourceID := (data.CardCfgId/1000)*1000 + 100 + data.CardCfgId%100
+		_, ok2 := serverproto.CardCfgLoader[data.CardCfgId]
+		if !ok2 {
+			continue
+		}
+		data.SourceCfgId = sourceID
+	}
+}
+
+func GetCardSource(cardId int32) int32 {
+	cardData, ok := ConvertCardList[cardId]
+	if !ok {
+		return 0
+	}
+	return cardData.SourceCfgId
+}
+
+// DropCfg数据
+type WeightKeyValueData struct {
+	Weight   int32
+	Key      int32
+	MinValue int32
+	Maxvalue int32
+}
+
+func (this *WeightKeyValueData) GetValue() int32 {
+	if this.MinValue == this.Maxvalue || this.MinValue > this.Maxvalue {
+		return this.Maxvalue
+	}
+	return this.MinValue + rand.Int31n(this.Maxvalue-this.MinValue+1)
+}
+
+type ConvertDropData struct {
+	Id          int32
+	TotalWeight int32                 //掉了总权重
+	DropList    []*WeightKeyValueData //weight itemId,value
+}
+
+type ConvertPassBox struct {
+	ItemList []*serverproto.KeyValueType
+}
+type DecayData struct {
+	FactorParam int32
+	FactorList  []*serverproto.KeyValueType
+}
+type ConvertDecayData struct {
+	Id        int32
+	DecayList []*DecayData
+}
+
+func (this *ConvertDecayData) GetDecayList(kvList map[int32]int32, param uint64) {
+	if param <= 0 || len(this.DecayList) <= 0 {
+		return
+	}
+
+	bFindIdx := false
+	findIdx := 0
+	for idx := 0; idx < len(this.DecayList); idx++ {
+		if this.DecayList[idx].FactorParam > int32(param) {
+			break
+		}
+		bFindIdx = true
+		findIdx = idx
+	}
+	if bFindIdx {
+		if findIdx >= len(this.DecayList) {
+			findIdx = len(this.DecayList) - 1
+		}
+		for k := 0; k < len(this.DecayList[findIdx].FactorList); k++ {
+			kvItem := this.DecayList[findIdx].FactorList[k]
+			kvList[kvItem.Key] += kvItem.Value
+		}
+	}
+}
+
+var DropDataList = map[int32]*ConvertDropData{}
+var LevelDropCommonDataList = map[int32]*ConvertDropData{}
+var LevelDropBossDataList = map[int32]*ConvertDropData{}
+var LevelDropHDDataList = map[int32]*ConvertDropData{}
+var ConvertLevelPowerDecayFactorList = map[int32]*ConvertDecayData{}
+var ConvertLevelTimeDecayFactorList = map[int32]*ConvertDecayData{}
+var ConvertLevelSpAdd *serverproto.KeyValueType = nil
+
+//var LevelPassBox = map[int32]*ConvertPassBox{}
+
+func convertDropCfg() {
+	//dropCfg
+	for _, data := range serverproto.DropCfgLoader {
+		convertData := &ConvertDropData{
+			Id:          data.Id,
+			TotalWeight: 0,
+		}
+		DropDataList[data.Id] = convertData
+		for index, _ := range data.Drop1 {
+			weightVal, key, minValue, maxValue := Str2Res_4(data.Drop1[index])
+			convertData.TotalWeight += weightVal
+			convertData.DropList = append(convertData.DropList,
+				&WeightKeyValueData{Weight: convertData.TotalWeight, Key: key, MinValue: minValue, Maxvalue: maxValue})
+		}
+	}
+
+	//levelCfg
+	for _, data := range serverproto.LevelCfgLoader {
+		//关卡drop处理
+		commonData := &ConvertDropData{
+			Id:          data.Id,
+			TotalWeight: 0,
+		}
+		LevelDropCommonDataList[data.Id] = commonData
+		for index, _ := range data.DropOl {
+			weightVal, key := Str2Res(data.DropOl[index])
+			commonData.TotalWeight = weightVal
+			commonData.DropList = append(commonData.DropList,
+				&WeightKeyValueData{Weight: commonData.TotalWeight, Key: key})
+		}
+
+		hdCommonData := &ConvertDropData{
+			Id:          data.Id,
+			TotalWeight: 0,
+		}
+		LevelDropHDDataList[data.Id] = hdCommonData
+		for index, _ := range data.HdDrop {
+			weightVal, key, val := Str2Res_3(data.HdDrop[index])
+			hdCommonData.TotalWeight = weightVal
+			hdCommonData.DropList = append(hdCommonData.DropList,
+				&WeightKeyValueData{Weight: hdCommonData.TotalWeight, Key: key,
+					MinValue: val, Maxvalue: val})
+		}
+
+		//boss drop处理
+		bossData := &ConvertDropData{
+			Id:          data.Id,
+			TotalWeight: 0,
+		}
+		LevelDropBossDataList[data.Id] = bossData
+		for index, _ := range data.Drop {
+			weightVal, key := Str2Res(data.Drop[index])
+			bossData.TotalWeight = weightVal
+			bossData.DropList = append(bossData.DropList,
+				&WeightKeyValueData{Weight: bossData.TotalWeight, Key: key})
+		}
+
+		//难度衰减系数
+		//power
+		parseDecay(data.Id, data.PowerWeaken, ConvertLevelPowerDecayFactorList)
+		//time
+		parseDecay(data.Id, data.StayTimeWeaken, ConvertLevelTimeDecayFactorList)
+
+		//sp add
+		k, v := Str2Res(data.SpAddition)
+		if k > 0 && v > 0 {
+			ConvertLevelSpAdd = &serverproto.KeyValueType{Key: k, Value: v}
+		}
+	}
+}
+
+func parseDecay(id int32, decayStr string, convertData map[int32]*ConvertDecayData) {
+	decayData := &ConvertDecayData{
+		Id: id,
+	}
+	tmpDataList := strings.Split(decayStr, "|")
+	for idx := 0; idx < len(tmpDataList); idx++ {
+		tmpPramList := strings.Split(tmpDataList[idx], ";")
+		val, _ := Str2Num(tmpPramList[0])
+		tmpDecayData := &DecayData{
+			FactorParam: int32(val),
+		}
+		for k := 1; k < len(tmpPramList); k++ {
+			k, v := Str2Res(tmpPramList[k])
+			if k <= 0 {
+				continue
+			}
+			tmpDecayData.FactorList = append(tmpDecayData.FactorList, &serverproto.KeyValueType{Key: k, Value: v})
+		}
+		decayData.DecayList = append(decayData.DecayList, tmpDecayData)
+	}
+	convertData[decayData.Id] = decayData
+	sort.Slice(decayData.DecayList, func(i, j int) bool {
+		return decayData.DecayList[i].FactorParam < decayData.DecayList[j].FactorParam
+	})
+}
+
+func DropCfgProcess(dropList map[int32]int32, dropId int32) {
+	if dropId <= 0 {
+		return
+	}
+
+	dropData, ok := serverproto.DropCfgLoader[dropId]
+	convertDropData, ok1 := DropDataList[dropId]
+	if !ok || !ok1 {
+		util.ErrorF("dropProcess drop data not found dropId=%v ok=%v ok1=%v", dropId, ok, ok1)
+		return
+	}
+	//万分比随机
+	dropRate := rand.Int31n(10000)
+	if dropRate >= dropData.Rate {
+		return
+	}
+
+	if dropData.DropType <= 0 {
+		//累计权重随机
+		for i := 0; i < int(dropData.Times); i++ {
+			if convertDropData.TotalWeight <= 0 {
+				break
+			}
+			dropRate = rand.Int31n(convertDropData.TotalWeight)
+			for _, data := range convertDropData.DropList {
+				if data.Weight > dropRate && data.Key > 0 {
+					dropList[data.Key] += data.GetValue()
+					break
+				}
+			}
+		}
+	} else { //drop all
+		for _, data := range convertDropData.DropList {
+			if data.Key > 0 {
+				dropList[data.Key] += data.GetValue() * dropData.Times
+			}
+		}
+	}
+}
+
+// TargetTask配置数据
+// 解析任务结构数据,避免使用时重复解析
+type ConvertTaskData struct {
+	TaskId      uint32
+	TaskType    int32
+	PreTaskId   uint32 //前置任务ID
+	NextTaskId  uint32 //后续接取任务
+	TaskScore   int32  //获取奖励后的任务积分
+	IsBeginTask bool
+
+	Condition  map[int32][]int32
+	TaskReward []*serverproto.KeyValueType
+}
+
+type CovertTaskScoreData struct {
+	Idx          uint32
+	Active       int32
+	RewardList   []*serverproto.KeyValueType
+	HDRewardList []*serverproto.KeyValueType //活动期间制定掉落物品
+}
+
+var TargetTaskBeginID uint32 = 0
+var ConvertTaskList = map[uint32]*ConvertTaskData{}
+var ConvertAddTaskList = map[uint32]*ConvertTaskData{}
+var ConvertMainTaskOriginalList = map[uint32]uint32{} //[taskid,originaltask]
+var ConvertDailyTaskScoreRewardList = map[uint32]*CovertTaskScoreData{}
+var ConvertWeekTaskScoreRewardList = map[uint32]*CovertTaskScoreData{}
+
+const (
+	TASK_TYPE_DAILY = 1
+	TASK_TYPE_WEEK  = 2
+	TASK_TYPE_MAIN  = 3
+
+	TASK_TYPE_TODAY  = 4
+	TASK_TYPE_GROWUP = 5
+)
+
+func convertTaskCfg() {
+	//globalCfgData, ok := serverproto.GlobalCfgLoader[int32(serverproto.GlobalType_Global_Target_Task_Begin_ID)]
+	//if ok {
+	//	TargetTaskBeginID = uint32(globalCfgData.IVal)
+	//}
+	//
+	//for _, data := range serverproto.TargetTaskCfgLoader {
+	//	convertData := &ConvertTaskData{
+	//		TaskId:     uint32(data.TargetTaskId),
+	//		TaskType:   data.TargetTaskType,
+	//		NextTaskId: uint32(data.FollowTaskOld),
+	//		Condition:  map[int32][]int32{},
+	//	}
+	//
+	//	//任务条件
+	//	for index, _ := range data.TargetTaskCondition {
+	//		valueList := strings.Split(data.TargetTaskCondition[index], ":")
+	//		if len(valueList) >= 2 {
+	//			taskType, _ := Str2Num(valueList[0])
+	//			convertData.Condition[int32(taskType)] = append(convertData.Condition[int32(taskType)], int32(taskType))
+	//			for i := 1; i < len(valueList); i++ {
+	//				taskValue, _ := Str2Num(valueList[i])
+	//				convertData.Condition[int32(taskType)] = append(convertData.Condition[int32(taskType)], int32(taskValue))
+	//			}
+	//		}
+	//	}
+	//
+	//	//任务奖励
+	//	for index, _ := range data.TargetReward {
+	//		key, value := Str2Res(data.TargetReward[index])
+	//		convertData.TaskReward = append(convertData.TaskReward, &serverproto.KeyValueType{
+	//			Key:   key,
+	//			Value: value,
+	//		})
+	//	}
+	//
+	//	ConvertTaskList[convertData.TaskId] = convertData
+	//}
+
+	for _, data := range serverproto.MissionCfgLoader {
+		convertData := &ConvertTaskData{
+			TaskId:    uint32(data.MissionID),
+			TaskType:  data.MissionType,
+			TaskScore: data.Active,
+			Condition: map[int32][]int32{},
+		}
+
+		//任务条件
+		for index, _ := range data.MissionCondition {
+			valueList := strings.Split(data.MissionCondition[index], ":")
+			if len(valueList) >= 2 {
+				taskType, _ := Str2Num(valueList[0])
+				convertData.Condition[int32(taskType)] = append(convertData.Condition[int32(taskType)], int32(taskType))
+				for i := 1; i < len(valueList); i++ {
+					taskValue, _ := Str2Num(valueList[i])
+					convertData.Condition[int32(taskType)] = append(convertData.Condition[int32(taskType)], int32(taskValue))
+				}
+			}
+		}
+
+		ConvertTaskList[convertData.TaskId] = convertData
+		ConvertAddTaskList[convertData.TaskId] = convertData
+	}
+
+	for _, data := range serverproto.LineMissionCfgLoader {
+		convertData := &ConvertTaskData{
+			TaskId:    uint32(data.MissionID),
+			TaskType:  TASK_TYPE_MAIN,
+			Condition: map[int32][]int32{},
+		}
+
+		if data.BeginMission > 0 {
+			convertData.IsBeginTask = true
+		}
+		convertData.NextTaskId = uint32(data.FollowMissionld)
+
+		//任务条件
+		for index, _ := range data.MissionCondition {
+			valueList := strings.Split(data.MissionCondition[index], ":")
+			if len(valueList) >= 2 {
+				taskType, _ := Str2Num(valueList[0])
+				convertData.Condition[int32(taskType)] = append(convertData.Condition[int32(taskType)], int32(taskType))
+				for i := 1; i < len(valueList); i++ {
+					taskValue, _ := Str2Num(valueList[i])
+					convertData.Condition[int32(taskType)] = append(convertData.Condition[int32(taskType)], int32(taskValue))
+				}
+			}
+		}
+
+		//任务奖励
+		for index, _ := range data.Reward {
+			key, value := Str2Res(data.Reward[index])
+			convertData.TaskReward = append(convertData.TaskReward, &serverproto.KeyValueType{
+				Key:   key,
+				Value: value,
+			})
+		}
+
+		ConvertTaskList[convertData.TaskId] = convertData
+		if convertData.IsBeginTask {
+			ConvertAddTaskList[convertData.TaskId] = convertData
+		}
+	}
+	for _, originalTaskData := range ConvertAddTaskList {
+		if !originalTaskData.IsBeginTask {
+			continue
+		}
+		ConvertMainTaskOriginalList[originalTaskData.TaskId] = originalTaskData.TaskId
+		if originalTaskData.NextTaskId == 0 || originalTaskData.TaskId == originalTaskData.NextTaskId {
+			continue
+		}
+		ConvertMainTaskOriginalList[originalTaskData.NextTaskId] = originalTaskData.TaskId
+		originalTaskProcess(originalTaskData.NextTaskId)
+	}
+
+	//积分奖励
+	for _, data := range serverproto.ActRewardCfgLoader {
+		scoreInfo := &CovertTaskScoreData{
+			Idx:    uint32(data.ID),
+			Active: data.Active,
+		}
+		for index, _ := range data.Reward {
+			key, value := Str2Res(data.Reward[index])
+			if key <= 0 || value <= 0 {
+				continue
+			}
+			scoreInfo.RewardList = append(scoreInfo.RewardList, &serverproto.KeyValueType{
+				Key:   key,
+				Value: value,
+			})
+		}
+		for index, _ := range data.HdDrop {
+			key, value := Str2Res(data.HdDrop[index])
+			if key <= 0 || value <= 0 {
+				continue
+			}
+			scoreInfo.HDRewardList = append(scoreInfo.HDRewardList, &serverproto.KeyValueType{
+				Key:   key,
+				Value: value,
+			})
+		}
+
+		if data.ActiveType == TASK_TYPE_DAILY {
+			ConvertDailyTaskScoreRewardList[scoreInfo.Idx] = scoreInfo
+		} else if data.ActiveType == TASK_TYPE_WEEK {
+			ConvertWeekTaskScoreRewardList[scoreInfo.Idx] = scoreInfo
+		}
+	}
+}
+
+func originalTaskProcess(taskId uint32) {
+	if data, ok := serverproto.LineMissionCfgLoader[int32(taskId)]; ok && data.FollowMissionld > 0 {
+		if data.MissionID == data.FollowMissionld {
+			return
+		}
+		ConvertMainTaskOriginalList[uint32(data.FollowMissionld)] = ConvertMainTaskOriginalList[taskId]
+		originalTaskProcess(uint32(data.FollowMissionld))
+	}
+}
+
+// convertParterProgressCfg
+type ProgressLevelAttr struct {
+	AttrSet map[int32]map[int32]int32
+}
+
+var ProgressAttrContainer = map[int32]*ProgressLevelAttr{}
+
+type PartnerSkillSet struct {
+	SkillLevel map[int32][]int32
+}
+
+//var PartnerSkillContainer = map[int32]*PartnerSkillSet{}
+
+func convertParterProgressCfg() {
+	for _, data := range serverproto.ParterProgressCfgLoader {
+		paraStr := "Attribute"
+
+		t := reflect.ValueOf(data).Elem()
+		convertData := &ProgressLevelAttr{
+			AttrSet: map[int32]map[int32]int32{},
+		}
+		for i := 1; i <= int(data.Times); i++ {
+			keyStr := paraStr + strconv.Itoa(i)
+			v := t.FieldByName(keyStr).Interface()
+			var mapAttribute0 = make(map[int32]int32)
+			for _, str := range v.([]string) {
+				attrList := strings.Split(str, ":")
+				if len(attrList) >= 2 {
+					attrId, _ := Str2Num(attrList[0])
+					attrValue, _ := Str2Num(attrList[1])
+					mapAttribute0[int32(attrId)] = int32(attrValue)
+				}
+			}
+			convertData.AttrSet[int32(i-1)] = mapAttribute0
+		}
+		ProgressAttrContainer[data.Id] = convertData
+	}
+	convertStrengthCfg()
+}
+
+var ConvertPartnerSkillIdxList = map[int32]*serverproto.ParterSkillTreeCfg{}
+
+type ConvertSkillSlotData struct {
+	Id            int32
+	ConditionList []*serverproto.KeyValueType
+}
+
+var ConvertSkillSlotMain = map[int32]*ConvertSkillSlotData{}
+var ConvertSkillSlotPartner = map[int32]*ConvertSkillSlotData{}
+
+func convertParterSkillTreeCfg() {
+	for _, data := range serverproto.ParterSkillTreeCfgLoader {
+		ConvertPartnerSkillIdxList[data.SkillId] = data
+	}
+	convertSkillTree() //技能升级
+
+	for _, data := range serverproto.SkillSlotCfgLoader {
+		mainAddData := &ConvertSkillSlotData{
+			Id: data.ID,
+		}
+		for idx := 0; idx < len(data.SCondition); idx++ {
+			k, v := Str2Res(data.SCondition[idx])
+			if k > 0 && v > 0 {
+				mainAddData.ConditionList = append(mainAddData.ConditionList,
+					&serverproto.KeyValueType{Key: k, Value: v})
+			}
+		}
+		ConvertSkillSlotMain[mainAddData.Id] = mainAddData
+
+		partnerAddData := &ConvertSkillSlotData{
+			Id: data.ID,
+		}
+		for idx := 0; idx < len(data.SParterCondition); idx++ {
+			k, v := Str2Res(data.SParterCondition[idx])
+			if k > 0 && v > 0 {
+				partnerAddData.ConditionList = append(partnerAddData.ConditionList,
+					&serverproto.KeyValueType{Key: k, Value: v})
+			}
+		}
+		ConvertSkillSlotPartner[partnerAddData.Id] = partnerAddData
+	}
+}
+
+type StrengthCost struct {
+	CostList []*serverproto.KeyValueType
+}
+
+var PartnerStrengthCost = map[int32]*StrengthCost{}
+
+type StrengthAttr struct {
+	AttrSet map[int32]map[int32]int32
+}
+
+var StrengthAttrContainer = map[int32]*StrengthAttr{}
+
+// 伙伴突破 相关配置
+func convertStrengthCfg() {
+	for _, data := range serverproto.ParterProgressCfgLoader {
+		paraStr := "BreachAttribute"
+		convertData := &StrengthAttr{
+			AttrSet: map[int32]map[int32]int32{},
+		}
+		t := reflect.ValueOf(data).Elem()
+		for i := 1; i <= int(data.BreachTimes); i++ {
+			keyStr := paraStr + strconv.Itoa(i)
+			v := t.FieldByName(keyStr)
+			var mapAttribute0 = make(map[int32]int32)
+			for _, str := range v.Interface().([]string) {
+				attrList := strings.Split(str, ":")
+				if len(attrList) >= 2 {
+					attrId, _ := Str2Num(attrList[0])
+					attrValue, _ := Str2Num(attrList[1])
+					mapAttribute0[int32(attrId)] = int32(attrValue)
+				}
+			}
+			convertData.AttrSet[int32(i-1)] = mapAttribute0
+		}
+
+		convertCost := &StrengthCost{}
+		for index, _ := range data.BreachCost {
+			attrList := strings.Split(data.BreachCost[index], ":")
+			if len(attrList) >= 2 {
+				attrId, _ := Str2Num(attrList[0])
+				attrValue, _ := Str2Num(attrList[1])
+
+				convertCost.CostList = append(convertCost.CostList, &serverproto.KeyValueType{
+					Key:   int32(attrId),
+					Value: int32(attrValue),
+				})
+			}
+		}
+		PartnerStrengthCost[data.Id] = convertCost
+
+		StrengthAttrContainer[data.Id] = convertData
+	}
+}
+
+// 主角
+type RoleAttributeSet struct {
+	AttrSet []*serverproto.KeyValueType
+}
+
+var RoleAttrContainer = map[int32]*RoleAttributeSet{}
+
+func convertRoleAttributeCfg() {
+	for _, data := range serverproto.RoleAttributeCfgLoader {
+		convertData := &RoleAttributeSet{}
+		convertData.AttrSet = []*serverproto.KeyValueType{
+			{Key: int32(serverproto.Attr_Life), Value: data.Hp},
+			{Key: int32(serverproto.Attr_Sp), Value: data.Sp},
+			{Key: int32(serverproto.Attr_Attack), Value: data.Atk},
+			{Key: int32(serverproto.Attr_MagicAttack), Value: data.Matk},
+			{Key: int32(serverproto.Attr_Defense), Value: data.Def},
+			{Key: int32(serverproto.Attr_MagicDefense), Value: data.Mdef},
+			{Key: int32(serverproto.Attr_Hit), Value: data.Hit},
+			{Key: int32(serverproto.Attr_Dodge), Value: data.Dodge},
+			{Key: int32(serverproto.Attr_Crit), Value: data.Crit},
+			{Key: int32(serverproto.Attr_Ten), Value: data.Ten},
+		}
+		RoleAttrContainer[data.BaseLv] = convertData
+	}
+}
+
+// 主角
+type JobAttrSet struct {
+	//	AttrSet []*serverproto.KeyValueType
+	AttrSet map[int32]int32
+}
+
+var JobAttrContainer = map[int32]*JobAttrSet{}
+
+func convertJobAttrCfg() {
+	for _, data := range serverproto.JobCfgLoader {
+		convertData := &JobAttrSet{
+			AttrSet: map[int32]int32{},
+		}
+		convertData.AttrSet[int32(serverproto.Attr_Life)] = data.HpRate
+		convertData.AttrSet[int32(serverproto.Attr_Sp)] = data.SpRate
+		convertData.AttrSet[int32(serverproto.Attr_Attack)] = data.AtkRate
+		convertData.AttrSet[int32(serverproto.Attr_MagicAttack)] = data.MatkRate
+		convertData.AttrSet[int32(serverproto.Attr_Defense)] = data.DefRate
+		convertData.AttrSet[int32(serverproto.Attr_MagicDefense)] = data.MdefRate
+		convertData.AttrSet[int32(serverproto.Attr_Hit)] = data.HitRate
+		convertData.AttrSet[int32(serverproto.Attr_Dodge)] = data.DodgeRate
+		convertData.AttrSet[int32(serverproto.Attr_Crit)] = data.CritRate
+		convertData.AttrSet[int32(serverproto.Attr_Ten)] = data.TenRate
+		JobAttrContainer[data.Id] = convertData
+	}
+}
+
+// 伙伴
+type PartnerAttrSet struct {
+	AttrSet []*serverproto.KeyValueType
+}
+
+var PartnerAttrContainer = map[int32]*PartnerAttrSet{}
+
+func convertPartnerAttrCfg() {
+	for _, data := range serverproto.ParterCfgLoader {
+		convertData := &PartnerAttrSet{}
+		convertData.AttrSet = []*serverproto.KeyValueType{
+			{Key: int32(serverproto.Attr_Life), Value: data.Hp},
+			{Key: int32(serverproto.Attr_Sp), Value: data.Sp},
+			{Key: int32(serverproto.Attr_Attack), Value: data.Atk},
+			{Key: int32(serverproto.Attr_MagicAttack), Value: data.Matk},
+			{Key: int32(serverproto.Attr_Defense), Value: data.Def},
+			{Key: int32(serverproto.Attr_MagicDefense), Value: data.Mdef},
+			{Key: int32(serverproto.Attr_Hit), Value: data.Hit},
+			{Key: int32(serverproto.Attr_Dodge), Value: data.Dodge},
+			{Key: int32(serverproto.Attr_Crit), Value: data.Crit},
+			{Key: int32(serverproto.Attr_Ten), Value: data.Ten},
+			{Key: int32(serverproto.Attr_AttackSpeed), Value: data.Aspd},
+		}
+		PartnerAttrContainer[data.ParterId] = convertData
+	}
+}
+
+type FashionAttrSet struct {
+	AttrSet           []*serverproto.KeyValueType
+	FashionUseJobList []int32
+	FashionQuality    int32
+	//AttrNum           int32
+}
+
+//var FashionAttrContainer = map[int32]*FashionAttrSet{}
+
+var ConvertFashionPaperData = map[int32]map[int32]int32{}
+
+func convertFashionCfg() {
+	//for _, cfgData := range serverproto.FashionCfgLoader {
+	//	convertData := &FashionAttrSet{}
+	//	for _, attrSet := range cfgData.FashionAttr {
+	//		key, value := Str2Res(attrSet)
+	//		if key <= 0 || value <= 0 {
+	//			continue
+	//		}
+	//		convertData.AttrSet = append(convertData.AttrSet, &serverproto.KeyValueType{
+	//			Key:   key,
+	//			Value: value,
+	//		})
+	//	}
+	//
+	//	for idx := 0; idx < len(cfgData.FashionUseJob); idx++ {
+	//		useJob, _ := Str2Num(cfgData.FashionUseJob[idx])
+	//		convertData.FashionUseJobList = append(convertData.FashionUseJobList, int32(useJob))
+	//	}
+	//	//convertData.AttrNum = cfgData.AttrNum
+	//	convertData.FashionQuality = cfgData.FashionQuality
+	//	//FashionAttrContainer[int32(cfgData.FashionId)] = convertData
+	//}
+	//paper resolveItemList
+	for _, data := range serverproto.FashionPaperCfgLoader {
+		ConvertFashionPaperData[data.PaperId] = map[int32]int32{}
+		for idx := range data.ResolveItem {
+			key, val := Str2Res(data.ResolveItem[idx])
+			if key > 0 && val > 0 {
+				ConvertFashionPaperData[data.PaperId][key] += val
+			}
+		}
+	}
+}
+
+type CardAttrSet struct {
+	AttrSet []*serverproto.KeyValueType
+}
+
+var CardAttrContainer = map[int32]*CardAttrSet{}
+
+func convertCardAttCfg() {
+	for _, cfgData := range serverproto.CardCfgLoader {
+		convertData := &CardAttrSet{}
+		for _, attrSet := range cfgData.Attribute1 {
+			key, value := Str2Res(attrSet)
+			if key <= 0 || value <= 0 {
+				continue
+			}
+			convertData.AttrSet = append(convertData.AttrSet, &serverproto.KeyValueType{
+				Key:   key,
+				Value: value,
+			})
+		}
+		CardAttrContainer[int32(cfgData.CardId)] = convertData
+	}
+}
+
+type EquipAttributeSet struct {
+	AttrSet []*serverproto.KeyValueType
+	SuitId  int32
+}
+
+var EquipAttrContainer = map[int32]*EquipAttributeSet{}
+
+func convertEquipCfg() {
+	for _, data := range serverproto.EquipCfgLoader {
+		convertData := &EquipAttributeSet{
+			SuitId: data.Suit,
+		}
+		convertData.AttrSet = []*serverproto.KeyValueType{
+			{Key: int32(serverproto.Attr_Str), Value: data.Str},
+			{Key: int32(serverproto.Attr_Agi), Value: data.Agi},
+			{Key: int32(serverproto.Attr_Int), Value: data.Int},
+			{Key: int32(serverproto.Attr_Vit), Value: data.Vit},
+			{Key: int32(serverproto.Attr_Dex), Value: data.Dex},
+			{Key: int32(serverproto.Attr_Luk), Value: data.Luk},
+
+			{Key: int32(serverproto.Attr_Life), Value: data.Life},
+			{Key: int32(serverproto.Attr_Sp), Value: data.Sp},
+			{Key: int32(serverproto.Attr_Attack), Value: data.Attack},
+			{Key: int32(serverproto.Attr_MagicAttack), Value: data.MagicAttack},
+			{Key: int32(serverproto.Attr_Defense), Value: data.Defense},
+			{Key: int32(serverproto.Attr_MagicDefense), Value: data.MagicDefense},
+			{Key: int32(serverproto.Attr_Hit), Value: data.Hit},
+			{Key: int32(serverproto.Attr_Dodge), Value: data.Dodge},
+			{Key: int32(serverproto.Attr_Crit), Value: data.Crit},
+			{Key: int32(serverproto.Attr_Ten), Value: data.Ten},
+
+			{Key: int32(serverproto.Attr_PhysicDamage_Percent), Value: data.PhysicalDamageBonus},
+			{Key: int32(serverproto.Attr_MagicDamage_Percent), Value: data.MagicDamageBonus},
+			{Key: int32(serverproto.Attr_Attack_Percent), Value: data.AtkPercent},
+			{Key: int32(serverproto.Attr_MagicAttack_Percent), Value: data.MatkPercent},
+		}
+		EquipAttrContainer[data.Id] = convertData
+	}
+}
+
+// 神器id,星级,消耗材料map
+var SkillEquipStarLevelUpCostContainer = map[int32]map[int32]map[int32]int32{}
+
+// 返还 神器id,星级,返还材料map
+var SkillEquipDecomposeReturnContainer = map[int32]map[int32]map[int32]int32{}
+
+// 神器战力
+var SkillEquipAppendFightPowerContainer = map[int32]map[int32]int32{}
+
+// 神器技能  神器id,星级,技能id
+var SkillEquipAppendSkillContainer = map[int32]map[int32]int32{}
+
+// 神器槽位附加属性  槽位等级,属性map
+var SkillEquipSlotAppendAttrContainer = map[int32]map[serverproto.Attr]float32{}
+
+// 神器槽位升级消耗  槽位等级,消耗材料map
+var SkillEquipSlotLevelUpCostContainer = map[int32]map[int32]int32{}
+
+type SkillEquipRemake struct {
+	Id            int32 //批次
+	BeginDay      int32
+	EndDay        int32
+	CurBegin      uint64  //当前批次开始
+	CurEnd        uint64  //当前批次结束
+	CurForgePool  []int32 //当前重铸池子
+	RealPool      []int32 //实际重铸池子
+	NextForgePool []int32 //下一批重铸池子
+	NextBegin     uint64  //下一轮开始时间
+}
+
+var SkillEquipRemakePool = map[int32]*SkillEquipRemake{}
+
+type RemakeCost struct {
+	CostMap map[int32]int32
+}
+
+// 重铸消耗
+var SkillEquipRemakeCostContainer = map[int32]*RemakeCost{}
+
+func convertSkillEquipCfg() {
+	for _, data := range serverproto.ArtifactCfgLoader {
+		// 一个id 对应的所有星级的材料消耗
+		costs := map[int32]map[int32]int32{}
+		SkillEquipStarLevelUpCostContainer[data.Id] = costs
+		for k, v := range data.Condition {
+			resList := strings.Split(v, ":")
+			// 当前星级对应的材料消耗 消耗的itemid,itemnum
+			cost := map[int32]int32{}
+			costs[int32(k)] = cost
+			for _, v1 := range resList {
+				r1, r2 := Str2ResBySep(v1, "|")
+				_, ok1 := cost[r1]
+				if ok1 {
+					cost[r1] += r2
+				} else {
+					cost[r1] = r2
+				}
+			}
+		}
+
+		// 一个id 对应的所有星级的材料返还
+		retResLists := map[int32]map[int32]int32{}
+		SkillEquipDecomposeReturnContainer[data.Id] = retResLists
+		for k, v := range data.SmeltReturn {
+			resList := strings.Split(v, ":")
+			// 当前星级对应的材料返还 itemid,itemnum
+			retRes := map[int32]int32{}
+			retResLists[int32(k)] = retRes
+			for _, v1 := range resList {
+				r1, r2 := Str2ResBySep(v1, "|")
+				_, ok1 := retRes[r1]
+				if ok1 {
+					retRes[r1] += r2
+				} else {
+					retRes[r1] = r2
+				}
+			}
+		}
+
+		appendFights := map[int32]int32{}
+		SkillEquipAppendFightPowerContainer[data.Id] = appendFights
+		for k, v := range data.AddFight {
+			fight, error := Str2Num(v)
+			if error != nil {
+				util.PanicF("convertSkillEquipCfg AddFight id=%d", data.Id)
+				break
+			}
+			appendFights[int32(k)] = int32(fight)
+		}
+
+		//skillList := map[int32]int32{}
+		//SkillEquipAppendSkillContainer[data.Id] = skillList
+		//for k, v := range data.ArtifacFuncId {
+		//	skillId, error := Str2Num(v)
+		//	if error != nil {
+		//		util.ErrorF("convertSkillEquipCfg ArtifacFuncId id=%d", data.Id)
+		//		break
+		//	}
+		//	skillList[int32(k)] = int32(skillId)
+		//}
+		if len(data.ReforgeCost) >= 1 {
+			costConvert := &RemakeCost{
+				CostMap: map[int32]int32{},
+			}
+			for _, data := range data.ReforgeCost {
+				itemId, itemNum := Str2Res(data)
+				if itemId > 0 && itemNum > 0 {
+					costConvert.CostMap[itemId] += itemNum
+				}
+			}
+			SkillEquipRemakeCostContainer[data.Id] = costConvert
+		}
+
+		if data.Times != 0 {
+			poolData, ok := SkillEquipRemakePool[data.Times]
+			if !ok {
+				convertData := &SkillEquipRemake{
+					Id: data.Times,
+				}
+				startDay, endDay := Str2Res(data.ArtifactDuration[0])
+				convertData.BeginDay = startDay
+				convertData.EndDay = endDay
+
+				convertData.CurForgePool = append(convertData.CurForgePool, data.Id)
+				convertData.RealPool = append(convertData.RealPool, data.Id)
+				SkillEquipRemakePool[data.Times] = convertData
+			} else {
+				poolData.CurForgePool = append(poolData.CurForgePool, data.Id)
+				poolData.RealPool = append(poolData.RealPool, data.Id)
+			}
+		}
+	}
+
+	for i := 1; i <= len(SkillEquipRemakePool); i++ {
+		curPool, ok := SkillEquipRemakePool[int32(i)]
+		if !ok {
+			//异常(当前批次不应该找不到)
+			break
+		}
+		nextPool, okNext := SkillEquipRemakePool[int32(i+1)]
+		if !okNext {
+			//说明当前批次是最后一批
+			break
+		}
+
+		//初始化下一阶段的重铸池
+		curPool.NextForgePool = append(curPool.NextForgePool, nextPool.CurForgePool...)
+		curPool.NextBegin = nextPool.NextBegin
+
+		//初始化,下一阶段的重铸池子
+		nextPool.RealPool = append(nextPool.RealPool, curPool.RealPool...)
+	}
+
+	for _, data := range serverproto.ArtifactExpCfgLoader {
+		cost := map[int32]int32{}
+		SkillEquipSlotLevelUpCostContainer[data.ArtifactLevel] = cost
+		for _, v := range data.UpgradeCost {
+			r1, r2 := Str2Res(v)
+			_, ok1 := cost[r1]
+			if ok1 {
+				cost[r1] += r2
+			} else {
+				cost[r1] = r2
+			}
+		}
+
+		attr := map[serverproto.Attr]float32{}
+		SkillEquipSlotAppendAttrContainer[data.ArtifactLevel] = attr
+		for _, v := range data.Nature {
+			r1, r2 := Str2Res(v)
+			_, ok1 := attr[serverproto.Attr(r1)]
+			if ok1 {
+				attr[serverproto.Attr(r1)] += float32(r2)
+			} else {
+				attr[serverproto.Attr(r1)] = float32(r2)
+			}
+		}
+	}
+
+}
+
+func CheckNeedInitStartTime() {
+	loc := util.GetLoc()
+	startUpTime := service.GetServiceStartupTime()
+	if startUpTime < 0 {
+		util.ErrorF("[SkillEquipRemakePool] data error:%v")
+	}
+	startServer := time.Unix(int64(startUpTime/1000), 0).In(loc).Format(util.DATE_FORMAT1)
+	startUpDayStr := util.GetDayByTimeStr1(startServer)
+
+	for i := 1; i <= len(SkillEquipRemakePool); i++ {
+		_, ok := SkillEquipRemakePool[int32(i)]
+		if !ok {
+			return
+		}
+
+		if SkillEquipRemakePool[int32(i)].CurBegin <= 0 {
+			//计算开服时间
+			startTime := time.Unix(startUpDayStr.Unix()+int64(SkillEquipRemakePool[int32(i)].BeginDay-1)*int64(DaySec), 0).In(loc)
+			SkillEquipRemakePool[int32(i)].CurBegin = uint64(startTime.UnixNano()/1e6) + 3600*5*1000
+
+			if SkillEquipRemakePool[int32(i)].EndDay > 0 {
+				endTime := time.Unix(startUpDayStr.Unix()+int64(SkillEquipRemakePool[int32(i)].EndDay-1)*int64(DaySec), 0).In(loc)
+				SkillEquipRemakePool[int32(i)].CurEnd = uint64(endTime.UnixNano()/1e6) + 3600*5*1000
+			}
+
+			util.InfoF("[SkillEquipRemakePool] CurBegin:%v, CurEnd:%v", SkillEquipRemakePool[int32(i)].CurBegin, SkillEquipRemakePool[int32(i)].CurEnd)
+		}
+
+		if i > 1 {
+			_, ok2 := SkillEquipRemakePool[int32(i-1)]
+			if ok2 {
+				SkillEquipRemakePool[int32(i-1)].NextBegin = SkillEquipRemakePool[int32(i)].CurBegin
+			}
+		}
+	}
+}
+
+func GetCurForgePool() *SkillEquipRemake {
+	CheckNeedInitStartTime()
+	curTime := util.GetCurrentTime()
+
+	for i := 1; i <= len(SkillEquipRemakePool); i++ {
+		_, ok := SkillEquipRemakePool[int32(i)]
+		if !ok {
+			return nil
+		}
+		if SkillEquipRemakePool[int32(i)].CurBegin <= 0 {
+			return nil
+		}
+
+		if i == 1 {
+			if curTime < SkillEquipRemakePool[int32(i)].CurBegin {
+				return nil
+			}
+		}
+
+		if SkillEquipRemakePool[int32(i)].CurBegin <= curTime {
+			if (SkillEquipRemakePool[int32(i)].CurEnd != 0 && curTime < SkillEquipRemakePool[int32(i)].CurEnd) ||
+				SkillEquipRemakePool[int32(i)].CurEnd == 0 {
+				return SkillEquipRemakePool[int32(i)]
+			}
+		}
+	}
+	return nil
+}
+
+type EquipRefineSet struct {
+	AttrSet []*serverproto.KeyValueType
+}
+
+var EquipRefineContainer = map[int32]*EquipRefineSet{}
+
+func convertEquipRefineCfg() {
+	for _, data := range serverproto.EquipRefineCfgLoader {
+		convertData := &EquipRefineSet{}
+		for idx := range data.SuitServer {
+			key, value := Str2Res(data.SuitServer[idx])
+			if key <= 0 || value <= 0 {
+				continue
+			}
+			convertData.AttrSet = append(convertData.AttrSet, &serverproto.KeyValueType{
+				Key:   key,
+				Value: value,
+			})
+		}
+		EquipRefineContainer[int32(data.Id)] = convertData
+	}
+}
+
+type FightPowerSet struct {
+	AttrSet []*serverproto.KeyValueType
+	Mapping int32
+}
+
+var FightPowerContainer = map[int32]*FightPowerSet{}
+
+var ConvertFightPower = map[int32]map[int32]int32{} //[jobtype][attrkey][attrval]
+
+func convertFightPowerCfg() {
+	for _, data := range serverproto.FightCfgLoader {
+		convertData := &FightPowerSet{}
+		for _, attrData := range data.Coefficient {
+			key, value := Str2Res(attrData)
+			if key < 0 || value <= 0 {
+				continue
+			}
+			convertData.AttrSet = append(convertData.AttrSet, &serverproto.KeyValueType{
+				Key:   key,
+				Value: value,
+			})
+		}
+		convertData.Mapping = data.Mapping
+
+		FightPowerContainer[int32(data.Id)] = convertData
+
+		for idx := 0; idx < len(data.Coefficient); idx++ {
+			k, v := Str2Res(data.Coefficient[idx])
+			if _, ok := ConvertFightPower[k]; !ok {
+				ConvertFightPower[k] = map[int32]int32{}
+			}
+			ConvertFightPower[k][data.Id] = v
+		}
+	}
+}
+
+type EquipSuitAttr struct {
+	AttrSet map[int32]map[int32]int32
+}
+
+var SuitAttrContainer = map[int32]*EquipSuitAttr{}
+
+func convertEquipSuitCfg() {
+	for _, data := range serverproto.EquipSuitNewCfgLoader {
+		convertData := &EquipSuitAttr{
+			AttrSet: map[int32]map[int32]int32{},
+		}
+		var mapAttribute0 map[int32]int32
+		mapAttribute0 = make(map[int32]int32)
+		for index, _ := range data.Suit1 {
+			key, value := Str2Res(data.Suit1[index])
+			if key <= 0 || value <= 0 {
+				continue
+			}
+			mapAttribute0[key] = value
+		}
+		convertData.AttrSet[0] = mapAttribute0
+
+		var mapAttribute1 map[int32]int32
+		mapAttribute1 = make(map[int32]int32)
+		for index, _ := range data.Suit2 {
+			key, value := Str2Res(data.Suit2[index])
+			if key <= 0 || value <= 0 {
+				continue
+			}
+			mapAttribute1[key] = value
+		}
+		convertData.AttrSet[1] = mapAttribute1
+
+		var mapAttribute2 map[int32]int32
+		mapAttribute2 = make(map[int32]int32)
+		for index, _ := range data.Suit3 {
+			key, value := Str2Res(data.Suit3[index])
+			if key <= 0 || value <= 0 {
+				continue
+			}
+			mapAttribute2[key] = value
+		}
+		convertData.AttrSet[2] = mapAttribute2
+
+		SuitAttrContainer[int32(data.Id)] = convertData
+	}
+}
+
+type ChangeCondition struct {
+	Condition map[int32][]int32
+}
+
+var ChangeJobCond = map[int32]*ChangeCondition{}
+
+func convertChangeJobCfg() {
+	for _, data := range serverproto.ConditionCfgLoader {
+		convertData := &ChangeCondition{
+			Condition: make(map[int32][]int32),
+		}
+		for _, subData := range data.Condition {
+			condList := strings.Split(subData, ":")
+			if len(condList) < 2 {
+				continue
+			}
+			taskType, _ := Str2Num(condList[0])
+			convertData.Condition[int32(taskType)] = append(convertData.Condition[int32(taskType)], int32(taskType))
+			for i := 1; i < len(condList); i++ {
+				cfgValue, _ := Str2Num(condList[i])
+				convertData.Condition[int32(taskType)] = append(convertData.Condition[int32(taskType)], int32(cfgValue))
+			}
+		}
+		ChangeJobCond[data.ConditionId] = convertData
+	}
+}
+
+type ArenaRankSeasonInfo struct {
+	ZoneId                   int32
+	SeasonId                 int32
+	RewardInfo               []*ArenaRankRewardInfo
+	Duration                 int32
+	Reset                    int32
+	StartTimeStr, EndTimeStr string
+	StartTime, EndTime       time.Time
+
+	DiffDurationDay int64
+}
+type ArenaRankRewardInfo struct {
+	Left, Right int32
+	RewardList  map[int32]int32
+}
+
+// var ConvertArenaSeasonReward = map[int32]*ArenaRankSeasonInfo{} //赛季对应top排行奖励
+var ConvertArenaSeason *ArenaRankSeasonInfo = nil
+
+type ArenaMatchInfo struct {
+	LevelId                                          int32           //段位ID
+	MinScore                                         int32           //段位对应的最低分
+	Score                                            int32           //段位对应的最高分
+	ScoreRewardList, WinRewardList, FailedRewardList map[int32]int32 //段位奖励 胜利奖励 失败奖励
+	WinScore, WinScore1, WinScore2                   int32           //score 与强敌胜利获得积分
+	FailedScore, FailedScore1, FailedScore2          int32
+	ScoreSectionLeft, ScoreSectionRight              float32 //强弱区间
+	WinStreak                                        []int32
+	//match
+	WinMatchList, FailedMatchList []serverproto.KeyValueType
+	LevelReduce                   int32
+}
+
+var ConvertArenaMatch []*ArenaMatchInfo //arena胜利失败奖励
+var ConvertArenaMatchList = map[int32]*ArenaMatchInfo{}
+var ConvertScoreToArenaLevelList = map[int32]int32{} //最低分数对应段位
+var MinTopRankScore int32 = 0                        //入top排行榜最低积分(段位的积分)
+
+func convertArenaCfg(zoneId int32) {
+	//clean for reload
+	ConvertArenaMatch = []*ArenaMatchInfo{}
+	ConvertArenaMatchList = map[int32]*ArenaMatchInfo{}
+	ConvertScoreToArenaLevelList = map[int32]int32{}
+	MinTopRankScore = 0
+
+	//ArenaRewardCfg
+	//加载对应服务器赛季数据
+	for _, data := range serverproto.ArenaRewardCfgLoader {
+		if data.Zone != zoneId {
+			continue
+		}
+
+		if ConvertArenaSeason == nil {
+			ConvertArenaSeason = &ArenaRankSeasonInfo{
+				ZoneId:   data.Zone,
+				SeasonId: 0,
+			}
+		}
+		if data.StartTime != "" && data.CloseTime != "" {
+			//loc := util.GetLoc()
+			//sTime, err1 := time.ParseInLocation(util.DATE_FORMAT, data.StartTime, loc)
+			//if err1 != nil {
+			//	util.PanicF("convertArenaCfg startTime err:%v", err1)
+			//}
+			//ConvertArenaSeason.StartTime = sTime
+			ConvertArenaSeason.StartTimeStr = data.StartTime
+
+			//cTime, err2 := time.ParseInLocation(util.DATE_FORMAT, data.CloseTime, loc)
+			//if err2 != nil {
+			//	util.PanicF("convertArenaCfg endTime err:%v", err2)
+			//}
+			//ConvertArenaSeason.EndTime = cTime
+			ConvertArenaSeason.EndTimeStr = data.CloseTime
+		}
+
+		rankRewardInfo := &ArenaRankRewardInfo{
+			RewardList: map[int32]int32{},
+		}
+		if len(data.ArenaRank) > 1 {
+			left, _ := Str2Num(data.ArenaRank[0])
+			right, _ := Str2Num(data.ArenaRank[1])
+			rankRewardInfo.Left = int32(left)
+			rankRewardInfo.Right = int32(right)
+		} else {
+			left, _ := Str2Num(data.ArenaRank[0])
+			rankRewardInfo.Left = int32(left)
+		}
+
+		for idx := range data.ArenaReward {
+			key, value := Str2Res(data.ArenaReward[idx])
+			rankRewardInfo.RewardList[key] += value
+		}
+		ConvertArenaSeason.RewardInfo = append(ConvertArenaSeason.RewardInfo, rankRewardInfo)
+		ConvertArenaSeason.Reset = data.Rest
+	}
+	//未找到对应zone数据,默认使用zone=1数据
+	zoneId = 1
+	if ConvertArenaSeason == nil {
+		for _, data := range serverproto.ArenaRewardCfgLoader {
+			if data.Zone != zoneId {
+				continue
+			}
+
+			if ConvertArenaSeason == nil {
+				ConvertArenaSeason = &ArenaRankSeasonInfo{
+					ZoneId:   data.Zone,
+					SeasonId: 0,
+				}
+			}
+			if data.StartTime != "" && data.CloseTime != "" {
+				//loc := util.GetLoc()
+				//sTime, err1 := time.ParseInLocation(util.DATE_FORMAT, data.StartTime, loc)
+				//if err1 != nil {
+				//	util.PanicF("convertArenaCfg startTime err:%v", err1)
+				//}
+				//ConvertArenaSeason.StartTime = sTime
+				ConvertArenaSeason.StartTimeStr = data.StartTime
+
+				//cTime, err2 := time.ParseInLocation(util.DATE_FORMAT, data.CloseTime, loc)
+				//if err2 != nil {
+				//	util.PanicF("convertArenaCfg endTime err:%v", err2)
+				//}
+				//ConvertArenaSeason.EndTime = cTime
+				ConvertArenaSeason.EndTimeStr = data.CloseTime
+			}
+
+			rankRewardInfo := &ArenaRankRewardInfo{
+				RewardList: map[int32]int32{},
+			}
+			if len(data.ArenaRank) > 1 {
+				left, _ := Str2Num(data.ArenaRank[0])
+				right, _ := Str2Num(data.ArenaRank[1])
+				rankRewardInfo.Left = int32(left)
+				rankRewardInfo.Right = int32(right)
+			} else {
+				left, _ := Str2Num(data.ArenaRank[0])
+				rankRewardInfo.Left = int32(left)
+			}
+
+			for idx := range data.ArenaReward {
+				key, value := Str2Res(data.ArenaReward[idx])
+				rankRewardInfo.RewardList[key] += value
+			}
+			ConvertArenaSeason.RewardInfo = append(ConvertArenaSeason.RewardInfo, rankRewardInfo)
+			ConvertArenaSeason.Reset = data.Rest
+		}
+	}
+
+	sort.Slice(ConvertArenaSeason.RewardInfo, func(i, j int) bool {
+		return ConvertArenaSeason.RewardInfo[i].Left < ConvertArenaSeason.RewardInfo[j].Left
+	})
+	ConvertArenaSeason.DiffDurationDay = util.GetDurationDay(ConvertArenaSeason.StartTimeStr, ConvertArenaSeason.EndTimeStr)
+
+	//ArenaLevelCfg
+	var minScore int32 = 0
+	var levelKeyList []int32
+	for _, data := range serverproto.ArenaLevelCfgLoader {
+		levelKeyList = append(levelKeyList, data.ArenaLevelId)
+	}
+	sort.Slice(levelKeyList, func(i, j int) bool {
+		return levelKeyList[i] < levelKeyList[j]
+	})
+	for idx := 0; idx < len(levelKeyList); idx++ {
+		data := serverproto.ArenaLevelCfgLoader[levelKeyList[idx]]
+		info := &ArenaMatchInfo{
+			LevelId:          data.ArenaLevelId,
+			Score:            data.ArenaLevelScore,
+			ScoreRewardList:  map[int32]int32{},
+			WinRewardList:    map[int32]int32{},
+			FailedRewardList: map[int32]int32{},
+			WinScore:         data.WinScore,
+			WinScore1:        data.WinScore1,
+			WinScore2:        data.WinScore2,
+			FailedScore:      data.LostScore,
+			FailedScore1:     data.LostScore1,
+			FailedScore2:     data.LostScore2,
+		}
+
+		for idx := range data.ArenaLevelReward {
+			key, value := Str2Res(data.ArenaLevelReward[idx])
+			if key > 0 && value > 0 {
+				info.ScoreRewardList[key] = value
+			}
+		}
+		for idx := range data.WinReward {
+			key, value := Str2Res(data.WinReward[idx])
+			if key > 0 && value > 0 {
+				info.WinRewardList[key] = value
+			}
+		}
+		for idx := range data.FailReward {
+			key, value := Str2Res(data.FailReward[idx])
+			if key > 0 && value > 0 {
+				info.FailedRewardList[key] = value
+			}
+		}
+		if len(data.Section) == 2 {
+			left, _ := Str2Num(data.Section[0])
+			right, _ := Str2Num(data.Section[1])
+			info.ScoreSectionLeft = 1 + float32(left)*0.01
+			info.ScoreSectionRight = 1 + float32(right)*0.01
+		}
+		info.WinStreak = append(info.WinStreak, 0)
+		for idx := range data.WinStreak {
+			val, _ := Str2Num(data.WinStreak[idx])
+			info.WinStreak = append(info.WinStreak, int32(val))
+		}
+		for idx := range data.Win {
+			left, right := Str2Res(data.Win[idx])
+			info.WinMatchList = append(info.WinMatchList, serverproto.KeyValueType{Key: left, Value: right})
+		}
+		for idx := range data.Fail {
+			left, right := Str2Res(data.Fail[idx])
+			info.FailedMatchList = append(info.FailedMatchList, serverproto.KeyValueType{Key: left, Value: right})
+		}
+		info.LevelReduce = data.LevelReduce
+		if minScore == 0 {
+			info.MinScore = minScore
+		} else {
+			info.MinScore = minScore + 1
+		}
+		ConvertArenaMatch = append(ConvertArenaMatch, info)
+		ConvertArenaMatchList[info.LevelId] = info
+		ConvertScoreToArenaLevelList[info.MinScore] = info.LevelId
+		minScore = info.Score
+	}
+	sort.Slice(ConvertArenaMatch, func(i, j int) bool {
+		return ConvertArenaMatch[i].Score < ConvertArenaMatch[j].Score
+	})
+	MinTopRankScore = ConvertArenaMatch[len(ConvertArenaMatch)-3].MinScore
+}
+
+type ConvertDaoChang100Info struct {
+	posIdx         int32
+	posIdxType     int32
+	PosIdxFuncType int32
+	RewardList     []*serverproto.KeyValueType
+	RobotId        int32
+	TimeProtect    uint64
+	TimeReward     uint64
+}
+
+var ConvertDaoChang100List = map[int32]*ConvertDaoChang100Info{}
+
+func convertDaoChang100Cfg() {
+	for _, data := range serverproto.HundredDojoCfgLoader {
+		info := &ConvertDaoChang100Info{
+			posIdx:         data.Id,
+			posIdxType:     data.AreaType,
+			PosIdxFuncType: data.FunType,
+			RobotId:        data.Robot,
+			TimeProtect:    uint64(data.TimeProtect) * 60 * 1000,
+			TimeReward:     uint64(data.TimeReward) * 60 * 1000,
+		}
+		for idx := 0; idx < len(data.RewardList); idx++ {
+			k, v := Str2Res(data.RewardList[idx])
+			if k > 0 && v > 0 {
+				info.RewardList = append(info.RewardList, &serverproto.KeyValueType{Key: k, Value: v})
+			}
+		}
+
+		if data.FunType == 1 {
+			if _, ok := ConvertRobotDaoChang100[data.Robot]; !ok {
+				panic("ConvertRobotDaoChang100 nil")
+			}
+		}
+
+		ConvertDaoChang100List[info.posIdx] = info
+	}
+}
+
+type ConvertPartnerInfo struct {
+	PartnerId int32
+	EquipList []int32
+	Level     int32
+}
+type ConvertRobotInfo struct {
+	RobotId       int32
+	RobotName     string
+	ArenaId       int32
+	Level         int32
+	Avatar        int32
+	EquipList     []int32
+	SkillList     []int32
+	Head          int32
+	PartnerIdList []*ConvertPartnerInfo
+	FightInfo     *serverproto.FightRoleInfo
+}
+
+func (this *ConvertRobotInfo) initFightInfo() {
+	this.FightInfo = &serverproto.FightRoleInfo{
+		IsRobot: true,
+		BriefInfo: &serverproto.CommonPlayerBriefInfo{
+			Uid:      uint64(this.RobotId),
+			NickName: this.RobotName,
+		},
+	}
+}
+
+var ConvertArenaRobot []int32 //[ArenaLevelId,RobotId]
+var ConvertRobot = map[int32]*ConvertRobotInfo{}
+var ConvertRobotDaoChang100 = map[int32]*ConvertRobotInfo{}
+var ConvertRobotCrossTopTower []*ConvertRobotInfo
+
+func convertRobotCfg() {
+	//clean for reload
+	ConvertArenaRobot = []int32{}
+	ConvertRobot = map[int32]*ConvertRobotInfo{}
+	ConvertRobotDaoChang100 = map[int32]*ConvertRobotInfo{}
+
+	for _, data := range serverproto.RobotCfgLoader {
+		//道场使用(段位对应机器人列表)
+		ConvertArenaRobot = append(ConvertArenaRobot, data.RobotId)
+
+		robotData := &ConvertRobotInfo{
+			RobotId:   data.RobotId,
+			ArenaId:   data.ArenaLevelId,
+			Level:     data.RobotLevel,
+			Avatar:    data.RobotAvatar,
+			Head:      data.RobotHeadPortrait,
+			RobotName: data.RobotName,
+		}
+		for idx := range data.RobotEquip {
+			equipId, _ := Str2Num(data.RobotEquip[idx])
+			robotData.EquipList = append(robotData.EquipList, int32(equipId))
+		}
+		for idx := range data.RobotSkill {
+			skillId, _ := Str2Num(data.RobotSkill[idx])
+			robotData.SkillList = append(robotData.SkillList, int32(skillId))
+		}
+		//伙伴列表
+		for idx := range data.PartnerId {
+			partnerInfo := &ConvertPartnerInfo{}
+			partnerId, _ := Str2Num(data.PartnerId[idx])
+			partnerInfo.PartnerId = int32(partnerId)
+			//伙伴装备
+			partnerEquipStrList := strings.Split(data.PartnerEquip[idx], ":")
+			for j := range partnerEquipStrList {
+				partnerEquipId, _ := Str2Num(partnerEquipStrList[j])
+				partnerInfo.EquipList = append(partnerInfo.EquipList, int32(partnerEquipId))
+			}
+			//伙伴等级
+			partnerLevel, _ := Str2Num(data.PartnerLevel[idx])
+			partnerInfo.Level = int32(partnerLevel)
+
+			robotData.PartnerIdList = append(robotData.PartnerIdList, partnerInfo)
+		}
+		robotData.initFightInfo()
+
+		switch data.SystemType {
+		case 0:
+			ConvertRobot[data.RobotId] = robotData
+		case 1:
+			ConvertRobotDaoChang100[data.RobotId] = robotData
+		case 2:
+			ConvertRobotCrossTopTower = append(ConvertRobotCrossTopTower, robotData)
+			//ConvertRobotCrossTopTower[data.RobotId] = robotData
+		}
+	}
+}
+
+// WorldBossCfg
+var ConvertWorldBoss = map[int32][]*ConvertWorldBossData{} //[1,info][2,info][3,info][0,info]
+
+type KillRewardInfo struct {
+	RewardWeight    int32
+	DeductionWeight int32
+	RewardList      []*serverproto.KeyValueType //1大奖,2中奖,3参与奖
+}
+
+const (
+	SummonBossType_Normal     = iota //普通世界boss
+	SummonBossType_ChangePlay        //变身世界boss
+)
+
+type ConvertWorldBossData struct {
+	Id           int32
+	RefreshId    int32
+	SummonId     int32
+	SummonType   int32       //
+	StartDay     int32       //=0表示根据给定的时间来开启[BossBeginTime,BossEndTime]
+	SummonTime   []time.Time //刷新时间
+	DurationTime int32
+
+	RollTotalWeight int32
+	DeductionWeight int32
+	RollList        []*KillRewardInfo
+	ReduceHp        *serverproto.KeyValueType //1大奖,2中奖,3参与奖
+
+	RefreshTime time.Time //刷新boss的时间错,逻辑中使用
+
+	//WorldBossChangePlay
+	BossBeginTimeStamp    uint64
+	BossEndTimeStmp       uint64
+	BossBeginTime         time.Time
+	BossEndTime           time.Time
+	ConsumeList           map[int32]int32
+	ChangePlayIdList      []*serverproto.KeyValueType
+	TotalChangePlayWeight int32
+}
+
+func (this *ConvertWorldBossData) RandChangePlayId() int32 {
+	var retBossId int32 = 0
+	randWeight := rand.Int31n(this.TotalChangePlayWeight) + 1
+	for idx := 0; idx < len(this.ChangePlayIdList); idx++ {
+		retBossId = this.ChangePlayIdList[idx].Key
+		if this.ChangePlayIdList[idx].Value >= randWeight {
+			break
+		}
+	}
+	return retBossId
+}
+
+var ConvertWorldBossList = map[int32]*ConvertWorldBossData{}
+var ConvertWorldBossChangePlayList = map[int32]*ConvertWorldBossData{}
+
+func convertWorldBossCfg() {
+	//WorldBossCfg
+	for _, data := range serverproto.WorldBossCfgLoader {
+		refreshId := data.Id % 4
+		convertData, ok := ConvertWorldBossList[data.Id]
+		if !ok {
+			convertData = &ConvertWorldBossData{
+				RefreshId:    refreshId,
+				Id:           data.Id,
+				DurationTime: 3600,
+				SummonId:     data.SummonId,
+			}
+		}
+		convertData.StartDay = data.StartDay
+		//convertData.Roll = data.Roll
+		convertData.DurationTime = data.LifeTime
+
+		loc := util.GetLoc()
+		for idx := range data.SummonTime {
+			sTime, err := time.ParseInLocation(util.DATE_FORMAT3, data.SummonTime[idx], loc)
+			if err == nil {
+				convertData.SummonTime = append(convertData.SummonTime, sTime)
+				//util.DebugF("bossid=%v summontime=%v", convertData.Id, sTime.String())
+			}
+		}
+
+		for idx := 0; idx < len(data.Roll); idx++ {
+			rollVal, _ := Str2Num(data.Roll[idx]) //正常概率
+			if rollVal <= 0 {
+				continue
+			}
+			rollVal2, _ := Str2Num(data.Roll2[idx]) //衰减概率
+			if rollVal2 <= 0 {
+				continue
+			}
+			convertData.RollTotalWeight += int32(rollVal)
+			convertData.DeductionWeight += int32(rollVal2)
+
+			RollData := &KillRewardInfo{
+				RewardWeight:    convertData.RollTotalWeight,
+				DeductionWeight: convertData.DeductionWeight,
+			}
+			if idx == 0 {
+				for idx := 0; idx < len(data.FirstRewardServer); idx++ {
+					key, val := Str2Res(data.FirstRewardServer[idx])
+					if key <= 0 || val <= 0 {
+						continue
+					}
+					RollData.RewardList = append(RollData.RewardList, &serverproto.KeyValueType{
+						Key:   key,
+						Value: val,
+					})
+				}
+			} else if idx == 1 {
+				for idx := 0; idx < len(data.SecondRewardServer); idx++ {
+					key, val := Str2Res(data.SecondRewardServer[idx])
+					if key <= 0 || val <= 0 {
+						continue
+					}
+					RollData.RewardList = append(RollData.RewardList, &serverproto.KeyValueType{
+						Key:   key,
+						Value: val,
+					})
+				}
+			} else if idx == 2 {
+				for idx := 0; idx < len(data.ThreeRewardServer); idx++ {
+					key, val := Str2Res(data.ThreeRewardServer[idx])
+					if key <= 0 || val <= 0 {
+						continue
+					}
+					RollData.RewardList = append(RollData.RewardList, &serverproto.KeyValueType{
+						Key:   key,
+						Value: val,
+					})
+				}
+			}
+			key, value := Str2Res(data.AutoHp[0])
+			convertData.ReduceHp = &serverproto.KeyValueType{
+				Key:   key,
+				Value: value,
+			}
+			convertData.RollList = append(convertData.RollList, RollData)
+		}
+
+		ConvertWorldBossList[data.Id] = convertData
+		//log.Print("time:", convertData.SummonTime[0].String(), convertData.SummonTime[1].String(), convertData.SummonTime[2].String())
+
+		ConvertWorldBoss[refreshId] = append(ConvertWorldBoss[refreshId], convertData)
+		sort.Slice(ConvertWorldBoss[refreshId], func(i, j int) bool {
+			return ConvertWorldBoss[refreshId][i].StartDay < ConvertWorldBoss[refreshId][j].StartDay
+		})
+	}
+
+	//WorldBossChangePlayCfg
+	for _, data := range serverproto.WorldBossChangePlayCfgLoader {
+		convertData := &ConvertWorldBossData{
+			//RefreshId:    refreshId,
+			Id:           data.Id,
+			DurationTime: data.LifeTime,
+			SummonId:     data.SummonId,
+			ConsumeList:  map[int32]int32{},
+		}
+		convertData.SummonType = SummonBossType_ChangePlay
+
+		loc := util.GetLoc()
+		for idx := range data.SummonTime {
+			sTime, err := time.ParseInLocation(util.DATE_FORMAT3, data.SummonTime[idx], loc)
+			if err == nil {
+				convertData.SummonTime = append(convertData.SummonTime, sTime)
+				//util.DebugF("bossid=%v summontime=%v", convertData.Id, sTime.String())
+			}
+		}
+
+		//beginTime endTime
+		tmpStartTimeList := strings.Split(data.StartTime, ";")
+		if tmpStartTimeList[0] == "1" && len(tmpStartTimeList) >= 2 {
+			convertData.BossBeginTime = util.GetTimeByStr(tmpStartTimeList[1])
+			convertData.BossBeginTimeStamp = uint64(convertData.BossBeginTime.UnixNano() / 1e6)
+		}
+		tmpEndTimeList := strings.Split(data.EndTime, ";")
+		if tmpEndTimeList[0] == "1" && len(tmpEndTimeList) >= 2 {
+			convertData.BossEndTime = util.GetTimeByStr(tmpEndTimeList[1])
+			convertData.BossEndTimeStmp = uint64(convertData.BossEndTime.UnixNano() / 1e6)
+
+		}
+
+		//consume list
+		Str2ResMapList(data.Consume, convertData.ConsumeList)
+
+		//ChangePlayList
+		var totalWeight int32 = 0
+		for idx := 0; idx < len(data.ChangePlayId); idx++ {
+			k, v := Str2Res(data.ChangePlayId[idx])
+			if k <= 0 || v <= 0 {
+				continue
+			}
+			totalWeight += k
+			convertData.ChangePlayIdList = append(convertData.ChangePlayIdList,
+				&serverproto.KeyValueType{
+					Key:   v,
+					Value: totalWeight,
+				})
+		}
+		convertData.TotalChangePlayWeight = totalWeight
+
+		for idx := 0; idx < len(data.Roll); idx++ {
+			rollVal, _ := Str2Num(data.Roll[idx]) //正常概率
+			if rollVal <= 0 {
+				continue
+			}
+			rollVal2, _ := Str2Num(data.Roll2[idx]) //衰减概率
+			if rollVal2 <= 0 {
+				continue
+			}
+			convertData.RollTotalWeight += int32(rollVal)
+			convertData.DeductionWeight += int32(rollVal2)
+
+			RollData := &KillRewardInfo{
+				RewardWeight:    convertData.RollTotalWeight,
+				DeductionWeight: convertData.DeductionWeight,
+			}
+			if idx == 0 {
+				for idx := 0; idx < len(data.FirstRewardServer); idx++ {
+					key, val := Str2Res(data.FirstRewardServer[idx])
+					if key <= 0 || val <= 0 {
+						continue
+					}
+					RollData.RewardList = append(RollData.RewardList, &serverproto.KeyValueType{
+						Key:   key,
+						Value: val,
+					})
+				}
+			} else if idx == 1 {
+				for idx := 0; idx < len(data.SecondRewardServer); idx++ {
+					key, val := Str2Res(data.SecondRewardServer[idx])
+					if key <= 0 || val <= 0 {
+						continue
+					}
+					RollData.RewardList = append(RollData.RewardList, &serverproto.KeyValueType{
+						Key:   key,
+						Value: val,
+					})
+				}
+			} else if idx == 2 {
+				for idx := 0; idx < len(data.ThreeRewardServer); idx++ {
+					key, val := Str2Res(data.ThreeRewardServer[idx])
+					if key <= 0 || val <= 0 {
+						continue
+					}
+					RollData.RewardList = append(RollData.RewardList, &serverproto.KeyValueType{
+						Key:   key,
+						Value: val,
+					})
+				}
+			}
+			key, value := Str2Res(data.AutoHp[0])
+			convertData.ReduceHp = &serverproto.KeyValueType{
+				Key:   key,
+				Value: value,
+			}
+			convertData.RollList = append(convertData.RollList, RollData)
+		}
+
+		ConvertWorldBossChangePlayList[data.Id] = convertData
+	}
+}
+
+type SkillAttr struct {
+	AttrList map[int32][]*serverproto.KeyValueType
+}
+
+var ConvertSkillAttr = map[int32]*SkillAttr{}
+
+func convertSkillUpEffect() {
+	for _, data := range serverproto.SkillUpEffectCfgLoader {
+		if data == nil {
+			//有错误,直接返回
+			return
+		}
+		passData := ConvertSkillAttr[data.SkillId]
+		if passData == nil {
+			key, value := Str2Res(data.AddAttributes[0])
+			attrData := &SkillAttr{
+				AttrList: map[int32][]*serverproto.KeyValueType{},
+			}
+			skillLevel := data.Id % 1000
+			attrData.AttrList[skillLevel] = append(attrData.AttrList[skillLevel], &serverproto.KeyValueType{
+				Key:   key,
+				Value: value,
+			})
+
+			ConvertSkillAttr[data.SkillId] = attrData
+		} else {
+			key, value := Str2Res(data.AddAttributes[0])
+			skillLevel := data.Id % 1000
+
+			passData.AttrList[skillLevel] = append(passData.AttrList[skillLevel], &serverproto.KeyValueType{
+				Key:   key,
+				Value: value,
+			})
+		}
+	}
+}
+
+type keyValList struct {
+	KeyType  int32
+	ValList  []float32
+	RankList []int32
+}
+type compConditionAndRewardData struct {
+	Id            int32             //档位
+	CfgId         int32             //配置表ID
+	ConditionList []*keyValList     //条件
+	RewardList    []map[int32]int32 //对应结算周期奖励
+}
+type CompetitionTypeData struct {
+	CompetitionId   int32
+	CompetitionType int32
+	ConditionList   map[int32]*compConditionAndRewardData //对应档位数据
+	LastConditionId int32
+
+	//赛季特殊道具ID
+	CompetitionItemList set.Interface
+}
+
+var ConvertCompTypeList = map[int32]*CompetitionTypeData{} //赛季类型数据
+func (this *CompetitionTypeData) GetCompetitionType() int32 {
+	return this.CompetitionType
+}
+
+func (this *CompetitionTypeData) GetRankSection(selfRank, totalRank int64) (int32, bool, int32) {
+	if selfRank <= 0 || totalRank <= 0 {
+		return this.LastConditionId, false, this.LastConditionId
+	} else {
+		if totalRank < GlobalCompetitionSectionTotal {
+			totalRank = GlobalCompetitionSectionTotal
+		}
+		rankPercent := 1 - float32(selfRank)*GlobalCompetitionSectionFactor/float32(totalRank)
+		rankPercent = rankPercent * 100
+		//first rank 直接返回第一档
+		if totalRank > 0 && selfRank == 1 {
+			rankPercent = 100
+		}
+		//rankPercent := (1 - float32(selfRank-1)/float32(totalRank)) * 100
+		for _, data := range this.ConditionList {
+			for _, conditionData := range data.ConditionList {
+				if conditionData.KeyType == 5 {
+					if conditionData.RankList[0] <= int32(selfRank) &&
+						int32(selfRank) <= conditionData.RankList[1] {
+						return data.Id, (data.Id == 1), data.CfgId
+					}
+				} else {
+					if len(conditionData.ValList) >= 2 &&
+						rankPercent > float32(conditionData.ValList[0]) &&
+						rankPercent <= float32(conditionData.ValList[1]) {
+						return data.Id, (data.Id == 1), data.CfgId
+						//	return data.Id, data.Id%int32(len(this.ConditionList)) == 1
+					}
+				}
+			}
+		}
+		util.ErrorF("GetRankSection not find correct sectionId rankPercent=%v [please find cehua!!!]", rankPercent)
+	}
+
+	return this.LastConditionId, false, this.LastConditionId
+}
+
+type CompetitionBeginEndTimeData struct {
+	CalBeginTime, CalEndTime time.Time //根据开服时间计算后的开启和结束时间
+}
+type CompetitionTimeData struct {
+	CompetitionId            int32
+	CompetitionType          int32 //赛季类型
+	Duration                 int32 //持续天数,天为单位
+	PeriodEndStrList         []int
+	BeginTimeStr, EndTimeStr string //开始/结束时间
+	ResetTime                int32  //休赛季时间,天为单位
+
+	RewardTimeStr []string
+	RewardTime    []time.Time //周期结算时间
+
+	CalBeginTime, CalEndTime time.Time   //根据开服时间计算后的开启和结束时间
+	PeriodEndTimeList        []time.Time //中间结算时间点
+}
+
+func (this *CompetitionTimeData) GetCalEndTime() time.Time {
+	return this.CalEndTime
+}
+func (this *CompetitionTimeData) GetCompetitionType() int32 {
+	return this.CompetitionType
+}
+
+var ConvertCompTimeList = map[int32]*CompetitionTimeData{} //赛季时间数据
+var ConvertCompTimeIdList []*CompetitionTimeData           //赛季时间顺序数据
+func convertCompetitionCfg() {
+	//clean for reload
+	ConvertCompTimeIdList = []*CompetitionTimeData{}
+	ConvertCompTimeList = map[int32]*CompetitionTimeData{}
+
+	//CompetitionCfg
+	ConvertCompTypeList = map[int32]*CompetitionTypeData{}
+	for _, data := range serverproto.CompetitionCfgLoader {
+		info, ok := ConvertCompTypeList[data.CompetitionId]
+		if !ok {
+			info = &CompetitionTypeData{
+				CompetitionId:       data.CompetitionId,
+				CompetitionType:     data.CompetitionType,
+				ConditionList:       map[int32]*compConditionAndRewardData{},
+				CompetitionItemList: set.New(set.NonThreadSafe),
+			}
+		}
+		//条件
+		conditionData := &compConditionAndRewardData{
+			//	Id: data.Id,
+			Id:    data.Level,
+			CfgId: data.Id,
+		}
+		for idx := range data.CompetitionCondition {
+			dataList := strings.Split(data.CompetitionCondition[idx], ":")
+			keyType, _ := Str2Num(dataList[0])
+
+			keyData := &keyValList{KeyType: int32(keyType)}
+			for i := 1; i < len(dataList); i++ {
+				if keyType == 5 {
+					val, _ := Str2Num(dataList[i])
+					keyData.RankList = append(keyData.RankList, int32(val))
+				} else {
+					val, _ := Str2Float32(dataList[i])
+					//val, _ := Str2Num(dataList[i])
+					keyData.ValList = append(keyData.ValList, float32(val))
+				}
+			}
+			conditionData.ConditionList = append(conditionData.ConditionList, keyData)
+		}
+
+		//结算奖励
+		if data.CompetitionType == 1 || data.CompetitionType == 2 || data.CompetitionType == 3 || data.CompetitionType == 4 ||
+			data.CompetitionType == 5 {
+			//第一次结算
+			var reward1List = map[int32]int32{}
+			for k := 0; k < len(data.CompetitionReward1); k++ {
+				key, val := Str2Res(data.CompetitionReward1[k])
+				if key > 0 && val > 0 {
+					reward1List[key] += val
+				}
+			}
+			conditionData.RewardList = append(conditionData.RewardList, reward1List)
+			//第二次结算
+			var reward2List = map[int32]int32{}
+			for k := 0; k < len(data.CompetitionReward2); k++ {
+				key, val := Str2Res(data.CompetitionReward2[k])
+				if key > 0 && val > 0 {
+					reward2List[key] += val
+				}
+			}
+			conditionData.RewardList = append(conditionData.RewardList, reward2List)
+			//第三次次结算
+			var reward3List = map[int32]int32{}
+			for k := 0; k < len(data.CompetitionReward3); k++ {
+				key, val := Str2Res(data.CompetitionReward3[k])
+				if key > 0 && val > 0 {
+					reward3List[key] += val
+				}
+			}
+			conditionData.RewardList = append(conditionData.RewardList, reward3List)
+		}
+
+		info.ConditionList[data.Id] = conditionData
+		if info.LastConditionId < data.Id {
+			info.LastConditionId = data.Id
+		}
+
+		//活动道具
+		for idx := 0; idx < len(data.HuodongItem); idx++ {
+			val, _ := Str2Num(data.HuodongItem[idx])
+			if val > 0 {
+				info.CompetitionItemList.Add(int32(val))
+			}
+		}
+
+		ConvertCompTypeList[info.CompetitionId] = info
+	}
+
+	//赛季时间处理
+	for _, data := range serverproto.CompetitionCfgLoader {
+		if data.BeginTime == "" || data.EndTime == "" {
+			continue
+		}
+		timeInfo, ok := ConvertCompTimeList[data.CompetitionId]
+		if ok {
+			continue
+		}
+
+		timeInfo = &CompetitionTimeData{
+			CompetitionId:   data.CompetitionId,
+			CompetitionType: data.CompetitionType,
+			ResetTime:       data.RestTime,
+			BeginTimeStr:    data.BeginTime,
+			EndTimeStr:      data.EndTime,
+		}
+
+		for k := 0; k < len(data.CompetitionPeriod); k++ {
+			val, _ := Str2Num(data.CompetitionPeriod[k])
+			if val <= 0 {
+				util.PanicF("CompetitionCfgLoader CompetitionPeriod Invalid!!!")
+			}
+			timeInfo.PeriodEndStrList = append(timeInfo.PeriodEndStrList, val)
+		}
+		sort.Ints(timeInfo.PeriodEndStrList)
+		if len(timeInfo.PeriodEndStrList) <= 0 {
+			util.PanicF("CompetitionCfgLoader CompetitionPeriod Invalid!!!")
+		}
+		timeInfo.Duration = int32(timeInfo.PeriodEndStrList[len(timeInfo.PeriodEndStrList)-1])
+
+		ConvertCompTimeList[timeInfo.CompetitionId] = timeInfo
+		ConvertCompTimeIdList = append(ConvertCompTimeIdList, timeInfo)
+	}
+	sort.Slice(ConvertCompTimeIdList, func(i, j int) bool {
+		return ConvertCompTimeIdList[i].CompetitionId < ConvertCompTimeIdList[j].CompetitionId
+	})
+}
+
+const (
+	WheelRewardType_Level  = 1
+	WheelRewardType_Normal = 2
+	WheelRewardType_Mini   = 3
+	WheelRewardType_MVp    = 4
+)
+
+type CompetitionPrizeWheelInfo struct {
+	ID int32
+	//奖励数据
+	LowRewardKv    serverproto.KeyValueType
+	NormalRewardKv serverproto.KeyValueType //normal [掉落ID,数量]
+	MiniRewardKV   serverproto.KeyValueType
+	MVPRewardKV    serverproto.KeyValueType
+
+	Weight int32
+
+	RewardFactorList map[int]int32 //抽奖概率 1low 2normal 3mini 4mvp
+	MvpFactorList    []int32       //4mvp
+}
+type WheelItemInfo struct {
+	Key   int32 //道具id
+	Val   int32 //道具数量
+	Money int32 //金币消耗
+	Score int32 //积分
+}
+type ConvertPrizeWheelInfo struct {
+	RewardTemplateList []*CompetitionPrizeWheelInfo
+	TotalWeight        int32
+	WheelCostItem      []*WheelItemInfo //道具/金币消耗 抽一次
+	WheelAllCostItem   WheelItemInfo    //抽全部道具/金币消耗
+
+	RefreshCostMoney []int32 // 刷新价格(金币)
+	NoMVPRewardNum   int32   //前面无大奖次数
+	ItemToMoney      int32   //单个道具对应金币数量
+}
+
+func (this *ConvertPrizeWheelInfo) genWheelRewardByType(itemIdx *int32, rewardType int32,
+	kv serverproto.KeyValueType, rewardList *[]*serverproto.WheelRewardItemInfo) {
+	for idx := 0; idx < int(kv.Value); idx++ {
+		*itemIdx++
+		rewardItem := &serverproto.WheelRewardItemInfo{
+			ItemIdx:    *itemIdx,
+			RewardType: rewardType, //1
+		}
+		tmpDropReward := map[int32]int32{}
+		DropCfgProcess(tmpDropReward, kv.Key)
+		for k, v := range tmpDropReward {
+			if k > 0 && v > 0 {
+				rewardItem.ItemId = k
+				rewardItem.ItemNum = v
+			}
+			break
+		}
+		*rewardList = append(*rewardList, rewardItem)
+	}
+}
+
+func (this *ConvertPrizeWheelInfo) GenWheelReward(rewardList *[]*serverproto.WheelRewardItemInfo) int32 {
+	if this.TotalWeight <= 0 {
+		return 0
+	}
+
+	var tmpRewardList []*serverproto.WheelRewardItemInfo
+	randWeight := rand.Int31n(this.TotalWeight) + 1 //[0,randWeight]
+	templateIdx := 0
+	for idx := 0; idx < len(this.RewardTemplateList); idx++ {
+		templateIdx = idx
+		if randWeight <= this.RewardTemplateList[idx].Weight {
+			break
+		}
+	}
+
+	templateInfo := this.RewardTemplateList[templateIdx]
+	var itemIdx int32 = 0
+	//level
+	this.genWheelRewardByType(&itemIdx, WheelRewardType_Level, templateInfo.LowRewardKv, &tmpRewardList)
+	//normal
+	this.genWheelRewardByType(&itemIdx, WheelRewardType_Normal, templateInfo.NormalRewardKv, &tmpRewardList)
+	//mini
+	this.genWheelRewardByType(&itemIdx, WheelRewardType_Mini, templateInfo.MiniRewardKV, &tmpRewardList)
+	//mvp
+	this.genWheelRewardByType(&itemIdx, WheelRewardType_MVp, templateInfo.MVPRewardKV, &tmpRewardList)
+
+	randArray := GenRandomArrayByLen(len(tmpRewardList))
+	for idx := 0; idx < len(randArray); idx++ {
+		*rewardList = append(*rewardList, tmpRewardList[randArray[idx]-1])
+	}
+	util.DebugF("templateIdx=%v GenWheelReward=%v", templateInfo.ID, *rewardList)
+
+	return templateInfo.ID
+}
+
+func (this *ConvertPrizeWheelInfo) GetTemplateData(templateIdx int32) *CompetitionPrizeWheelInfo {
+	for idx := 0; idx < len(this.RewardTemplateList); idx++ {
+		if this.RewardTemplateList[idx].ID == templateIdx {
+			return this.RewardTemplateList[idx]
+		}
+	}
+	return nil
+}
+
+var ConvertPrizeWheelData *ConvertPrizeWheelInfo
+var ConvertActivityPrizeWheelData = map[int32]*ConvertPrizeWheelInfo{}
+
+func convertCompetitionPrizeWheelCfg() {
+	ConvertPrizeWheelData = &ConvertPrizeWheelInfo{}
+	//赛季转盘
+	for _, cfgData := range serverproto.CompetitionPrizeWheelCfgLoader {
+		convertCompetitionPrizeWheelCfgLoad(cfgData, ConvertPrizeWheelData)
+	}
+
+	//活动转盘
+	for _, cfgData := range serverproto.ActivityRoulettelCfgLoader {
+		if _, ok := ConvertActivityPrizeWheelData[cfgData.ActivitiesId]; !ok {
+			ConvertActivityPrizeWheelData[cfgData.ActivitiesId] = &ConvertPrizeWheelInfo{}
+		}
+		convertActivityPrizeWheelCfgLoad(cfgData, ConvertActivityPrizeWheelData[cfgData.ActivitiesId])
+	}
+}
+func convertCompetitionPrizeWheelCfgLoad(cfgData *serverproto.CompetitionPrizeWheelCfg, tmpData *ConvertPrizeWheelInfo) {
+	//赛季转盘
+	tmpData.TotalWeight += cfgData.ModProbability
+	if cfgData.NoRewardNum > 0 {
+		tmpData.NoMVPRewardNum = cfgData.NoRewardNum
+	}
+	if cfgData.ItemPrice > 0 {
+		tmpData.ItemToMoney = cfgData.ItemPrice
+	}
+	if len(cfgData.RefreshPrice) > 0 && cfgData.RefreshPrice[0] != "" {
+		for idx := 0; idx < len(cfgData.RefreshPrice); idx++ {
+			tmpVal, _ := Str2Num(cfgData.RefreshPrice[idx])
+			tmpData.RefreshCostMoney = append(tmpData.RefreshCostMoney, int32(tmpVal))
+		}
+	}
+
+	templateData := &CompetitionPrizeWheelInfo{
+		ID:               cfgData.Id,
+		Weight:           tmpData.TotalWeight,
+		RewardFactorList: map[int]int32{},
+	}
+	//low
+	k, v := Str2Res(cfgData.LowNormalNum[0])
+	templateData.LowRewardKv.Key = v
+	templateData.LowRewardKv.Value = k
+	//normal
+	k, v = Str2Res(cfgData.NormalNum[0])
+	templateData.NormalRewardKv.Key = v
+	templateData.NormalRewardKv.Value = k
+	//mini
+	k, v = Str2Res(cfgData.MiniNum[0])
+	templateData.MiniRewardKV.Key = v
+	templateData.MiniRewardKV.Value = k
+	//mvp
+	k, v = Str2Res(cfgData.MvpNum[0])
+	templateData.MVPRewardKV.Key = v
+	templateData.MVPRewardKV.Value = k
+	for idx := 0; idx < len(cfgData.Probability); idx++ {
+		factor, _ := Str2Num(cfgData.Probability[idx])
+		templateData.RewardFactorList[idx+1] = int32(factor)
+	}
+	for idx := 0; idx < len(cfgData.MvpProbability); idx++ {
+		factor, _ := Str2Num(cfgData.MvpProbability[idx])
+		templateData.MvpFactorList = append(templateData.MvpFactorList, int32(factor))
+	}
+
+	if len(cfgData.RewardOneItem) > 0 && cfgData.RewardOneItem[0] != "" {
+		if len(cfgData.RewardOneItem) != len(cfgData.RewardOneGold) {
+			util.PanicF("convertCompetitionPrizeWheelCfg")
+		}
+		for idx := 0; idx < len(cfgData.RewardOneItem); idx++ {
+			k, v := Str2Res(cfgData.RewardOneItem[idx])
+			score, _ := Str2Num(cfgData.RewardOnePoint[idx])
+			tmpMoney, _ := Str2Num(cfgData.RewardOneGold[idx])
+			tmpWheelInfo := &WheelItemInfo{
+				Key:   k,
+				Val:   v,
+				Money: int32(tmpMoney),
+				Score: int32(score),
+			}
+			tmpData.WheelCostItem = append(tmpData.WheelCostItem, tmpWheelInfo)
+		}
+
+		k, v := Str2Res(cfgData.RewardAllItem[0])
+		tmpData.WheelAllCostItem.Key = k
+		tmpData.WheelAllCostItem.Val = v
+		tmpData.WheelAllCostItem.Money = cfgData.RewardAdllGold
+		tmpData.WheelAllCostItem.Score = cfgData.RewardAllPoint
+	}
+
+	tmpData.RewardTemplateList = append(tmpData.RewardTemplateList, templateData)
+}
+func convertActivityPrizeWheelCfgLoad(cfgData *serverproto.ActivityRoulettelCfg, tmpData *ConvertPrizeWheelInfo) {
+	//赛季转盘
+	tmpData.TotalWeight += cfgData.ModProbability
+	if cfgData.NoRewardNum > 0 {
+		tmpData.NoMVPRewardNum = cfgData.NoRewardNum
+	}
+	if cfgData.ItemPrice > 0 {
+		tmpData.ItemToMoney = cfgData.ItemPrice
+	}
+	if len(cfgData.RefreshPrice) > 0 && cfgData.RefreshPrice[0] != "" {
+		for idx := 0; idx < len(cfgData.RefreshPrice); idx++ {
+			tmpVal, _ := Str2Num(cfgData.RefreshPrice[idx])
+			tmpData.RefreshCostMoney = append(tmpData.RefreshCostMoney, int32(tmpVal))
+		}
+	}
+
+	templateData := &CompetitionPrizeWheelInfo{
+		ID:               cfgData.Id,
+		Weight:           tmpData.TotalWeight,
+		RewardFactorList: map[int]int32{},
+	}
+	//low
+	k, v := Str2Res(cfgData.LowNormalNum[0])
+	templateData.LowRewardKv.Key = v
+	templateData.LowRewardKv.Value = k
+	//normal
+	k, v = Str2Res(cfgData.NormalNum[0])
+	templateData.NormalRewardKv.Key = v
+	templateData.NormalRewardKv.Value = k
+	//mini
+	k, v = Str2Res(cfgData.MiniNum[0])
+	templateData.MiniRewardKV.Key = v
+	templateData.MiniRewardKV.Value = k
+	//mvp
+	k, v = Str2Res(cfgData.MvpNum[0])
+	templateData.MVPRewardKV.Key = v
+	templateData.MVPRewardKV.Value = k
+	for idx := 0; idx < len(cfgData.Probability); idx++ {
+		factor, _ := Str2Num(cfgData.Probability[idx])
+		templateData.RewardFactorList[idx+1] = int32(factor)
+	}
+	for idx := 0; idx < len(cfgData.MvpProbability); idx++ {
+		factor, _ := Str2Num(cfgData.MvpProbability[idx])
+		templateData.MvpFactorList = append(templateData.MvpFactorList, int32(factor))
+	}
+
+	if len(cfgData.RewardOneItem) > 0 && cfgData.RewardOneItem[0] != "" {
+		if len(cfgData.RewardOneItem) != len(cfgData.RewardOneGold) {
+			util.PanicF("convertCompetitionPrizeWheelCfg")
+		}
+		for idx := 0; idx < len(cfgData.RewardOneItem); idx++ {
+			k, v := Str2Res(cfgData.RewardOneItem[idx])
+			tmpMoney, _ := Str2Num(cfgData.RewardOneGold[idx])
+			tmpWheelInfo := &WheelItemInfo{
+				Key:   k,
+				Val:   v,
+				Money: int32(tmpMoney),
+			}
+			tmpData.WheelCostItem = append(tmpData.WheelCostItem, tmpWheelInfo)
+		}
+
+		k, v := Str2Res(cfgData.RewardAllItem[0])
+		tmpData.WheelAllCostItem.Key = k
+		tmpData.WheelAllCostItem.Val = v
+		tmpData.WheelAllCostItem.Money = cfgData.RewardAdllGold
+	}
+
+	tmpData.RewardTemplateList = append(tmpData.RewardTemplateList, templateData)
+}
+
+// 卡片重置
+var ConvertCardResetList = map[int32]*serverproto.CardReset{} //赛季类型数据
+func convertCardResetCfg() {
+	for _, data := range serverproto.CardResetLoader {
+		index := data.CardType*1000 + data.CardLv
+		if index == 0 {
+			//打印一下日志。有问题的
+			continue
+		}
+		ConvertCardResetList[index] = data
+	}
+}
+
+type ResetSkill struct {
+	BackResource map[int32]int32
+}
+
+type levelUpInfo struct {
+	HeroLevel   map[int32]int32                     //技能升级对应的等级限制
+	OpenCost    []*serverproto.KeyValueType         //解锁消耗
+	UpGradeCost map[int32]*serverproto.KeyValueType //升级消耗
+	ResetBack   map[int32]int32                     //重置返还
+}
+
+var ConvertSkillTree = map[int32]*levelUpInfo{}
+var ConvertPartnerSkillTree = map[int32]*levelUpInfo{}
+var ConvertResetSkill = map[int32]*serverproto.KeyValueType{}
+var ConvertSkillJobAndStage = map[int32][]*serverproto.KeyValueType{} //[jobType*100+jobStage*10 +jobBranch,skillIdList]
+// var ConvertParterSkillJobAndStage = map[int32][]*serverproto.KeyValueType{} //[jobType*100+jobStage*10 +jobBranch,skillIdList]
+var ConvertBattleAttrSkill = map[int32]map[serverproto.Attr]float32{} //优化属性计算
+
+func convertSkillTree() {
+	//解析伙伴的技能升级数据
+	for _, data := range serverproto.ParterSkillTreeCfgLoader {
+		convertData := &levelUpInfo{
+			HeroLevel:   map[int32]int32{},
+			UpGradeCost: map[int32]*serverproto.KeyValueType{},
+			ResetBack:   map[int32]int32{},
+		}
+
+		dem, ok := serverproto.SkillDemandCfgLoader[data.OpenLevel]
+		if !ok {
+			panic("技能升级表 对应伙伴技能表错误")
+		}
+		for i, lv := range dem.LvupDemand {
+			level, _ := Str2Num(lv)
+			convertData.HeroLevel[int32(i)] = int32(level)
+		}
+
+		for _, openCost := range data.OpenNeedCost {
+			key, val := Str2Res(openCost)
+			if key == 0 && val == 0 {
+				continue
+			}
+			convertData.OpenCost = append(convertData.OpenCost, &serverproto.KeyValueType{
+				Key:   int32(key),
+				Value: int32(val),
+			})
+		}
+
+		var backCount int32 = 0
+		for index, upCost := range dem.LvupCost {
+			key, val := Str2Res(upCost)
+			if key == 0 && val == 0 {
+				continue
+			}
+			convertData.UpGradeCost[int32(index)] = &serverproto.KeyValueType{
+				Key:   int32(key),
+				Value: int32(val),
+			}
+
+			//初始化返还数量
+			backCount += val
+			convertData.ResetBack[int32(index+2)] += backCount
+		}
+		ConvertPartnerSkillTree[data.SkillId] = convertData
+	}
+
+	//解析伙伴的技能升级数据
+	for _, data := range serverproto.SkillTreeCfgLoader {
+		convertData := &levelUpInfo{
+			HeroLevel:   map[int32]int32{},
+			UpGradeCost: map[int32]*serverproto.KeyValueType{},
+			ResetBack:   map[int32]int32{},
+		}
+
+		dem, ok := serverproto.SkillDemandCfgLoader[data.OpenLevel]
+		if !ok {
+			panic("技能升级表 对应主角技能表错误")
+		}
+		for index, rLevel := range dem.LvupDemand {
+			level, _ := Str2Num(rLevel)
+			convertData.HeroLevel[int32(index)] = int32(level)
+		}
+
+		for _, openCost := range data.OpenNeedCost {
+			key, val := Str2Res(openCost)
+			if key == 0 && val == 0 {
+				continue
+			}
+			convertData.OpenCost = append(convertData.OpenCost, &serverproto.KeyValueType{
+				Key:   int32(key),
+				Value: int32(val),
+			})
+		}
+
+		var backCount int32 = 0
+		for index, cost := range dem.LvupCost {
+			key, val := Str2Res(cost)
+			if key == 0 && val == 0 {
+				continue
+			}
+			convertData.UpGradeCost[int32(index)] = &serverproto.KeyValueType{
+				Key:   int32(key),
+				Value: int32(val),
+			}
+
+			//初始化返还数量
+			backCount += val
+			convertData.ResetBack[int32(index+2)] += backCount
+		}
+		ConvertSkillTree[data.SkillId] = convertData
+	}
+
+	globalCfg, ok := serverproto.GlobalCfgLoader[int32(serverproto.GlobalType_Global_Reset_Skill_Level_Cost)]
+	if !ok {
+		util.InfoF("skill reset cost config not found")
+	}
+	strList := strings.Split(globalCfg.SVal, ";")
+	for idx := range strList {
+		key, value := Str2Res(strList[idx])
+		if key == 0 && value == 0 {
+			continue
+		}
+		ConvertResetSkill[int32(idx)] = &serverproto.KeyValueType{
+			Key:   key,
+			Value: value,
+		}
+	}
+}
+
+type ShopRefreshCost struct {
+	ItemList map[int32]int32
+}
+
+type SpecialShop struct {
+	ItemList     []*SpecialShopItem
+	TotalWeight  int32 //权重1
+	TotalWeight1 int32 //权重2
+	TotalWeight2 int32 //权重3
+	TotalWeight3 int32 //权重4
+	TotalWeight4 int32 //权重5
+	RefreshTime  []int32
+	RefreshCost  map[int32]*ShopRefreshCost
+	RefreshCount int32
+}
+
+type SpecialShopItem struct {
+	ShopItem *serverproto.ShopItem
+	Weight   int32
+	Weight1  int32
+	Weight2  int32
+	Weight3  int32
+	Weight4  int32
+}
+
+type RedBagShopTime struct {
+	ShopItem *serverproto.ShopItem
+	ItemList map[int32]int32
+}
+
+var ConvertShopItemData = map[int32]*serverproto.ShopItem{}
+var ConvertRoleShopData = map[int32]*SpecialShop{}
+var ConvertRedBagShopItemData = map[int32]*RedBagShopTime{}
+
+type ItemCondition struct {
+	Conditions []*serverproto.KeyValueType
+}
+
+var ConvertShopItemCondition = map[int32]*ItemCondition{}
+
+func convertShopCfg() {
+	//初始化商店类型
+	for _, shopData := range serverproto.ShopTypeCfgLoader {
+		ConvertRoleShopData[shopData.Id] = &SpecialShop{
+			TotalWeight:  0,
+			TotalWeight1: 0,
+			TotalWeight2: 0,
+			TotalWeight3: 0,
+			TotalWeight4: 0,
+			RefreshCost:  make(map[int32]*ShopRefreshCost),
+		}
+		//刷新时间
+		for _, refTime := range shopData.RefreshTime {
+			hour, _ := Str2Num(refTime)
+			ConvertRoleShopData[shopData.Id].RefreshTime = append(ConvertRoleShopData[shopData.Id].RefreshTime, int32(hour))
+		}
+		//刷新消耗
+		for index, costData := range shopData.PayForRefresh {
+			limitRes := strings.Split(costData, ":")
+			if len(limitRes) >= 2 {
+				itemId, _ := Str2Num(limitRes[0])
+				itemNum, _ := Str2Num(limitRes[1])
+				_, ok := ConvertRoleShopData[shopData.Id].RefreshCost[int32(index)]
+				if !ok {
+					refreshCost := &ShopRefreshCost{
+						ItemList: make(map[int32]int32),
+					}
+					refreshCost.ItemList[int32(itemId)] += int32(itemNum)
+					ConvertRoleShopData[shopData.Id].RefreshCost[int32(index)] = refreshCost
+				} else {
+					ConvertRoleShopData[shopData.Id].RefreshCost[int32(index)].ItemList[int32(itemId)] += int32(itemNum)
+				}
+			}
+		}
+		ConvertRoleShopData[shopData.Id].RefreshCount = shopData.RefreshNum
+	}
+	for _, data := range serverproto.ShopCfgLoader {
+		convertData := &serverproto.ShopItem{}
+		convertData.GoodsId = data.GoodsId
+		convertData.Price = data.PayForNum
+		convertData.CurPrice = data.DiscountPayForNum
+		convertData.Dispercent = data.Proportion
+		convertData.Hot = true
+		convertData.HdItemId = data.HdDrop
+		if data.SellWell == 0 {
+			convertData.Hot = false
+		}
+
+		var limitType int32 = 0
+		limitRes := strings.Split(data.RestrictedType, ":")
+		if len(limitRes) >= 2 {
+			lType, _ := Str2Num(limitRes[0])
+			convertData.LimitType = int32(lType)
+			limitType = convertData.LimitType
+			if len(limitRes) == 2 {
+				lCount, _ := Str2Num(limitRes[1])
+				convertData.Count = int32(lCount)
+			}
+			if len(limitRes) >= 3 {
+				lCircle, _ := Str2Num(limitRes[1])
+				convertData.Circle = int32(lCircle)
+				lCount, _ := Str2Num(limitRes[2])
+				convertData.Count = int32(lCount)
+			}
+		}
+
+		if limitType == 3 {
+			loc := util.GetLoc()
+			if data.BeginTime != "" {
+				sTime, err1 := time.ParseInLocation(util.DATE_FORMAT, data.BeginTime, loc)
+				if err1 != nil {
+					util.PanicF("convertShop startTime err:%v", err1)
+				}
+				convertData.StartTime = int64(sTime.Unix())
+			}
+			if data.EndTime != "" {
+				cTime, err2 := time.ParseInLocation(util.DATE_FORMAT, data.EndTime, loc)
+				if err2 != nil {
+					util.PanicF("convertShop endTime err:%v", err2)
+				}
+				convertData.EndTime = int64(cTime.Unix())
+			}
+		}
+
+		//特殊商店单独处理
+		shopType, ok2 := serverproto.ShopTypeCfgLoader[data.GoodsType]
+		if ok2 && shopType.ShopType == 2 {
+			_, ok4 := ConvertRoleShopData[data.GoodsType]
+			if !ok4 {
+				//道具没有对应的商店。这策划不靠谱!!!!
+				util.PanicF("convertShop shopType not found err:%v", data.GoodsType)
+			}
+			//计算最新的权重
+			ConvertRoleShopData[data.GoodsType].TotalWeight += data.Weight
+			ConvertRoleShopData[data.GoodsType].TotalWeight1 += data.Weight1
+			ConvertRoleShopData[data.GoodsType].TotalWeight2 += data.Weight2
+			ConvertRoleShopData[data.GoodsType].TotalWeight3 += data.Weight3
+			ConvertRoleShopData[data.GoodsType].TotalWeight4 += data.Weight4
+
+			shopItem := &SpecialShopItem{}
+			shopItem.Weight = ConvertRoleShopData[data.GoodsType].TotalWeight
+			shopItem.Weight1 = ConvertRoleShopData[data.GoodsType].TotalWeight1
+			shopItem.Weight2 = ConvertRoleShopData[data.GoodsType].TotalWeight2
+			shopItem.Weight3 = ConvertRoleShopData[data.GoodsType].TotalWeight3
+			shopItem.Weight4 = ConvertRoleShopData[data.GoodsType].TotalWeight4
+
+			shopItem.ShopItem = convertData
+			ConvertRoleShopData[data.GoodsType].ItemList = append(ConvertRoleShopData[data.GoodsType].ItemList, shopItem)
+
+			continue
+		}
+		//
+		if data.GoodsType == 50 {
+			shopItem := &RedBagShopTime{}
+			shopItem.ShopItem = convertData
+			shopItem.ItemList = make(map[int32]int32)
+			for _, items := range data.Reward {
+				limitRes := strings.Split(items, ":")
+				if len(limitRes) >= 2 {
+					itemId, _ := Str2Num(limitRes[0])
+					itemCount, _ := Str2Num(limitRes[1])
+
+					shopItem.ItemList[int32(itemId)] = int32(itemCount)
+				}
+			}
+			ConvertRedBagShopItemData[data.GoodsId] = shopItem
+			continue
+		}
+
+		ConvertShopItemData[data.GoodsId] = convertData
+
+		if len(data.Condition) > 0 {
+			condition := &ItemCondition{}
+			for _, cond := range data.Condition {
+				condId, condArg := Str2Res(cond)
+				if condId != 0 && condArg != 0 {
+					condition.Conditions = append(condition.Conditions, &serverproto.KeyValueType{
+						Key:   int32(condId),
+						Value: int32(condArg),
+					})
+				}
+			}
+			ConvertShopItemCondition[data.GoodsId] = condition
+		}
+	}
+}
+
+// 比较refTime 和当前时间是否在同一时间段内
+func CheckShopNeedRefresh(refTime int64) bool {
+	if refTime < util.GetTimeSeconds() {
+		return true
+	}
+	return false
+}
+
+func GetNextShopRefreshHour(shopType int32, curHour int32) int32 {
+	shopData, ok := ConvertRoleShopData[shopType]
+	if !ok {
+		return -1
+	}
+	for _, data := range shopData.RefreshTime {
+		if curHour < data {
+			return data
+		}
+	}
+	return shopData.RefreshTime[0]
+}
+
+func GetShopItemByShopType(shopType int32, vipWeight int32) []int32 {
+	shop, ok1 := serverproto.ShopTypeCfgLoader[shopType]
+	if !ok1 {
+		return nil
+	}
+	if shop.ShopType != 2 || shop.GoodsRefreshNum <= 0 {
+		return nil
+	}
+	shopData, ok2 := ConvertRoleShopData[shopType]
+	if !ok2 {
+		return nil
+	}
+	if int32(len(shopData.ItemList)) < shop.GoodsRefreshNum {
+		return nil
+	}
+
+	var itemList []int32
+	selected := map[int32]int32{}
+	totalWeight := shopData.TotalWeight
+	if vipWeight == 1 {
+		totalWeight = shopData.TotalWeight1
+	} else if vipWeight == 2 {
+		totalWeight = shopData.TotalWeight2
+	} else if vipWeight == 3 {
+		totalWeight = shopData.TotalWeight3
+	} else if vipWeight == 4 {
+		totalWeight = shopData.TotalWeight4
+	}
+	if totalWeight == 0 {
+		return nil
+	}
+	for i := 0; i < int(shop.GoodsRefreshNum); {
+		randWeight := rand.Int31n(totalWeight) //[0,randWeight)
+		for _, data := range shopData.ItemList {
+			weight := data.Weight
+			if vipWeight == 1 {
+				weight = data.Weight1
+			} else if vipWeight == 2 {
+				weight = data.Weight2
+			} else if vipWeight == 3 {
+				weight = data.Weight3
+			} else if vipWeight == 4 {
+				weight = data.Weight4
+			}
+			if weight == 0 { //策划口头补充的需求
+				continue
+			}
+			if randWeight <= weight {
+				_, ok3 := selected[data.ShopItem.GoodsId]
+				if ok3 { //找到重复的
+					break
+				}
+
+				itemList = append(itemList, data.ShopItem.GoodsId)
+				selected[data.ShopItem.GoodsId] = 1
+				i++
+				break
+			}
+		}
+	}
+	return itemList
+}
+
+type SignInData struct {
+	VipLevel int32
+	DaySign  []*serverproto.KeyValueType //每日签到奖励
+	AccuSign []*serverproto.KeyValueType //累积签到奖励
+}
+
+var ConvertSignUpData = map[int32]*SignInData{}
+
+func convertSignInCfg() {
+	for _, data := range serverproto.SignInCfgLoader {
+		convertData := SignInData{}
+		if len(data.SignInReward) > 0 {
+			for _, reward := range data.SignInReward {
+				key, val := Str2Res(reward)
+				if key == 0 || val == 0 {
+					continue
+				}
+				convertData.DaySign = append(convertData.DaySign, &serverproto.KeyValueType{
+					Key:   int32(key),
+					Value: int32(val),
+				})
+			}
+		}
+		if len(data.SignInAddReward) > 0 {
+			for _, reward := range data.SignInAddReward {
+				key, val := Str2Res(reward)
+				if key == 0 || val == 0 {
+					continue
+				}
+				convertData.AccuSign = append(convertData.AccuSign, &serverproto.KeyValueType{
+					Key:   int32(key),
+					Value: int32(val),
+				})
+			}
+		}
+		convertData.VipLevel = data.VipLevel
+		ConvertSignUpData[data.ID] = &convertData
+	}
+	if len(ConvertSignUpData)%30 != 0 {
+		util.PanicF("convertSign total count err:%v", len(ConvertSignUpData))
+	}
+}
+
+var ActiveCodeList = map[string]struct{}{}
+
+func convertActiveCodeCfg() {
+	for _, val := range serverproto.ActiveCodeCfgLoader {
+		ActiveCodeList[val.Code] = struct{}{}
+	}
+}
+func CheckActiveCode(activeCode string) serverproto.ErrorCode {
+	if activeCode == "" {
+		return serverproto.ErrorCode_ERROR_ROLE_ACTIVECODE_ERROR
+	}
+
+	if len(ActiveCodeList) <= 0 {
+		return serverproto.ErrorCode_ERROR_OK
+	}
+
+	if _, ok := ActiveCodeList[activeCode]; !ok {
+		return serverproto.ErrorCode_ERROR_ROLE_ACTIVECODE_ERROR
+	}
+
+	return serverproto.ErrorCode_ERROR_OK
+}
+
+type LevelItem struct {
+	MapId   int32
+	LevelId int32
+
+	//boss战小怪
+	MonsterList []*serverproto.KeyValueType
+	BossId      int32
+	BossPos     int32
+	RageId      uint32
+}
+
+var ConvertMapItemList = map[int32]*LevelItem{}
+
+func convertMapCfg() {
+	//for _, mapItemData := range serverproto.MapCfgLoader {
+	//	var levelId int32 = 1
+	//	mapId := mapItemData.Id
+	//	for {
+	//		tmpId := mapId*10000 + levelId
+	//		data, ok := serverproto.LevelCfgLoader[tmpId]
+	//		if !ok {
+	//			break
+	//		}
+	//		addLevelItem := &LevelItem{
+	//			MapId:   mapId,
+	//			LevelId: levelId,
+	//		}
+	//
+	//		//boss战小怪处理
+	//		for idx := 0; idx <= len(data.Monsters); idx++ {
+	//			loc, monsterId := Str2Res(data.Monsters[idx])
+	//			if loc >= 1 && loc <= 6 && monsterId > 0 {
+	//				addLevelItem.MonsterList = append(addLevelItem.MonsterList,
+	//					&serverproto.KeyValueType{
+	//						Key:   loc,
+	//						Value: monsterId,
+	//					})
+	//			}
+	//		}
+	//
+	//		if data.BossId > 0 {
+	//			addLevelItem.BossId = data.BossId
+	//			addLevelItem.BossPos = data.BossPosition
+	//			addLevelItem.RageId = uint32(data.BossRageBuffId)
+	//		}
+	//
+	//		ConvertMapItemList[tmpId] = addLevelItem
+	//	}
+	//}
+}
+
+// NatureCfg.csv
+var ConvertNatureMap = map[int32]map[int32][]*serverproto.KeyValueType{}
+
+func convertNatureCfg() {
+	//for _, data := range serverproto.NatureCfgLoader {
+	//	if data.AntiNature1 != "" {
+	//		convertNatureAttr(1, data.AntiNature1)
+	//	}
+	//	if data.AntiNature2 != "" {
+	//		convertNatureAttr(2, data.AntiNature2)
+	//	}
+	//	if data.AntiNature3 != "" {
+	//		convertNatureAttr(3, data.AntiNature3)
+	//	}
+	//	if data.AntiNature4 != "" {
+	//		convertNatureAttr(4, data.AntiNature4)
+	//	}
+	//	if data.AntiNature5 != "" {
+	//		convertNatureAttr(5, data.AntiNature5)
+	//	}
+	//	if data.AntiNature6 != "" {
+	//		convertNatureAttr(6, data.AntiNature6)
+	//	}
+	//	if data.AntiNature7 != "" {
+	//		convertNatureAttr(7, data.AntiNature7)
+	//	}
+	//}
+}
+func convertNatureAttr(natureId int32, attr string) {
+	attrList := strings.Split(attr, ";")
+	for idx := range attrList {
+		key, value := Str2Res(attrList[idx])
+		if key > 0 && value > 0 {
+			if ConvertNatureMap[natureId] == nil {
+				ConvertNatureMap[natureId] = map[int32][]*serverproto.KeyValueType{}
+			}
+			ConvertNatureMap[natureId][key] = append(ConvertNatureMap[natureId][key], &serverproto.KeyValueType{
+				Key:   key,
+				Value: value,
+			})
+		}
+	}
+}
+
+type TowerReward struct {
+	ItemList   []*serverproto.KeyValueType
+	ExItemList []*serverproto.KeyValueType
+	FightCheck int32
+	SPAdd      *serverproto.KeyValueType
+}
+
+var ConvertTowerData = map[int32]*TowerReward{}
+var ConvertClimbPowerDecayFactorList = map[int32]*ConvertDecayData{}
+var ConvertClimbTimeDecayFactorList = map[int32]*ConvertDecayData{}
+
+func convertTowerCfg() {
+	for _, tower := range serverproto.ClimbingTowerCfgLoader {
+		convertReward := &TowerReward{}
+		for _, items := range tower.RewardItems {
+			key, value := Str2Res(items)
+			if key == 0 || value == 0 {
+				continue
+			}
+			convertReward.ItemList = append(convertReward.ItemList, &serverproto.KeyValueType{
+				Key:   key,
+				Value: value,
+			})
+		}
+		for _, special := range tower.SpecialReward {
+			key, value := Str2Res(special)
+			if key == 0 || value == 0 {
+				continue
+			}
+			convertReward.ExItemList = append(convertReward.ExItemList, &serverproto.KeyValueType{
+				Key:   key,
+				Value: value,
+			})
+		}
+		convertReward.FightCheck = tower.FightCheck
+
+		//power
+		parseDecay(tower.Id, tower.PowerWeaken, ConvertClimbPowerDecayFactorList)
+		//time
+		parseDecay(tower.Id, tower.StayTimeWeaken, ConvertClimbTimeDecayFactorList)
+		//sp add
+		k, v := Str2Res(tower.SpAddition)
+		if k > 0 && v > 0 {
+			convertReward.SPAdd = &serverproto.KeyValueType{Key: k, Value: v}
+		}
+
+		ConvertTowerData[tower.Id] = convertReward
+	}
+}
+
+type ConvertEvilBossData struct {
+	EvilLevel       int32
+	MaxFightingTime int32
+	MonsterList     []*serverproto.KeyValueTypeList
+	LevelReward     map[int32]int32
+	LevelTimes      int32
+}
+
+var ConvertEvilBossList = map[int32]*ConvertEvilBossData{}
+
+func convertEvilCfg() {
+	for _, data := range serverproto.EvilCfgLoader {
+		convertData := &ConvertEvilBossData{
+			EvilLevel:       data.Id,
+			MaxFightingTime: data.MaxFightingTime,
+			LevelReward:     map[int32]int32{},
+		}
+		for idx := 0; idx < len(data.MonsterList); idx++ {
+			//id,addexp,cd,quality,weight
+			v1, v2, v3, v4, v5 := Str2Res_5(data.MonsterList[idx])
+			if v1 > 0 && v2 > 0 && v3 > 0 {
+				monsterData := &serverproto.KeyValueTypeList{
+					Key: v1,
+				}
+				monsterData.ValueList = append(monsterData.ValueList, v2, v3, v4, v5)
+				convertData.MonsterList = append(convertData.MonsterList, monsterData)
+			}
+		}
+
+		for idx := 0; idx < len(data.LevelReward); idx++ {
+			key, val := Str2Res(data.LevelReward[idx])
+			if key > 0 && val > 0 {
+				convertData.LevelReward[key] += val
+			}
+		}
+		convertData.LevelTimes = data.LevelTimes
+
+		ConvertEvilBossList[convertData.EvilLevel] = convertData
+	}
+}
+
+/*
+type ConvertVIPData struct {
+	VipId                int32 //vip等级, 1表示vip0,默认数值
+	EvilFreeRefreshCount int32 //恶魔免费刷新次数 数值0表示无限次数刷新
+}
+
+var ConvertVIPList = map[int32]*ConvertVIPData{}
+var maxVipLevel int32 = 0
+
+func convertVIPCfg() {
+	for _, data := range serverproto.VipCfgLoader {
+		vipData := &ConvertVIPData{
+			VipId:                data.Id,
+			EvilFreeRefreshCount: data.FreeTimes,
+		}
+		ConvertVIPList[vipData.VipId-1] = vipData
+		if data.Id > maxVipLevel {
+			maxVipLevel = data.Id - 1
+		}
+	}
+}
+func GetVIPDataByLevel(vipLevel int32) *ConvertVIPData {
+	if vipLevel < 0 {
+		vipLevel = maxVipLevel
+	}
+	if vipLevel > maxVipLevel {
+		vipLevel = maxVipLevel
+	}
+	if data, ok := ConvertVIPList[vipLevel]; ok {
+		return data
+	}
+	return nil
+}
+*/
+
+type CardCollectReward struct {
+	CardId     int32
+	CardReward map[int32]*serverproto.KeyValueType
+}
+
+var ConvertCardCollectReward = map[int32]*CardCollectReward{}
+
+func convertCardCollectCfg() {
+	for _, data := range serverproto.CardIdentificationLoader {
+		convertData := &CardCollectReward{
+			CardId:     data.Cardid,
+			CardReward: map[int32]*serverproto.KeyValueType{},
+		}
+		limitRes := strings.Split(data.CardReward1[0], ":")
+		if len(limitRes) >= 2 {
+			itemKey, _ := Str2Num(limitRes[0])
+			itemValue, _ := Str2Num(limitRes[1])
+			convertData.CardReward[1] = &serverproto.KeyValueType{
+				Key:   int32(itemKey),
+				Value: int32(itemValue),
+			}
+		}
+		limitRes = strings.Split(data.CardReward2[0], ":")
+		if len(limitRes) >= 2 {
+			itemKey, _ := Str2Num(limitRes[0])
+			itemValue, _ := Str2Num(limitRes[1])
+			convertData.CardReward[2] = &serverproto.KeyValueType{
+				Key:   int32(itemKey),
+				Value: int32(itemValue),
+			}
+		}
+		limitRes = strings.Split(data.CardReward3[0], ":")
+		if len(limitRes) >= 2 {
+			itemKey, _ := Str2Num(limitRes[0])
+			itemValue, _ := Str2Num(limitRes[1])
+			convertData.CardReward[3] = &serverproto.KeyValueType{
+				Key:   int32(itemKey),
+				Value: int32(itemValue),
+			}
+		}
+		limitRes = strings.Split(data.CardReward4[0], ":")
+		if len(limitRes) >= 2 {
+			itemKey, _ := Str2Num(limitRes[0])
+			itemValue, _ := Str2Num(limitRes[1])
+			convertData.CardReward[4] = &serverproto.KeyValueType{
+				Key:   int32(itemKey),
+				Value: int32(itemValue),
+			}
+		}
+		limitRes = strings.Split(data.CardReward5[0], ":")
+		if len(limitRes) >= 2 {
+			itemKey, _ := Str2Num(limitRes[0])
+			itemValue, _ := Str2Num(limitRes[1])
+			convertData.CardReward[5] = &serverproto.KeyValueType{
+				Key:   int32(itemKey),
+				Value: int32(itemValue),
+			}
+		}
+		ConvertCardCollectReward[data.Cardid] = convertData
+	}
+}
+
+var ConvertGuildLevel = map[int32]int32{}
+var ConvertLeaveGuildTime = map[int32]int32{}
+
+func convertGuildLevelCfg() {
+	for _, data := range serverproto.GuildLvCfgLoader {
+		ConvertGuildLevel[data.Id] = data.ExpRequire
+	}
+
+	cfgData, ok := serverproto.GlobalCfgLoader[int32(serverproto.GlobalType_Global_Guild_Leave_Guild_CD)]
+	if !ok {
+		util.PanicF("convertSign total count err:%v", len(ConvertSignUpData))
+	}
+
+	limitRes := strings.Split(cfgData.SVal, ";")
+	for _, res := range limitRes {
+		cdData := strings.Split(res, ":")
+		if len(cdData) >= 2 {
+			cdCount, _ := Str2Num(cdData[0])
+			cdTime, _ := Str2Num(cdData[1])
+
+			ConvertLeaveGuildTime[int32(cdCount)] = int32(cdTime)
+		}
+	}
+}
+
+// pet
+const (
+	Pet_Type_Normal = 1
+	Pet_Type_Mini   = 2
+	Pet_Type_MVP    = 3
+)
+
+type PetProgressData struct {
+	PetCfgId     int32
+	ProgressList []*ConvertPetProgressDataDetail
+}
+type ConvertPetProgressDataDetail struct {
+	ProgressLevel int32
+	CostZeny      int32 //消耗zeny
+	AttrList      []*serverproto.KeyValueType
+	RateList      []*serverproto.KeyValueType
+
+	//1品质 2进阶等级 3特殊属性
+	ConditionPet1 []*serverproto.KeyValueType //进阶消耗的材料
+	ConditionPet2 []*serverproto.KeyValueType //进阶消耗的材料
+}
+type ConvertPetSkillData struct {
+	SkillId       int32
+	RateList      []int32 //技能发动概率
+	MaxSkillLevel int32
+}
+type ConvertPetData struct {
+	PetCfgId         int32
+	Exp              int32                               //等级1对应的经验
+	ManualRewardList map[int32]*serverproto.KeyValueType //图鉴奖励
+	Quality          int32                               //1normal 2mini 3mvp
+	NatureType       int32
+	SkillList        []*ConvertPetSkillData //技能列表
+	JobType          int32
+}
+
+func (this *ConvertPetData) GetSkill(skillId int32) *ConvertPetSkillData {
+	for idx := 0; idx < len(this.SkillList); idx++ {
+		if this.SkillList[idx].SkillId == skillId {
+			return this.SkillList[idx]
+		}
+	}
+	return nil
+}
+func (this *ConvertPetData) GetSkillRate(skillId, skillLevel int32) int32 {
+	if skillLevel <= 0 {
+		return 0
+	}
+	for idx := 0; idx < len(this.SkillList); idx++ {
+		if this.SkillList[idx].SkillId == skillId &&
+			this.SkillList[idx].MaxSkillLevel >= skillLevel {
+			return this.SkillList[idx].RateList[int(skillLevel-1)]
+		}
+	}
+	return 0
+}
+
+type ConvertExpData struct {
+	PetLevel       int32
+	NormalExp      int32
+	NormalAccuExp  int32 //累计需要经验
+	NormalZeny     int32
+	NormalAccuZeny int32 //累计消耗zeny
+	MiniExp        int32
+	MiniAccuExp    int32
+	MiniZeny       int32
+	MiniAccuZeny   int32
+	MvpExp         int32
+	MvpAccuExp     int32
+	MvpZeny        int32
+	MvpAccuZeny    int32
+}
+type ConvertBondData struct {
+	BondId         int32
+	ConditionList1 []*serverproto.KeyValueType
+	ConditionList2 []*serverproto.KeyValueType
+	ConditionList3 []*serverproto.KeyValueType
+}
+
+type PetBondFightData struct {
+	FightPower1 []*serverproto.KeyValueType
+	FightPower2 []*serverproto.KeyValueType
+	FightPower3 []*serverproto.KeyValueType
+
+	Attr1List []*serverproto.KeyValueType
+	Attr2List []*serverproto.KeyValueType
+	Attr3List []*serverproto.KeyValueType
+}
+type PetProFightPower struct {
+	AttrMap map[int32]int32
+}
+
+type PetPartnerFightPower struct {
+	FightPower1 map[int32]int32
+	FightPower2 map[int32]int32
+	FightPower3 map[int32]int32
+}
+type ConvertPetEquipData struct {
+	CfgId              int32
+	Type               int32 //位置编号
+	Quality            int32 //绿色,蓝色,紫色,金色,红色
+	MaxLevel           int32
+	AdvanceTargetEquip int32
+	AdvanceCost        map[int32]int32
+	SuitId             int32
+	LevelUpList        map[int32]*ConvertPetEquipLevelUpData
+}
+type ConvertPetEquipLevelUpData struct {
+	Level      int32
+	CostList   map[int32]int32
+	AttrList   map[int32]int32
+	FightPower uint64
+}
+
+type ConvertPetEquipSuitData struct {
+	Id            int32
+	ConditionList []*serverproto.KeyValueType
+	AttrList      map[int32]int32
+}
+
+var ConvertPet = map[int32]*ConvertPetData{}
+var ConvertPetProgress = map[int32]*PetProgressData{}
+var ConvertPetExp = map[int32]*ConvertExpData{}
+var ConvertBond []*ConvertBondData
+
+var ConvertBondFight = map[int32]*PetBondFightData{}
+var ConvertPetProFight = map[int32]*PetProFightPower{}
+var ConvertPetPartnerFight = map[int32]*PetPartnerFightPower{}
+var ConvertPetEquip = map[int32]*ConvertPetEquipData{} //[equipcfgid][data]
+var ConvertPteEquipSuit []*ConvertPetEquipSuitData
+
+func getFieldData(fieldName string, data interface{}) []string {
+	tmpDataType := reflect.ValueOf(data).Elem()
+	tmpVal := tmpDataType.FieldByName(fieldName).Interface()
+	switch val := tmpVal.(type) {
+	case []string:
+		return val
+	default:
+		panic(errors.New("field type error"))
+	}
+	return nil
+}
+func convertPetCfg() {
+	//clean for reload
+	ConvertBond = []*ConvertBondData{}
+
+	//progress
+	for _, data := range serverproto.PetProgressCfgLoader {
+		progressData := &PetProgressData{
+			PetCfgId: data.Id,
+		}
+
+		for idx := 0; idx < len(data.CostMoney); idx++ {
+			constZeny, _ := Str2Num(data.CostMoney[idx])
+			detailData := &ConvertPetProgressDataDetail{
+				ProgressLevel: int32(idx) + 1,
+				CostZeny:      int32(constZeny),
+			}
+
+			//condition
+			tmpCondition1Str := "Condition" + strconv.Itoa(idx+1) + "1"
+			tmpCondition2Str := "Condition" + strconv.Itoa(idx+1) + "2"
+			tmpAttrStr := "Attribute" + strconv.Itoa(idx+1)
+			tmpAttributeRateAddStr := "AttributeRateAdd" + strconv.Itoa(idx+1)
+			convertPetCfg_ProgressCondition(getFieldData(tmpCondition1Str, data), getFieldData(tmpCondition2Str, data), detailData)
+			convertPetCfg_ProgressAttr(getFieldData(tmpAttrStr, data), getFieldData(tmpAttributeRateAddStr, data), detailData)
+			////condition
+			//switch idx {
+			//case 0:
+			//	convertPetCfg_ProgressCondition(data.Condition11, data.Condition12, detailData)
+			//	convertPetCfg_ProgressAttr(data.Attribute1, data.AttributeRateAdd1, detailData)
+			//case 1:
+			//	convertPetCfg_ProgressCondition(data.Condition21, data.Condition22, detailData)
+			//	convertPetCfg_ProgressAttr(data.Attribute2, data.AttributeRateAdd2, detailData)
+			//case 2:
+			//	convertPetCfg_ProgressCondition(data.Condition31, data.Condition32, detailData)
+			//	convertPetCfg_ProgressAttr(data.Attribute3, data.AttributeRateAdd3, detailData)
+			//case 3:
+			//	convertPetCfg_ProgressCondition(data.Condition41, data.Condition42, detailData)
+			//	convertPetCfg_ProgressAttr(data.Attribute4, data.AttributeRateAdd4, detailData)
+			//case 4:
+			//	convertPetCfg_ProgressCondition(data.Condition51, data.Condition52, detailData)
+			//	convertPetCfg_ProgressAttr(data.Attribute5, data.AttributeRateAdd5, detailData)
+			//}
+
+			progressData.ProgressList = append(progressData.ProgressList, detailData)
+
+			ConvertPetProgress[progressData.PetCfgId] = progressData
+
+			progressFight := &PetProFightPower{
+				AttrMap: make(map[int32]int32),
+			}
+			var totalFight int32 = 0
+			for idx, fightPower := range data.AddFight {
+				val, _ := Str2Num(fightPower)
+				totalFight += int32(val)
+				progressFight.AttrMap[int32(idx)] = totalFight
+			}
+			ConvertPetProFight[progressData.PetCfgId] = progressFight
+		}
+		ConvertPetProgress[progressData.PetCfgId] = progressData
+	}
+	//petskillup global
+
+	//pet
+	for _, data := range serverproto.PetCfgLoader {
+		petData := &ConvertPetData{
+			PetCfgId:   data.Id,
+			Quality:    data.Quality,
+			NatureType: data.NatureType,
+			JobType:    data.JobType,
+		}
+		petData.ManualRewardList = map[int32]*serverproto.KeyValueType{}
+		for idx := 0; idx < len(data.PetReward); idx++ {
+			advLevel, key, val := Str2Res_3(data.PetReward[idx])
+			if key > 0 && val > 0 {
+				petData.ManualRewardList[advLevel] = &serverproto.KeyValueType{Key: key, Value: val}
+			}
+		}
+		//skill
+		convertPetCfg_Skill(data.Skill1, data.Skill1Rate, petData)
+		convertPetCfg_Skill(data.Skill2, data.Skill2Rate, petData)
+		convertPetCfg_Skill(data.Skill3, data.Skill3Rate, petData)
+		convertPetCfg_Skill(data.Skill4, data.Skill4Rate, petData)
+
+		ConvertPet[petData.PetCfgId] = petData
+	}
+
+	//pet exp
+	var tmpList []*ConvertExpData
+	for _, data := range serverproto.PetExpCfgLoader {
+		expData := &ConvertExpData{
+			PetLevel:   data.PetLevel,
+			NormalExp:  data.Experience1,
+			NormalZeny: data.CostMoney1,
+			MiniExp:    data.Experience2,
+			MiniZeny:   data.CostMoney2,
+			MvpExp:     data.Experience3,
+			MvpZeny:    data.CostMoney3,
+		}
+		ConvertPetExp[expData.PetLevel] = expData
+		tmpList = append(tmpList, expData)
+	}
+	sort.Slice(tmpList, func(i, j int) bool {
+		return tmpList[i].PetLevel < tmpList[j].PetLevel
+	})
+	for idx := 0; idx < len(tmpList); idx++ {
+		tmpLevel := tmpList[idx].PetLevel
+		if tmpLevel > 1 {
+			tmpLevel := tmpList[idx].PetLevel
+			ConvertPetExp[tmpLevel].NormalAccuExp = ConvertPetExp[tmpLevel-1].NormalAccuExp + ConvertPetExp[tmpLevel].NormalExp
+			ConvertPetExp[tmpLevel].NormalAccuZeny = ConvertPetExp[tmpLevel-1].NormalAccuZeny + ConvertPetExp[tmpLevel].NormalZeny
+
+			ConvertPetExp[tmpLevel].MiniAccuExp = ConvertPetExp[tmpLevel-1].MiniAccuExp + ConvertPetExp[tmpLevel].MiniExp
+			ConvertPetExp[tmpLevel].MiniAccuZeny = ConvertPetExp[tmpLevel-1].MiniAccuZeny + ConvertPetExp[tmpLevel].MiniZeny
+
+			ConvertPetExp[tmpLevel].MvpAccuExp = ConvertPetExp[tmpLevel-1].MvpAccuExp + ConvertPetExp[tmpLevel].MvpExp
+			ConvertPetExp[tmpLevel].MvpAccuZeny = ConvertPetExp[tmpLevel-1].MvpAccuZeny + ConvertPetExp[tmpLevel].MvpZeny
+		} else {
+			ConvertPetExp[tmpLevel].NormalAccuExp = ConvertPetExp[tmpLevel].NormalExp
+			ConvertPetExp[tmpLevel].NormalAccuZeny = ConvertPetExp[tmpLevel].NormalZeny
+
+			ConvertPetExp[tmpLevel].MiniAccuExp = ConvertPetExp[tmpLevel].MiniExp
+			ConvertPetExp[tmpLevel].MiniAccuZeny = ConvertPetExp[tmpLevel].MiniZeny
+
+			ConvertPetExp[tmpLevel].MvpAccuExp = ConvertPetExp[tmpLevel].MvpExp
+			ConvertPetExp[tmpLevel].MvpAccuZeny = ConvertPetExp[tmpLevel].MvpZeny
+		}
+	}
+
+	//pet partner
+	for _, data := range serverproto.PetpartnerCfgLoader {
+		bondData := &ConvertBondData{
+			BondId: data.Id,
+		}
+		for idx := 0; idx < len(data.Condition1); idx++ {
+			key, val := Str2Res(data.Condition1[idx])
+			if key <= 0 {
+				continue
+			}
+			bondData.ConditionList1 = append(bondData.ConditionList1, &serverproto.KeyValueType{
+				Key: key, Value: val,
+			})
+		}
+		for idx := 0; idx < len(data.Condition2); idx++ {
+			key, val := Str2Res(data.Condition2[idx])
+			if key <= 0 {
+				continue
+			}
+			bondData.ConditionList2 = append(bondData.ConditionList2, &serverproto.KeyValueType{
+				Key: key, Value: val,
+			})
+		}
+		for idx := 0; idx < len(data.Condition3); idx++ {
+			key, val := Str2Res(data.Condition3[idx])
+			if key <= 0 {
+				continue
+			}
+			bondData.ConditionList3 = append(bondData.ConditionList3, &serverproto.KeyValueType{
+				Key: key, Value: val,
+			})
+		}
+		ConvertBond = append(ConvertBond, bondData)
+
+		//战斗力相关 key= {0,1,2,3,4,5}
+		bondFightData := &PetBondFightData{}
+		for idx := 0; idx < len(data.AddHeroCap1); idx++ {
+			key, val := Str2Res(data.AddHeroCap1[idx])
+			if key < 0 {
+				continue
+			}
+			bondFightData.FightPower1 = append(bondFightData.FightPower1, &serverproto.KeyValueType{
+				Key: key, Value: val,
+			})
+		}
+		for idx := 0; idx < len(data.AddHeroCap2); idx++ {
+			key, val := Str2Res(data.AddHeroCap1[idx])
+			if key < 0 {
+				continue
+			}
+			bondFightData.FightPower2 = append(bondFightData.FightPower2, &serverproto.KeyValueType{
+				Key: key, Value: val,
+			})
+		}
+		for idx := 0; idx < len(data.AddHeroCap3); idx++ {
+			key, val := Str2Res(data.AddHeroCap1[idx])
+			if key < 0 {
+				continue
+			}
+			bondFightData.FightPower3 = append(bondFightData.FightPower3, &serverproto.KeyValueType{
+				Key: key, Value: val,
+			})
+		}
+
+		//attr
+		for idx := 0; idx < len(data.Attribute1); idx++ {
+			k, v := Str2Res(data.Attribute1[idx])
+			if k <= 0 || v <= 0 {
+				continue
+			}
+			bondFightData.Attr1List = append(bondFightData.Attr1List, &serverproto.KeyValueType{Key: k, Value: v})
+		}
+		for idx := 0; idx < len(data.Attribute2); idx++ {
+			k, v := Str2Res(data.Attribute2[idx])
+			if k <= 0 || v <= 0 {
+				continue
+			}
+			bondFightData.Attr2List = append(bondFightData.Attr2List, &serverproto.KeyValueType{Key: k, Value: v})
+		}
+		for idx := 0; idx < len(data.Attribute3); idx++ {
+			k, v := Str2Res(data.Attribute3[idx])
+			if k <= 0 || v <= 0 {
+				continue
+			}
+			bondFightData.Attr3List = append(bondFightData.Attr3List, &serverproto.KeyValueType{Key: k, Value: v})
+		}
+
+		ConvertBondFight[data.Id] = bondFightData
+	}
+	sort.Slice(ConvertBond, func(i, j int) bool {
+		return ConvertBond[i].BondId < ConvertBond[j].BondId
+	})
+
+	//pet equip
+	//ConvertPetEquip
+	for _, data := range serverproto.PetEquipCfgLoader {
+		convertData := &ConvertPetEquipData{
+			CfgId:              data.Id,
+			Quality:            data.Quality,
+			Type:               data.Type,
+			MaxLevel:           data.MaxLevel,
+			AdvanceTargetEquip: data.Advance,
+			AdvanceCost:        map[int32]int32{},
+			LevelUpList:        map[int32]*ConvertPetEquipLevelUpData{},
+		}
+		Str2ResMapList(data.AdvanceCost, convertData.AdvanceCost)
+		ConvertPetEquip[convertData.CfgId] = convertData
+	}
+	for _, data := range serverproto.PetEquipExpCfgLoader {
+		convertData, ok := ConvertPetEquip[data.PetEquipID]
+		if !ok {
+			continue
+		}
+		levelData := &ConvertPetEquipLevelUpData{
+			Level:      data.PetEquipLevel,
+			CostList:   map[int32]int32{},
+			AttrList:   map[int32]int32{},
+			FightPower: uint64(data.FightPower),
+		}
+		Str2ResMapList(data.Cost, levelData.CostList)
+		Str2ResMapList(data.Nature, levelData.AttrList)
+
+		convertData.LevelUpList[data.PetEquipLevel] = levelData
+	}
+	for _, data := range serverproto.PetEquipSuitCfgLoader {
+		convertData := &ConvertPetEquipSuitData{
+			Id:       data.Id,
+			AttrList: map[int32]int32{},
+		}
+		Str2ResMapList(data.Suit, convertData.AttrList)
+		convertData.ConditionList = append(convertData.ConditionList, Str2ResSliceList(data.Amount)...)
+
+		ConvertPteEquipSuit = append(ConvertPteEquipSuit, convertData)
+	}
+	sort.Slice(ConvertPteEquipSuit, func(i, j int) bool {
+		return ConvertPteEquipSuit[i].Id > ConvertPteEquipSuit[j].Id
+	})
+}
+
+func convertPetCfg_ProgressCondition(conditionList1 []string, conditionList2 []string, detailData *ConvertPetProgressDataDetail) {
+	for idx := 0; idx < len(conditionList1); idx++ {
+		kvList := &serverproto.KeyValueType{}
+		v1, v2 := Str2Res(conditionList1[idx])
+		if v1 > 0 {
+			kvList.Key = v1
+			kvList.Value = v2
+		}
+		detailData.ConditionPet1 = append(detailData.ConditionPet1, kvList)
+	}
+
+	for idx := 0; idx < len(conditionList2); idx++ {
+		kvList := &serverproto.KeyValueType{}
+		v1, v2 := Str2Res(conditionList2[idx])
+		if v1 > 0 {
+			kvList.Key = v1
+			kvList.Value = v2
+		}
+		detailData.ConditionPet2 = append(detailData.ConditionPet2, kvList)
+	}
+}
+func convertPetCfg_ProgressAttr(attrList []string, rateList []string, detailData *ConvertPetProgressDataDetail) {
+	for idx := 0; idx < len(attrList); idx++ {
+		key, val := Str2Res(attrList[idx])
+		if key > 0 && val > 0 {
+			detailData.AttrList = append(detailData.AttrList, &serverproto.KeyValueType{
+				Key: key, Value: val,
+			})
+		}
+	}
+
+	for idx := 0; idx < len(rateList); idx++ {
+		key, val := Str2Res(rateList[idx])
+		if key > 0 && val > 0 {
+			detailData.RateList = append(detailData.RateList, &serverproto.KeyValueType{
+				Key: key, Value: val,
+			})
+		}
+	}
+}
+func convertPetCfg_Skill(skillId int32, skillRateList []string, petData *ConvertPetData) {
+	if skillId > 0 {
+		skill1 := &ConvertPetSkillData{
+			SkillId: skillId,
+		}
+		for idx := 0; idx < len(skillRateList); idx++ {
+			val, _ := Str2Num(skillRateList[idx])
+			skill1.RateList = append(skill1.RateList, int32(val))
+		}
+		skill1.MaxSkillLevel = int32(len(skill1.RateList))
+		petData.SkillList = append(petData.SkillList, skill1)
+	}
+}
+
+type GuildBossReward struct {
+	RewardList map[int32]int32
+}
+
+type RankReward struct {
+	MaxDam       int32
+	MinDam       int32
+	RewardID     int32
+	MasterReward int32
+}
+
+type GuildBossRank struct {
+	Reward    []*RankReward
+	MaxDamage int32
+}
+
+var ConvertGuildBossReward = map[int32]*GuildBossReward{}
+var ConvertGuildBossRewardRank = map[int32]*GuildBossRank{}
+
+func convertGuildBosRewardsCfg() {
+	for _, reward := range serverproto.GuildBossRewardCfgLoader {
+		convertReward := &GuildBossReward{
+			RewardList: map[int32]int32{},
+		}
+
+		for _, data := range reward.Reward {
+			strList := strings.Split(data, ":")
+			if len(strList) >= 2 {
+				itemKey, _ := Str2Num(strList[0])
+				itemValue, _ := Str2Num(strList[1])
+				convertReward.RewardList[int32(itemKey)] = int32(itemValue)
+			}
+		}
+		ConvertGuildBossReward[reward.Id] = convertReward
+	}
+
+	for _, guildBoss := range serverproto.GuildBossCfgLoader {
+		convertGuildBossRank := &GuildBossRank{}
+
+		if len(guildBoss.RewardRange) != len(guildBoss.Reward) {
+			util.PanicF("[convertGuildBosRewardsCfg] reward config error:%v, %v, %v", guildBoss.Id, len(guildBoss.RewardRange), len(guildBoss.Reward))
+		}
+		if guildBoss.BossType == 1 { //1 普通boss 2 精英boss
+			if len(guildBoss.RewardRange) != len(guildBoss.MasterReward) {
+				util.PanicF("[convertGuildBosRewardsCfg] MasterReward config error:%v", guildBoss.Id)
+			}
+		}
+
+		for idx, rank := range guildBoss.RewardRange {
+			strList := strings.Split(rank, ":")
+			minDam, _ := Str2Num(strList[0])
+			maxDam, _ := Str2Num(strList[1])
+
+			if len(strList) >= 2 {
+				rankReward := &RankReward{}
+				rankReward.MinDam = int32(minDam)
+				rankReward.MaxDam = int32(maxDam)
+				rewardId, _ := Str2Num(guildBoss.Reward[idx])
+				rankReward.RewardID = int32(rewardId)
+				if guildBoss.BossType == 1 { //1 普通boss 2 精英boss
+					masterId, _ := Str2Num(guildBoss.MasterReward[idx])
+					rankReward.MasterReward = int32(masterId)
+				}
+
+				convertGuildBossRank.Reward = append(convertGuildBossRank.Reward, rankReward)
+			}
+		}
+		ConvertGuildBossRewardRank[guildBoss.Id] = convertGuildBossRank
+	}
+}
+
+var ConvertGuildBattleList = map[int32]int32{}
+
+func convertGuildBattleCfg() {
+	for _, cfgData := range serverproto.GuildWarDojoCfgLoader {
+		ConvertGuildBattleList[cfgData.Id] = cfgData.GuildWarPoint
+	}
+}
+
+type ConvertExpedition struct {
+	ExpeditionType    int32
+	LevelNum          int32
+	LevelUnlockAddNum int32
+	//UnlockCondition   []*serverproto.KeyValueType
+	LevelInfo        map[int32]*ConvertExpeditionDetailInfo
+	LevelCoefficient float32
+	PassRewardList   []*serverproto.KeyValueType //通关奖励(每日获取一次)
+}
+
+func (this *ConvertExpedition) GetLevelReward(levelIdx int32, addItemList map[int32]int32) {
+	levelData, ok := this.LevelInfo[levelIdx]
+	if !ok {
+		return
+	}
+	for idx := 0; idx < len(levelData.RewardList); idx++ {
+		addItemList[levelData.RewardList[idx].Key] += levelData.RewardList[idx].Value
+	}
+}
+
+type ConvertExpeditionBossInfo struct {
+	Weight    int32
+	BossId    int32
+	BossLevel int32
+	BossHP    int32
+	BossSP    int32
+}
+type ConvertExpeditionDetailInfo struct {
+	Id              int32
+	LevelId         int32
+	BossList        []*ConvertExpeditionBossInfo
+	BuffList        []*serverproto.KeyValueType //key:id val:weight
+	RewardList      []*serverproto.KeyValueType
+	MaxFightingTime int32
+	WarriorScore    int32 //勇士积分
+}
+
+func (this *ConvertExpeditionDetailInfo) RandBoss(tmpBossIdxList []int) (*ConvertExpeditionBossInfo, int) {
+	var totalWeight int32 = 0
+	var tmpList []*serverproto.KeyValueType
+
+	for idx := 0; idx < len(this.BossList); idx++ {
+		bFind := false
+		for k := 0; k < len(tmpBossIdxList); k++ {
+			if idx == tmpBossIdxList[k] {
+				bFind = true
+				break
+			}
+		}
+		if bFind {
+			continue
+		}
+
+		totalWeight += this.BossList[idx].Weight
+		tmpList = append(tmpList, &serverproto.KeyValueType{Key: int32(idx), Value: totalWeight})
+	}
+
+	if totalWeight <= 0 {
+		return nil, 0
+	}
+	var retBossIdx = 0
+	randWeight := rand.Int31n(totalWeight) + 1
+	for idx := 0; idx < len(tmpList); idx++ {
+		retBossIdx = int(tmpList[idx].Key)
+		if tmpList[idx].Value >= randWeight {
+			break
+		}
+	}
+	return this.BossList[retBossIdx], retBossIdx
+}
+
+func (this *ConvertExpeditionDetailInfo) RandBuff(hasBuffList set.Interface, tmpBuffList []int32, bossId uint64) int32 {
+	var retBuffId int32 = 0
+	var totalWeight int32 = 0
+	var tmpList []*serverproto.KeyValueType
+	bossBuffList, ok := ConvertExpeditionDropBuffList[bossId]
+	if !ok {
+		util.InfoF("Expedition bossid=%v randBuffList empty", bossId)
+		return retBuffId
+	}
+
+	if len(bossBuffList.BuffList) <= 0 {
+		util.InfoF("Expedition bossid=%v randBuffList empty", bossId)
+		return retBuffId
+	}
+
+	for idx := 0; idx < len(bossBuffList.BuffList); idx++ {
+		if hasBuffList.Has(bossBuffList.BuffList[idx].Key) {
+			continue
+		}
+		bFind := false
+		for k := 0; k < len(tmpBuffList); k++ {
+			if tmpBuffList[k] == bossBuffList.BuffList[idx].Key {
+				bFind = true
+				break
+			}
+		}
+		if bFind {
+			continue
+		}
+
+		totalWeight += bossBuffList.BuffList[idx].Value
+		tmpList = append(tmpList, &serverproto.KeyValueType{Key: bossBuffList.BuffList[idx].Key, Value: totalWeight})
+	}
+
+	if totalWeight <= 0 {
+		return 0
+	}
+
+	randWeight := rand.Int31n(totalWeight) + 1
+	for idx := 0; idx < len(tmpList); idx++ {
+		retBuffId = tmpList[idx].Key
+		if tmpList[idx].Value >= randWeight {
+			break
+		}
+	}
+	return retBuffId
+}
+
+type ConvertExpeditionBuffInfo struct {
+	Id           uint64
+	BossId       int32
+	LevelId      int32                       //关卡唯一ID
+	BuffList     []*serverproto.KeyValueType //key:id val:weight
+	WarriorScore int32                       //勇士积分
+}
+
+var ConvertExpeditionDataList = map[int32]*ConvertExpedition{}
+var ConvertExpeditionDropBuffList = map[uint64]*ConvertExpeditionBuffInfo{}
+
+func convertExpeditionCfg() {
+	//ExpeditionCfg
+	for _, cfgData := range serverproto.ExpeditionCfgLoader {
+		convertData, ok := ConvertExpeditionDataList[cfgData.Type]
+		if !ok {
+			convertData = &ConvertExpedition{
+				ExpeditionType: cfgData.Type,
+				LevelNum:       cfgData.LevelNum,
+				LevelInfo:      map[int32]*ConvertExpeditionDetailInfo{},
+			}
+			ConvertExpeditionDataList[cfgData.Type] = convertData
+		}
+		if cfgData.Type > 0 {
+			convertData.ExpeditionType = cfgData.Type
+		}
+		if cfgData.LevelNum > 0 {
+			convertData.LevelNum = cfgData.LevelNum
+		}
+		if cfgData.ChallengeNum > 0 {
+			convertData.LevelUnlockAddNum = cfgData.ChallengeNum
+		}
+		if cfgData.LevelCoefficient > 0 {
+			convertData.LevelCoefficient = float32(cfgData.LevelCoefficient) / 100
+		}
+		if len(cfgData.DayReward) > 0 {
+			for idx := 0; idx < len(cfgData.DayReward); idx++ {
+				key, val := Str2Res(cfgData.DayReward[idx])
+				if key <= 0 || val <= 0 {
+					continue
+				}
+				convertData.PassRewardList = append(convertData.PassRewardList,
+					&serverproto.KeyValueType{Key: key, Value: val})
+			}
+		}
+
+		//level info
+		levelInfo := &ConvertExpeditionDetailInfo{
+			Id:              cfgData.Id,
+			LevelId:         cfgData.LevelId,
+			MaxFightingTime: cfgData.MaxFightingTime,
+			WarriorScore:    cfgData.WarriorScore,
+		}
+		//level boss list
+		var totalWeight int32 = 0
+		for idx := 0; idx < len(cfgData.BossList); idx++ {
+			weight, bossId, level, hp, sp := Str2Res_5(cfgData.BossList[idx])
+			if bossId <= 0 || level <= 0 || hp <= 0 || sp <= 0 {
+				continue
+			}
+			totalWeight = weight
+			bossInfo := &ConvertExpeditionBossInfo{
+				Weight:    totalWeight,
+				BossId:    bossId,
+				BossLevel: level,
+				BossHP:    hp,
+				BossSP:    sp,
+			}
+			levelInfo.BossList = append(levelInfo.BossList, bossInfo)
+		}
+		//level reward list
+		for idx := 0; idx < len(cfgData.Reward); idx++ {
+			key, val := Str2Res(cfgData.Reward[idx])
+			if key <= 0 || val <= 0 {
+				continue
+			}
+			levelInfo.RewardList = append(levelInfo.RewardList, &serverproto.KeyValueType{Key: key, Value: val})
+		}
+
+		convertData.LevelInfo[levelInfo.LevelId] = levelInfo
+	}
+	//boss drop buff list
+	for _, cfgData := range serverproto.ExpeditionBuffDropCfgLoader {
+		bossBuffData := &ConvertExpeditionBuffInfo{
+			BossId:       cfgData.BossID,
+			LevelId:      cfgData.LevelId,
+			WarriorScore: cfgData.WarriorScore,
+		}
+		bossBuffData.Id = uint64(bossBuffData.BossId)*100000 + uint64(bossBuffData.LevelId)
+
+		for idx := 0; idx < len(cfgData.Buffs); idx++ {
+			weight, buffId := Str2Res(cfgData.Buffs[idx])
+			if buffId <= 0 {
+				continue
+			}
+			bossBuffData.BuffList = append(bossBuffData.BuffList, &serverproto.KeyValueType{Key: buffId, Value: weight})
+		}
+		ConvertExpeditionDropBuffList[bossBuffData.Id] = bossBuffData
+	}
+
+	//检查boss数据是否存在
+	for _, typeData := range ConvertExpeditionDataList {
+		for _, levelData := range typeData.LevelInfo {
+			for idx := 0; idx < len(levelData.BossList); idx++ {
+				//对应level boss是否存在掉落buff数据
+				tmpId := uint64(levelData.BossList[idx].BossId)*100000 + uint64(levelData.Id)
+				if _, ok := ConvertExpeditionDropBuffList[tmpId]; !ok {
+					//panic(errors.New("level boss not exist drop buff data:" + strconv.FormatUint(tmpId, 10)))
+				}
+			}
+		}
+	}
+}
+
+// /精彩活动
+type ConvertActivitiesData struct {
+	Id                  int32
+	ActivityType        int32
+	StartTimeStr        string
+	EndTimeStr          string
+	TerminalOpenTimeStr string
+	OpenConditionList   []*serverproto.KeyValueType
+	BG                  string
+	ServiceMark         int32 //是否为合服活动
+
+	TimeType  int //1绝对时间 2相对开服时间 3相对角色创建时间
+	StartTime time.Time
+	EndTime   time.Time
+
+	StartDay int
+	EndDay   int
+
+	CalStartTime time.Time
+	CalEndTime   time.Time
+	CalEndTimeMs uint64
+
+	HDItemList set.Interface
+
+	//过期后的活动是否强制开启(之前没有开启过,只针对相对开服时间开启的活动类型)
+	ExpiredActivities bool
+	//活动开启最后截至时间(填写绝对时间)
+	TerminalOpenTime   time.Time
+	TerminalOpenTimeMs uint64
+}
+type ConvertActivitiesTaskData struct {
+	TaskId        int32
+	ConditionList map[int32][]int32
+	RewardList    map[int32]int32
+	TaskScore     int32
+}
+
+var ConvertActivitiesList = map[int32]*ConvertActivitiesData{}
+var ConvertActivitiesTaskList = map[int32]*ConvertActivitiesTaskData{}
+
+// 14日连续登录活动
+// key=ActivitiesId * 1000 + Day
+var ConvertActivitiesFOList = map[int32]map[int32]int32{}
+
+// 14日阶段目标
+type ConvertActivitiesFortnightDaysData struct {
+	Days          int32
+	TaskList      []uint32
+	DailyTaskList []uint32
+}
+type ConvertActivitiesFortnightDaysScoreData struct {
+	RewardIdx  int32
+	Score      int32
+	RewardList map[int32]int32
+}
+
+var ConvertActivitiesFortnightDaysList = map[int32]*ConvertActivitiesFortnightDaysData{}
+var ConvertActivitiesFortnightDaysScoreList = map[int32][]*ConvertActivitiesFortnightDaysScoreData{}
+
+// 首充/百元礼包
+type ConvertActFirstRechargeData struct {
+	OpenConditionList    []*serverproto.KeyValueType
+	OpenConditionStrList []string
+	RechargeAmount       float32 //达到该金额解锁首充奖励获取
+	Day1Reward           []*serverproto.KeyValueType
+	Day2Reward           []*serverproto.KeyValueType
+	Day3Reward           []*serverproto.KeyValueType
+}
+
+var ConvertActFirstRecharge *ConvertActFirstRechargeData = nil
+var ConvertAct100Recharge *ConvertActFirstRechargeData = nil
+
+type StActTiredRecharge struct {
+	Day     int32
+	Amount  float32
+	Rewards []*serverproto.KeyValueType
+}
+
+// 累计充值奖励
+var ConvertActTiredRecharge = map[int32]*StActTiredRecharge{}
+
+func GetActTiredRechargeDb(index, day int32) *StActTiredRecharge {
+	dbDay := int32(0)
+	for _, recharge := range ConvertActTiredRecharge {
+		if day >= recharge.Day {
+			if dbDay <= 0 || recharge.Day > dbDay {
+				dbDay = recharge.Day
+			}
+		}
+	}
+	// 左16位 当天领奖档次, 右16位活动天数
+	db := ConvertActTiredRecharge[index<<16|dbDay]
+	return db
+}
+
+// 超值礼包
+type ConvertActDiscountsRechargeData struct {
+	Id            int32
+	ProductId     int32
+	Name          string
+	OpenCondition *serverproto.KeyValueTypeList
+	Amount        float32 //购买价格
+	RewardList    []*serverproto.KeyValueType
+	DurationTime  uint64 //持续时间
+	UnlockCount   int32  //触发次数
+	Recharge      int32  //历史累计充值档位
+}
+
+var ConvertActDiscountsRecharge = map[int32]*ConvertActDiscountsRechargeData{}
+
+// [type][id][data]
+var ConvertActDiscountsRechargeList = map[int32][]*ConvertActDiscountsRechargeData{}
+
+type ConvertActCollectionData struct {
+	Id                    int32
+	Name                  string
+	Order                 int32
+	ExchangeConditionList map[int32]int32
+	ServerRewardNum       int32 //全服奖励数量
+	RewardNum             int32 //兑换奖励次数上限
+	RewardList            []*serverproto.KeyValueType
+	ActivitiesId          int32
+}
+
+var ConvertActCollection = map[int32]*ConvertActCollectionData{}
+
+type ConvertActLikabilityItemData struct {
+	ActivityId       int32
+	LikabilityItemId int32 //道具id
+	LikabilityList   []*serverproto.KeyValueTypeList
+}
+
+//var ConvertActLikabilityItem = map[int32]*ConvertActLikabilityItemData{}
+
+// [activityid][level][item...]
+var ConvertActLikabilityItemList = map[int32]map[int32]*ConvertActLikabilityItemData{}
+
+type ConvertActLikabilityData struct {
+	ActivityId int32
+	Level      int32
+	LikeValMax int32
+	RewardList []*serverproto.KeyValueTypeList
+}
+
+// var ConvertActLikability = map[int32]*ConvertActLikabilityData{}
+var ConvertActLikabilityList = map[int32]map[int32]*ConvertActLikabilityData{}
+
+const (
+	Exchange_Type_Special = 1
+	Exchange_Type_Common  = 2
+)
+
+const (
+	Exchange_Activity_Type_Pet  = 0
+	Exchange_Activity_Type_Card = 1
+)
+
+type ExchangePetCondition struct {
+	CondType    int32
+	ConditionId int32
+	Id          int32
+	Level       int32
+	SkillLevel  int32
+	Count       int32
+}
+
+type ExchangeCardCondition struct {
+	CondType    int32
+	ConditionId int32
+	ItemType    int32
+	ItemLevel   int32
+	ItemId      int32
+	ItemCount   int32
+	ItemQuality int32
+	Scope       map[int32]int32
+}
+
+type ConvertExchangeData struct {
+	Id              int32
+	ActivitiesId    int32
+	ActivitiesType  int32
+	ConditionPet    []*ExchangePetCondition
+	ConditionCard   []*ExchangeCardCondition
+	Reward          []*serverproto.KeyValueType
+	RewardNum       int32 //兑换次数
+	ServerRewardNum int32
+	BroadCast       int32
+}
+
+var ConvertExchange = map[int32]*ConvertExchangeData{}
+
+type ResetIndexs struct {
+	Id []int32
+}
+
+var ConvertExchangeReset = map[int32]*ResetIndexs{}
+
+const (
+	ActivitiesTime_Type_None   = 0 //永久活动时间
+	ActivitiesTime_Type_Global = 1 //绝对时间
+	ActivitiesTime_Type_Server = 2 //相对开服时间    //根据开服时间endday-startday(持续时间)
+	ActivitiesTime_Type_Role   = 3 //相对角色创建时间 //根据创建角色时间endday-startday + 1(持续时间)
+	ActivitiesTime_Type_System = 4 //根据玩家开启系统决定活动开启时间
+)
+
+func convertActivitiesCfg() {
+	//ActivitiesCfg
+	for _, cfgData := range serverproto.ActivitiesCfgLoader {
+		tmpData := &ConvertActivitiesData{
+			Id:           cfgData.Id,
+			ActivityType: cfgData.Type,
+			BG:           cfgData.BG,
+			HDItemList:   set.New(set.NonThreadSafe),
+			ServiceMark:  cfgData.ServiceMark,
+		}
+
+		for idx := 0; idx < len(cfgData.OpenCondition); idx++ {
+			key, val := Str2Res(cfgData.OpenCondition[idx])
+			if key > 0 {
+				tmpData.OpenConditionList = append(tmpData.OpenConditionList, &serverproto.KeyValueType{Key: key, Value: val})
+			}
+		}
+		startDataList := strings.Split(cfgData.StartTime, ";")
+		endDataList := strings.Split(cfgData.EndTime, ";")
+		if len(startDataList) > 0 && len(endDataList) > 0 {
+			tmpData.TimeType, _ = Str2Num(startDataList[0])
+			switch tmpData.TimeType {
+			case ActivitiesTime_Type_Global: //绝对时间
+				loc := util.GetLoc()
+				tmpData.StartTime, _ = time.ParseInLocation(util.DATE_FORMAT, startDataList[1], loc)
+				tmpData.EndTime, _ = time.ParseInLocation(util.DATE_FORMAT, endDataList[1], loc)
+				tmpData.StartTimeStr = startDataList[1]
+				tmpData.EndTimeStr = endDataList[1]
+			case ActivitiesTime_Type_Server: //相对开服时间
+				fallthrough
+			case ActivitiesTime_Type_Role: //相对创建角色时间
+				tmpData.StartDay, _ = Str2Num(startDataList[1])
+				tmpData.EndDay, _ = Str2Num(endDataList[1])
+				tmpData.StartTimeStr = startDataList[2]
+				tmpData.EndTimeStr = endDataList[2]
+				if tmpData.EndDay < tmpData.StartDay {
+					continue
+				}
+				loc := util.GetLoc()
+				tmpData.StartTime, _ = time.ParseInLocation(util.DATE_FORMAT2, startDataList[2], loc)
+				tmpData.EndTime, _ = time.ParseInLocation(util.DATE_FORMAT2, endDataList[2], loc)
+
+				if len(startDataList) >= 4 {
+					tmpData.TerminalOpenTimeStr = startDataList[3]
+					tmpData.TerminalOpenTime = util.GetTimeByStr(tmpData.TerminalOpenTimeStr)
+					tmpData.TerminalOpenTimeMs = uint64(tmpData.TerminalOpenTime.UnixNano() / 1e6)
+				}
+			case ActivitiesTime_Type_System: //根据玩家开启系统决定活动开启时间
+			}
+		} else {
+			//永久活动时间
+			tmpData.TimeType = 0
+		}
+
+		//过期后的活动是否强制开启(之前没有开启过,只针对相对开服时间开启的活动类型)
+		if cfgData.ExpiredActivities > 0 && tmpData.TimeType == ActivitiesTime_Type_Server {
+			tmpData.ExpiredActivities = true
+		}
+
+		//是否有活动道具
+		for idx := 0; idx < len(cfgData.HdDrop); idx++ {
+			hdItemId, _ := Str2Num(cfgData.HdDrop[idx])
+			if hdItemId > 0 {
+				tmpData.HDItemList.Add(int32(hdItemId))
+			}
+		}
+
+		ConvertActivitiesList[tmpData.Id] = tmpData
+	}
+	//ActivityTaskCfg
+	for _, cfgData := range serverproto.ActivitiesTaskCfgLoader {
+		tmpData := &ConvertActivitiesTaskData{
+			TaskId:        cfgData.TaskId,
+			TaskScore:     cfgData.Integral,
+			RewardList:    map[int32]int32{},
+			ConditionList: map[int32][]int32{},
+		}
+		for idx := 0; idx < len(cfgData.TaskCondition); idx++ {
+			valueList := strings.Split(cfgData.TaskCondition[idx], ":")
+			if len(valueList) >= 2 {
+				taskType, _ := Str2Num(valueList[0])
+				tmpData.ConditionList[int32(taskType)] = append(tmpData.ConditionList[int32(taskType)], int32(taskType))
+				for i := 1; i < len(valueList); i++ {
+					taskValue, _ := Str2Num(valueList[i])
+					tmpData.ConditionList[int32(taskType)] = append(tmpData.ConditionList[int32(taskType)], int32(taskValue))
+				}
+			}
+		}
+		for idx := 0; idx < len(cfgData.Reward); idx++ {
+			key, val := Str2Res(cfgData.Reward[idx])
+			if key > 0 && val > 0 {
+				tmpData.RewardList[key] += val
+			}
+		}
+
+		ConvertActivitiesTaskList[tmpData.TaskId] = tmpData
+	}
+	//ActivitiesFortnightOnlineCfg
+	for _, cfgData := range serverproto.ActivitiesFortnightOnlineCfgLoader {
+		tempId := cfgData.ActivitiesId*1000 + cfgData.Day
+		ConvertActivitiesFOList[tempId] = map[int32]int32{}
+		for idx := 0; idx < len(cfgData.Rewards); idx++ {
+			key, val := Str2Res(cfgData.Rewards[idx])
+			if key > 0 && val > 0 {
+				ConvertActivitiesFOList[tempId][key] += val
+			}
+		}
+	}
+	//ActivitiesFortnightDaysCfg
+	duplicateSet := set.New(set.NonThreadSafe)
+	for _, cfgData := range serverproto.ActivitiesFortnightDaysCfgLoader {
+		tmpData := &ConvertActivitiesFortnightDaysData{
+			Days: cfgData.Id,
+		}
+		for idx := 0; idx < len(cfgData.TaskIds); idx++ {
+			taskId, _ := Str2Num(cfgData.TaskIds[idx])
+			if duplicateSet.Has(taskId) {
+				panic("task id repeated")
+			}
+			duplicateSet.Add(taskId)
+			tmpData.TaskList = append(tmpData.TaskList, uint32(taskId))
+		}
+		for idx := 0; idx < len(cfgData.DailyTaskIds); idx++ {
+			taskId, _ := Str2Num(cfgData.DailyTaskIds[idx])
+			if duplicateSet.Has(taskId) {
+				panic("task id repeated")
+			}
+			duplicateSet.Add(taskId)
+			tmpData.DailyTaskList = append(tmpData.DailyTaskList, uint32(taskId))
+		}
+		ConvertActivitiesFortnightDaysList[tmpData.Days] = tmpData
+	}
+
+	//ActivitiesRewardCfg
+	//task score reward
+	for _, cfgData := range serverproto.ActivitiesRewardCfgLoader {
+		scoreData := &ConvertActivitiesFortnightDaysScoreData{
+			RewardIdx:  cfgData.Id,
+			Score:      cfgData.Integral,
+			RewardList: map[int32]int32{},
+		}
+		for idx := 0; idx < len(cfgData.Rewards); idx++ {
+			key, val := Str2Res(cfgData.Rewards[idx])
+			if key > 0 && val > 0 {
+				scoreData.RewardList[key] += val
+			}
+		}
+		//Type 1第一周 2第二周
+		ConvertActivitiesFortnightDaysScoreList[cfgData.Type] = append(ConvertActivitiesFortnightDaysScoreList[cfgData.Type], scoreData)
+	}
+
+	//ActiviesFirstChargeCfg
+	for _, cfgData := range serverproto.ActivitiesFirstChargeCfgLoader {
+		tmpData := &ConvertActFirstRechargeData{
+			RechargeAmount: float32(cfgData.RechargeAmount),
+		}
+		tmpData.OpenConditionStrList = cfgData.OpenCondition
+		for idx := 0; idx < len(cfgData.OpenCondition); idx++ {
+			k, v := Str2Res(cfgData.OpenCondition[idx])
+			if k > 0 && v > 0 {
+				tmpData.OpenConditionList = append(tmpData.OpenConditionList, &serverproto.KeyValueType{Key: k, Value: v})
+			}
+		}
+		for idx := 0; idx < len(cfgData.Reward1); idx++ {
+			k, v := Str2Res(cfgData.Reward1[idx])
+			if k > 0 && v > 0 {
+				tmpData.Day1Reward = append(tmpData.Day1Reward, &serverproto.KeyValueType{Key: k, Value: v})
+			}
+		}
+		for idx := 0; idx < len(cfgData.Reward2); idx++ {
+			k, v := Str2Res(cfgData.Reward2[idx])
+			if k > 0 && v > 0 {
+				tmpData.Day2Reward = append(tmpData.Day2Reward, &serverproto.KeyValueType{Key: k, Value: v})
+			}
+		}
+		for idx := 0; idx < len(cfgData.Reward3); idx++ {
+			k, v := Str2Res(cfgData.Reward3[idx])
+			if k > 0 && v > 0 {
+				tmpData.Day3Reward = append(tmpData.Day3Reward, &serverproto.KeyValueType{Key: k, Value: v})
+			}
+		}
+		//first recharge
+		if cfgData.Id == 1 {
+			ConvertActFirstRecharge = tmpData
+		} else if cfgData.Id == 2 {
+			//百元大礼包
+			ConvertAct100Recharge = tmpData
+		}
+	}
+	//ActiviesTiredChargeCfg 累计充值奖励
+	for _, cfgData := range serverproto.ActivitiesTiredChargeCfgLoader {
+		dbData := &StActTiredRecharge{Amount: cfgData.RechargeAmount, Day: cfgData.Day}
+		for idx := 0; idx < len(cfgData.Reward); idx++ {
+			k, v := Str2Res(cfgData.Reward[idx])
+			if k <= 0 || v <= 0 {
+				continue
+			}
+			dbData.Rewards = append(dbData.Rewards, &serverproto.KeyValueType{Key: k, Value: v})
+		}
+		// 左16位 当天领奖档次, 右16位活动天数
+		ConvertActTiredRecharge[cfgData.Index<<16|cfgData.Day] = dbData
+	}
+	//ActiviesDiscountsCfg //超值礼包
+	for _, cfgData := range serverproto.ActivitiesDiscountsCfgLoader {
+		tmpData := &ConvertActDiscountsRechargeData{
+			Id:           cfgData.Id,
+			Amount:       float32(cfgData.Money),
+			DurationTime: uint64(cfgData.Time) * 1000,
+			Name:         cfgData.Name,
+			UnlockCount:  cfgData.Popup,
+			Recharge:     cfgData.Recharge,
+			ProductId:    cfgData.ProductID,
+		}
+		for idx := 0; idx < len(cfgData.Reward); idx++ {
+			k, v := Str2Res(cfgData.Reward[idx])
+			if k <= 0 || v <= 0 {
+				continue
+			}
+			tmpData.RewardList = append(tmpData.RewardList, &serverproto.KeyValueType{Key: k, Value: v})
+		}
+		for idx := 0; idx < len(cfgData.TriggeringCondition); idx++ {
+			valList := strings.Split(cfgData.TriggeringCondition[idx], ":")
+			key, _ := Str2Num(valList[0])
+			tmpData.OpenCondition = &serverproto.KeyValueTypeList{Key: int32(key)}
+			for k := 1; k < len(valList); k++ {
+				val, _ := Str2Num(valList[k])
+				tmpData.OpenCondition.ValueList = append(tmpData.OpenCondition.ValueList, int32(val))
+			}
+			break
+		}
+		ConvertActDiscountsRecharge[cfgData.Id] = tmpData
+
+		//分类优化性能
+		ConvertActDiscountsRechargeList[tmpData.OpenCondition.Key] = append(
+			ConvertActDiscountsRechargeList[tmpData.OpenCondition.Key], tmpData)
+	}
+	for key, _ := range ConvertActDiscountsRechargeList {
+		sort.Slice(ConvertActDiscountsRechargeList[key], func(i, j int) bool {
+			return ConvertActDiscountsRechargeList[key][i].OpenCondition.ValueList[0] < ConvertActDiscountsRechargeList[key][j].OpenCondition.ValueList[0]
+		})
+	}
+
+	//ActivitiesCollectionCfg 集字活动
+	//var ConvertActCollection = map[int32]*ConvertActCollectionData{}
+	for _, cfgData := range serverproto.ActivitiesCollectionCfgLoader {
+		tmpData := &ConvertActCollectionData{
+			Id:                    cfgData.Id,
+			ExchangeConditionList: map[int32]int32{},
+			ServerRewardNum:       cfgData.ServersReward,
+			RewardNum:             cfgData.Number,
+			ActivitiesId:          cfgData.ActivitiesId,
+		}
+		for idx := 0; idx < len(cfgData.ExchangeCondition); idx++ {
+			k, v := Str2Res(cfgData.ExchangeCondition[idx])
+			if k <= 0 || v <= 0 {
+				continue
+			}
+			tmpData.ExchangeConditionList[k] += v
+		}
+		for idx := 0; idx < len(cfgData.Reward); idx++ {
+			k, v := Str2Res(cfgData.Reward[idx])
+			if k <= 0 || v <= 0 {
+				continue
+			}
+			tmpData.RewardList = append(tmpData.RewardList,
+				&serverproto.KeyValueType{Key: k, Value: v})
+		}
+
+		ConvertActCollection[tmpData.Id] = tmpData
+	}
+
+	//ActivitieslikabilityCfg ActivitiesGiftCfg 好感度活动
+	for _, cfgData := range serverproto.ActivitiesGiftCfgLoader {
+		tmpData := &ConvertActLikabilityItemData{
+			ActivityId:       cfgData.Activityid,
+			LikabilityItemId: cfgData.Classitemid,
+		}
+		for idx := 0; idx < len(cfgData.Classcostaddlike); idx++ {
+			v1, v2, v3 := Str2Res_3(cfgData.Classcostaddlike[idx])
+			if v1 <= 0 {
+				continue
+			}
+			tmpData.LikabilityList = append(tmpData.LikabilityList,
+				&serverproto.KeyValueTypeList{Key: cfgData.Classitemid, ValueList: []int32{v1, v2, v3}})
+		}
+		if _, ok := ConvertActLikabilityItemList[cfgData.Activityid]; !ok {
+			ConvertActLikabilityItemList[cfgData.Activityid] = map[int32]*ConvertActLikabilityItemData{}
+		}
+		ConvertActLikabilityItemList[cfgData.Activityid][cfgData.Classitemid] = tmpData
+		//ConvertActLikabilityItem[cfgData.Classitemid] = tmpData
+	}
+	for _, cfgData := range serverproto.ActivitieslikabilityCfgLoader {
+		tmpData := &ConvertActLikabilityData{
+			ActivityId: cfgData.Activityid,
+			Level:      cfgData.Likelevel,
+			LikeValMax: cfgData.LikeMax,
+		}
+		for idx := 0; idx < len(cfgData.Conditionrewards); idx++ {
+			k, v1, v2 := Str2Res_3(cfgData.Conditionrewards[idx])
+			if k <= 0 {
+				continue
+			}
+			tmpData.RewardList = append(tmpData.RewardList, &serverproto.KeyValueTypeList{
+				Key:       k,
+				ValueList: []int32{v1, v2},
+			})
+		}
+		if _, ok := ConvertActLikabilityList[cfgData.Activityid]; !ok {
+			ConvertActLikabilityList[cfgData.Activityid] = map[int32]*ConvertActLikabilityData{}
+		}
+		ConvertActLikabilityList[cfgData.Activityid][cfgData.Likelevel] = tmpData
+	}
+
+	for _, cfgData := range serverproto.ActivitiesPetExchangeCfgLoader {
+		tmpData := &ConvertExchangeData{
+			Id:              cfgData.Id,
+			ActivitiesId:    cfgData.ActivitiesId,
+			RewardNum:       cfgData.Number,
+			ServerRewardNum: cfgData.ServersReward,
+			ActivitiesType:  cfgData.Type,
+			BroadCast:       cfgData.Broadcast,
+		}
+		if cfgData.ResetDay != 0 {
+			ResetData, resetOk := ConvertExchangeReset[cfgData.ActivitiesId]
+			if resetOk {
+				ResetData.Id = append(ResetData.Id, cfgData.Id)
+			} else {
+				convertResetData := &ResetIndexs{}
+				convertResetData.Id = append(convertResetData.Id, cfgData.Id)
+				ConvertExchangeReset[cfgData.ActivitiesId] = convertResetData
+			}
+		}
+
+		if cfgData.Type == int32(Exchange_Activity_Type_Pet) {
+			for _, condition := range cfgData.ExchangeCondition1 {
+				strList := strings.Split(condition, ":")
+				if len(strList) >= 5 {
+					condId, _ := Str2Num(strList[0])
+					id, _ := Str2Num(strList[1])
+					level, _ := Str2Num(strList[2])
+					skillLevel, _ := Str2Num(strList[3])
+					count, _ := Str2Num(strList[4])
+
+					cond := &ExchangePetCondition{
+						CondType:    Exchange_Type_Special,
+						ConditionId: int32(condId),
+						Id:          int32(id),
+						Level:       int32(level),
+						SkillLevel:  int32(skillLevel),
+						Count:       int32(count),
+					}
+					tmpData.ConditionPet = append(tmpData.ConditionPet, cond)
+				}
+			}
+			for _, condition := range cfgData.ExchangeCondition2 {
+				strList := strings.Split(condition, ":")
+				if len(strList) >= 5 {
+					condId, _ := Str2Num(strList[0])
+					id, _ := Str2Num(strList[1])
+					level, _ := Str2Num(strList[2])
+					skillLevel, _ := Str2Num(strList[3])
+					count, _ := Str2Num(strList[4])
+
+					cond := &ExchangePetCondition{
+						CondType:    Exchange_Type_Common,
+						ConditionId: int32(condId),
+						Id:          int32(id),
+						Level:       int32(level),
+						SkillLevel:  int32(skillLevel),
+						Count:       int32(count),
+					}
+					tmpData.ConditionPet = append(tmpData.ConditionPet, cond)
+				}
+			}
+		} else if cfgData.Type == int32(Exchange_Activity_Type_Card) {
+			for _, condition := range cfgData.ExchangeCondition1 {
+				strList := strings.Split(condition, ":")
+				if len(strList) >= 4 {
+					condId, _ := Str2Num(strList[0])
+					itemType, _ := Str2Num(strList[1])
+					itemId, _ := Str2Num(strList[2])
+					itemNum, _ := Str2Num(strList[3])
+					cond := &ExchangeCardCondition{
+						CondType:    Exchange_Type_Special,
+						ConditionId: int32(condId),
+						ItemType:    int32(itemType),
+						ItemId:      int32(itemId),
+						ItemCount:   int32(itemNum),
+					}
+					tmpData.ConditionCard = append(tmpData.ConditionCard, cond)
+				}
+			}
+			if len(cfgData.Scope) == len(cfgData.ExchangeCondition2) {
+				for i := 0; i < len(cfgData.ExchangeCondition2); i++ {
+					strList := strings.Split(cfgData.ExchangeCondition2[i], ":")
+					if len(strList) >= 4 {
+						condId, _ := Str2Num(strList[0])
+						itemType, _ := Str2Num(strList[1])
+						itemLevel, _ := Str2Num(strList[2])
+						itemCount, _ := Str2Num(strList[3])
+						itemQuality, _ := Str2Num(strList[4])
+						cond := &ExchangeCardCondition{
+							CondType:    Exchange_Type_Common,
+							ConditionId: int32(condId),
+							ItemType:    int32(itemType),
+							ItemLevel:   int32(itemLevel),
+							ItemCount:   int32(itemCount),
+							ItemQuality: int32(itemQuality),
+						}
+						cond.Scope = map[int32]int32{}
+
+						scopeList := strings.Split(cfgData.Scope[i], ":")
+						for _, data := range scopeList {
+							cardCfgId, _ := Str2Num(data)
+							cond.Scope[int32(cardCfgId)] = 1
+						}
+						tmpData.ConditionCard = append(tmpData.ConditionCard, cond)
+					}
+				}
+			} else {
+
+			}
+		}
+
+		for _, reward := range cfgData.Reward {
+			strList := strings.Split(reward, ":")
+			if len(strList) >= 2 {
+				petCfgId, _ := Str2Num(strList[0])
+				petCount, _ := Str2Num(strList[1])
+				tmpData.Reward = append(tmpData.Reward, &serverproto.KeyValueType{
+					Key:   int32(petCfgId),
+					Value: int32(petCount),
+				})
+			}
+		}
+
+		ConvertExchange[cfgData.Id] = tmpData
+	}
+}
+
+type HeadFrameAttr struct {
+	AttrList map[int32]int32
+}
+
+var ConvertHeadFrameAttr = map[int32]*HeadFrameAttr{}
+
+func convertHeadFrameCfg() {
+	for _, data := range serverproto.HeadFrameCfgLoader {
+		convert := &HeadFrameAttr{
+			AttrList: make(map[int32]int32),
+		}
+		for _, attr := range data.HeadFrameQuality {
+			strList := strings.Split(attr, ":")
+			if len(strList) >= 2 {
+				attrId, _ := Str2Num(strList[0])
+				attrValue, _ := Str2Num(strList[1])
+				convert.AttrList[int32(attrId)] += int32(attrValue)
+			}
+		}
+		ConvertHeadFrameAttr[data.HeadFrameId] = convert
+	}
+}
+
+// invitation
+type ConvertInvitationTask struct {
+	TaskId        uint32
+	RewardList    map[int32]int32
+	ConditionList map[int32][]int32
+	CompleteNum   int32
+}
+
+var ConvertInvitationTaskList = map[uint32]*ConvertInvitationTask{}
+var ConvertInvitationTaskTypeList = map[int32][]*ConvertInvitationTask{}
+
+func convertInvitationCfg() {
+	for _, cfgData := range serverproto.InvitationTaskCfgLoader {
+		tmpData := &ConvertInvitationTask{
+			TaskId:        uint32(cfgData.TaskId),
+			CompleteNum:   cfgData.CompleteNum,
+			RewardList:    map[int32]int32{},
+			ConditionList: map[int32][]int32{},
+		}
+		for idx := 0; idx < len(cfgData.TaskCondition); idx++ {
+			valueList := strings.Split(cfgData.TaskCondition[idx], ":")
+			if len(valueList) >= 2 {
+				taskType, _ := Str2Num(valueList[0])
+				tmpData.ConditionList[int32(taskType)] = append(tmpData.ConditionList[int32(taskType)], int32(taskType))
+				for i := 1; i < len(valueList); i++ {
+					taskValue, _ := Str2Num(valueList[i])
+					tmpData.ConditionList[int32(taskType)] = append(tmpData.ConditionList[int32(taskType)], int32(taskValue))
+				}
+			}
+		}
+		for idx := 0; idx < len(cfgData.Reward); idx++ {
+			key, val := Str2Res(cfgData.Reward[idx])
+			if key > 0 && val > 0 {
+				tmpData.RewardList[key] += val
+			}
+		}
+
+		for key := range tmpData.ConditionList {
+			ConvertInvitationTaskTypeList[key] = append(ConvertInvitationTaskTypeList[key], tmpData)
+		}
+
+		ConvertInvitationTaskList[tmpData.TaskId] = tmpData
+	}
+}
+
+type VipData struct {
+	VipRight  map[int32]int32
+	VipReward map[int32]int32
+}
+
+var ConvertVipRight = map[int32]*VipData{}
+
+const (
+	Vip_System_Levelup         = 1  //vip升级需要经验
+	Vip_System_Evil            = 2  //vip恶魔协会免费刷新次数(0开始恶魔协会刷新金色条目)
+	Vip_System_Online          = 3  //vip上线提示
+	Vip_System_PetAdvance      = 4  //宠物进阶消耗
+	Vip_System_CardReset       = 5  //卡片重置
+	Vip_System_PetDesolve      = 6  //宠物分解
+	Vip_System_SkillReset      = 7  //技能重置
+	Vip_System_GuildHunt       = 8  //公会狩猎次数
+	Vip_System_CardInsert      = 9  //一键插卡
+	Vip_System_ShopWeight      = 10 //商店权重
+	Vip_System_WorldBoss       = 11 //世界boss
+	Vip_System_Arena           = 12 //英灵殿
+	Vip_System_QuickBattle     = 13 //快速战斗次数
+	Vip_System_HungSilver      = 14 //挂机银币
+	Vip_System_HungExp         = 15 //挂机经验
+	Vip_System_HungPartnerExp  = 16 //挂机伙伴经验
+	Vip_System_HungSkillExp    = 17 //技能经验
+	Vip_System_HungExtraTime   = 18 //挂机额外时长
+	Vip_System_SignReward      = 19 //签到翻倍
+	Vip_System_WorldBoss_Count = 20 //世界boss次数
+)
+
+func convertVipCfg() {
+	for _, data := range serverproto.VipCfgLoader {
+		convertVip := &VipData{
+			VipRight:  make(map[int32]int32),
+			VipReward: make(map[int32]int32),
+		}
+		convertVip.VipRight[Vip_System_Levelup] = data.VipExp
+		convertVip.VipRight[Vip_System_Evil] = data.EvilFreeTimes
+		convertVip.VipRight[Vip_System_Online] = data.VipLogin
+		convertVip.VipRight[Vip_System_PetAdvance] = data.PetAdvance
+		convertVip.VipRight[Vip_System_CardReset] = data.CardReset
+		convertVip.VipRight[Vip_System_PetDesolve] = data.PetBreak
+		convertVip.VipRight[Vip_System_SkillReset] = data.SkillReset
+		convertVip.VipRight[Vip_System_GuildHunt] = data.GuildBossChallenge
+		convertVip.VipRight[Vip_System_CardInsert] = data.CardInsertion
+		convertVip.VipRight[Vip_System_ShopWeight] = data.ShopWeight
+		convertVip.VipRight[Vip_System_WorldBoss] = data.WorldBoss
+		convertVip.VipRight[Vip_System_Arena] = data.PvpReward
+		convertVip.VipRight[Vip_System_QuickBattle] = data.HangupTimes
+		convertVip.VipRight[Vip_System_HungSilver] = data.SilverUp
+		convertVip.VipRight[Vip_System_HungExp] = data.BaseExpUp
+		convertVip.VipRight[Vip_System_HungPartnerExp] = data.PartnerExpUp
+		convertVip.VipRight[Vip_System_HungSkillExp] = data.SkillExpUp
+		convertVip.VipRight[Vip_System_HungExtraTime] = data.HangupDuration
+		convertVip.VipRight[Vip_System_SignReward] = data.SignInRewardUp
+		convertVip.VipRight[Vip_System_WorldBoss_Count] = data.WorldBossCount
+
+		for _, data := range data.Reward {
+			strList := strings.Split(data, ":")
+			if len(strList) >= 2 {
+				key, _ := Str2Num(strList[0])
+				value, _ := Str2Num(strList[1])
+				convertVip.VipReward[int32(key)] += int32(value)
+			}
+		}
+		ConvertVipRight[data.Lv] = convertVip
+	}
+}
+
+type SummonCost struct {
+	ItemId       int32
+	ItemNum      int32
+	SourceId     int32
+	SourceNum    int32
+	DrawCount    map[int32]int32
+	ActivitiesId int32 //是否属于活动召唤数据
+	SummonType   int32 //召唤类型 1卡片 2宠物 3神器
+	Total        int32
+	//根据开服时间获取不同掉落配置
+	ServerDataList []*SummonCostByServerTime
+}
+
+// 相对开服时间天数
+func (this *SummonCost) GetDataByDiffDay(diffDay int32) *SummonCostByServerTime {
+	for idx := 0; idx < len(this.ServerDataList); idx++ {
+		if diffDay <= this.ServerDataList[idx].ServerTime {
+			return this.ServerDataList[idx]
+		}
+	}
+	if len(this.ServerDataList) > 0 {
+		return this.ServerDataList[len(this.ServerDataList)-1]
+	}
+	return nil
+}
+
+type SummonCostByServerTime struct {
+	Id          int32
+	ServerTime  int32 //相对开服时间天数
+	SummonType  int32 //召唤类型
+	SummonGroup int32 //召唤组
+	DropId      int32
+	DropId2     int32
+	ExtDropId   int32
+}
+
+type DrawTemplate struct {
+	ConfigId   int32
+	WeightItem int32
+	WeightGold int32
+	ExtraPoint int32
+	DrawItem   []*serverproto.KeyValueType
+}
+
+type DrawPool struct {
+	TotalWeightItem int32
+	TotalWeightGold int32
+	DrawTemplate    []*DrawTemplate
+}
+
+var ConvertSummonList = map[int32]*SummonCost{}
+var ConvertDrawTemplate = map[int32]*DrawPool{}
+
+const (
+	Draw_ResType_Item = 1
+	Draw_ResType_Gold = 2
+)
+
+func convertSummonCfg() {
+	for _, data := range serverproto.SummonServerCfgLoader {
+		convertData := &SummonCost{
+			DrawCount:    make(map[int32]int32),
+			ActivitiesId: data.ActivitiesId,
+			SummonType:   data.Type,
+			Total:        data.Total,
+		}
+
+		if len(data.Cost) >= 1 {
+			itemId, itemCount := Str2Res(data.Cost[0])
+			convertData.ItemId = itemId
+			convertData.ItemNum = itemCount
+		}
+		if len(data.Cost) >= 2 {
+			sourceId, sourceCount := Str2Res(data.Cost[1])
+			convertData.SourceId = sourceId
+			convertData.SourceNum = sourceCount
+		}
+
+		for _, count := range data.Method {
+			drawCount, _ := Str2Num(count)
+			convertData.DrawCount[int32(drawCount)] = 1
+		}
+
+		serverData := &SummonCostByServerTime{
+			Id:          data.Id,
+			ServerTime:  data.StartDay,
+			SummonType:  data.Type,
+			SummonGroup: data.SummoType,
+			DropId:      data.DropId,
+			DropId2:     data.DropId2,
+			ExtDropId:   data.ExtDropId,
+		}
+		//召唤组 只针对系统召唤(不包括活动)
+		if data.SummoType > 0 {
+			if summonData, ok := ConvertSummonList[data.SummoType]; ok {
+				summonData.ServerDataList = append(summonData.ServerDataList, serverData)
+			} else {
+				convertData.ServerDataList = append(convertData.ServerDataList, serverData)
+				ConvertSummonList[data.SummoType] = convertData
+			}
+			//无须读取导致之前没有赋值
+			if data.Total > 0 && len(data.Cost) > 0 {
+				ConvertSummonList[data.SummoType].Total = convertData.Total
+				ConvertSummonList[data.SummoType].SummonType = convertData.SummonType
+				ConvertSummonList[data.SummoType].ActivitiesId = convertData.ActivitiesId
+				ConvertSummonList[data.SummoType].DrawCount = convertData.DrawCount
+				ConvertSummonList[data.SummoType].ItemId = convertData.ItemId
+				ConvertSummonList[data.SummoType].ItemNum = convertData.ItemNum
+				ConvertSummonList[data.SummoType].SourceId = convertData.SourceId
+				ConvertSummonList[data.SummoType].SourceNum = convertData.SourceNum
+			}
+		} else {
+			convertData.ServerDataList = append(convertData.ServerDataList, serverData)
+			ConvertSummonList[data.Id] = convertData
+		}
+	}
+	for _, v := range ConvertSummonList {
+		sort.Slice(v.ServerDataList, func(i, j int) bool {
+			return v.ServerDataList[i].ServerTime < v.ServerDataList[j].ServerTime
+		})
+	}
+
+	for _, data := range serverproto.SummonTemplateCfgLoader {
+		drawPool, ok := ConvertDrawTemplate[data.CardType]
+		if !ok {
+			drawPool = &DrawPool{
+				TotalWeightItem: 0,
+				TotalWeightGold: 0,
+			}
+			ConvertDrawTemplate[data.CardType] = drawPool
+		}
+		if drawPool == nil {
+			//	panic()
+			return
+		}
+		drawPool.TotalWeightItem = drawPool.TotalWeightItem + data.Probability1
+		drawPool.TotalWeightGold = drawPool.TotalWeightGold + data.Probability2
+
+		//
+		drawTemplate := &DrawTemplate{
+			ConfigId:   data.Id,
+			WeightItem: drawPool.TotalWeightItem,
+			WeightGold: drawPool.TotalWeightGold,
+			ExtraPoint: data.SecurityNum,
+		}
+		if len(data.BlueNum) >= 1 {
+			strList := strings.Split(data.BlueNum[0], ":")
+			if len(strList) >= 2 {
+				key, _ := Str2Num(strList[0])
+				value, _ := Str2Num(strList[1])
+				drawTemplate.DrawItem = append(drawTemplate.DrawItem, &serverproto.KeyValueType{
+					Key:   int32(key),
+					Value: int32(value),
+				})
+			}
+		}
+		if len(data.PurpleNum) >= 1 {
+			strList := strings.Split(data.PurpleNum[0], ":")
+			if len(strList) >= 2 {
+				key, _ := Str2Num(strList[0])
+				value, _ := Str2Num(strList[1])
+				drawTemplate.DrawItem = append(drawTemplate.DrawItem, &serverproto.KeyValueType{
+					Key:   int32(key),
+					Value: int32(value),
+				})
+			}
+		}
+		if len(data.GoldNum) >= 1 {
+			strList := strings.Split(data.GoldNum[0], ":")
+			if len(strList) >= 2 {
+				key, _ := Str2Num(strList[0])
+				value, _ := Str2Num(strList[1])
+				drawTemplate.DrawItem = append(drawTemplate.DrawItem, &serverproto.KeyValueType{
+					Key:   int32(key),
+					Value: int32(value),
+				})
+			}
+		}
+
+		drawPool.DrawTemplate = append(drawPool.DrawTemplate, drawTemplate)
+	}
+}
+
+func GetDrawProbItem(drawType int32, resType int32) *DrawTemplate {
+	drawPool, ok := ConvertDrawTemplate[drawType]
+	if !ok {
+		return nil
+	}
+	var totalWeight int32 = 0
+	if resType == Draw_ResType_Item {
+		totalWeight = drawPool.TotalWeightItem
+	} else if resType == Draw_ResType_Gold {
+		totalWeight = drawPool.TotalWeightGold
+	}
+	randWeight := rand.Int31n(totalWeight)
+	for _, data := range drawPool.DrawTemplate {
+		target := data.WeightItem
+		if resType == Draw_ResType_Gold {
+			target = data.WeightGold
+		}
+		if target >= randWeight {
+			return data
+		}
+	}
+	return nil
+}
+
+type GiftBag struct {
+	GoodsId     int32
+	BagType     int32
+	Price       float32
+	Name        string
+	BuyReward   []*serverproto.KeyValueType
+	FirstReward []*serverproto.KeyValueType
+	ExtraReward []*serverproto.KeyValueType
+	LimitCount  int32
+	RmbTotalPay int32
+}
+
+type LimitBag struct {
+	GoodsId    int32
+	Price      float32
+	BeginTime  int64
+	EndTime    int64
+	LimitCount int32
+	Name       string
+	StartDay   int32
+	EndDay     int32
+	LimitType  int32
+	SeasonId   int32
+	BuyReward  []*serverproto.KeyValueType
+	ActivityId int32
+}
+
+type MonthCard struct {
+	GoodsId    int32
+	Price      float32
+	Duration   int32
+	Name       string
+	MailCfgId  int32
+	BuyReward  []*serverproto.KeyValueType
+	MailReward []*serverproto.KeyValueType
+}
+
+// 冲榜商店
+type RushShop struct {
+	GoodsId    int32
+	Activity   int32
+	Price      float32
+	Name       string
+	LimitCount int32
+	WorthRate  int32
+	BuyReward  []*serverproto.KeyValueType
+	Score      int32
+	Ticket     int32
+}
+
+var ConvertFreeBag = map[int32]*GiftBag{}
+var ConvertGiftBag = map[int32]*GiftBag{}
+var ConvertLimitGag = map[int32]*LimitBag{}
+var ConvertMonthCard = map[int32]*MonthCard{}
+
+var ConvertGuildBattle = map[int32]*RushShop{}
+
+// 卢恩冲榜商店
+var ConvertTowerShop = map[int32]*RushShop{}
+var ConvertArenaShop = map[int32]*RushShop{}
+var ConvertMapShop = map[int32]*RushShop{}
+var ConvertPetShop = map[int32]*RushShop{}
+var ConvertSkillShop = map[int32]*RushShop{}
+var ConvertIdolShop = map[int32]*RushShop{}
+
+func ConvertOldRedisRuneCfg() {
+	convertRuneCfg()
+}
+func convertRuneCfg() {
+	for _, data := range serverproto.RuneShopGiftsCfgLoader {
+		convertGift := &GiftBag{
+			GoodsId:     data.Id,
+			BagType:     data.Type,
+			Price:       data.RMB,
+			Name:        data.Name,
+			LimitCount:  data.RestrictedType,
+			RmbTotalPay: data.RmbTotalPay,
+		}
+		for _, reward := range data.Reward {
+			strList := strings.Split(reward, ":")
+			if len(strList) >= 2 {
+				key, _ := Str2Num(strList[0])
+				value, _ := Str2Num(strList[1])
+				convertGift.BuyReward = append(convertGift.BuyReward, &serverproto.KeyValueType{
+					Key:   int32(key),
+					Value: int32(value),
+				})
+			}
+		}
+		for _, first := range data.FirstBuyReward {
+			strList := strings.Split(first, ":")
+			if len(strList) >= 2 {
+				key, _ := Str2Num(strList[0])
+				value, _ := Str2Num(strList[1])
+				convertGift.FirstReward = append(convertGift.FirstReward, &serverproto.KeyValueType{
+					Key:   int32(key),
+					Value: int32(value),
+				})
+			}
+		}
+		for _, extra := range data.ExtraBuyReward {
+			strList := strings.Split(extra, ":")
+			if len(strList) >= 2 {
+				key, _ := Str2Num(strList[0])
+				value, _ := Str2Num(strList[1])
+				convertGift.ExtraReward = append(convertGift.ExtraReward, &serverproto.KeyValueType{
+					Key:   int32(key),
+					Value: int32(value),
+				})
+			}
+		}
+		ConvertGiftBag[data.Id] = convertGift
+		if data.RMB == 0 {
+			ConvertFreeBag[data.Id] = convertGift
+		}
+	}
+
+	for _, data := range serverproto.RuneShopLimitCfgLoader {
+		convertLimitBag := &LimitBag{
+			GoodsId:    data.Id,
+			Price:      data.RMB,
+			Name:       data.Name,
+			StartDay:   data.SellingBegin,
+			EndDay:     data.SellingDuration,
+			LimitCount: data.RestrictedType,
+			LimitType:  data.SellingType,
+			SeasonId:   data.SeasonId,
+			ActivityId: data.ActiveId,
+		}
+		for _, extra := range data.BuyReward {
+			strList := strings.Split(extra, ":")
+			if len(strList) >= 2 {
+				key, _ := Str2Num(strList[0])
+				value, _ := Str2Num(strList[1])
+				convertLimitBag.BuyReward = append(convertLimitBag.BuyReward, &serverproto.KeyValueType{
+					Key:   int32(key),
+					Value: int32(value),
+				})
+			}
+		}
+		loc := util.GetLoc()
+		if data.BeginTime != "" {
+			sTime, err1 := time.ParseInLocation(util.DATE_FORMAT, data.BeginTime, loc)
+			if err1 != nil {
+				util.PanicF("convertRune startTime err:%v", err1)
+			}
+			convertLimitBag.BeginTime = int64(sTime.Unix() * 1000)
+		}
+		if data.EndTime != "" {
+			cTime, err2 := time.ParseInLocation(util.DATE_FORMAT, data.EndTime, loc)
+			if err2 != nil {
+				util.PanicF("convertRune endTime err:%v", err2)
+			}
+			convertLimitBag.EndTime = int64(cTime.Unix() * 1000)
+		}
+		ConvertLimitGag[data.Id] = convertLimitBag
+	}
+
+	for _, data := range serverproto.RuneShopMonthCardCfgLoader {
+		monthCard := &MonthCard{
+			GoodsId:   data.Id,
+			Name:      data.Name,
+			Duration:  data.AddTime,
+			Price:     data.RMB,
+			MailCfgId: data.RewardMail,
+		}
+		for _, buyReward := range data.BuyRewardServer {
+			strList := strings.Split(buyReward, ":")
+			if len(strList) >= 2 {
+				key, _ := Str2Num(strList[0])
+				value, _ := Str2Num(strList[1])
+				monthCard.BuyReward = append(monthCard.BuyReward, &serverproto.KeyValueType{
+					Key:   int32(key),
+					Value: int32(value),
+				})
+			}
+		}
+		for _, dayReward := range data.DayReward {
+			strList := strings.Split(dayReward, ":")
+			if len(strList) >= 2 {
+				key, _ := Str2Num(strList[0])
+				value, _ := Str2Num(strList[1])
+				monthCard.MailReward = append(monthCard.MailReward, &serverproto.KeyValueType{
+					Key:   int32(key),
+					Value: int32(value),
+				})
+			}
+		}
+		ConvertMonthCard[data.Id] = monthCard
+	}
+
+	for _, data := range serverproto.RuneShopRankTowerCfgLoader {
+		towerShop := &RushShop{
+			GoodsId:    data.Id,
+			Name:       data.Name,
+			Price:      data.RMB,
+			Activity:   data.RankId,
+			LimitCount: data.RestrictedType,
+		}
+		for _, items := range data.Reward {
+			strList := strings.Split(items, ":")
+			if len(strList) >= 2 {
+				key, _ := Str2Num(strList[0])
+				value, _ := Str2Num(strList[1])
+				towerShop.BuyReward = append(towerShop.BuyReward, &serverproto.KeyValueType{
+					Key:   int32(key),
+					Value: int32(value),
+				})
+			}
+		}
+		ConvertTowerShop[data.Id] = towerShop
+	}
+
+	for _, data := range serverproto.RuneShopRankArenaCfgLoader {
+		arenaShop := &RushShop{
+			GoodsId:    data.Id,
+			Name:       data.Name,
+			Price:      data.RMB,
+			Activity:   data.RankId,
+			LimitCount: data.RestrictedType,
+		}
+		for _, items := range data.Reward {
+			strList := strings.Split(items, ":")
+			if len(strList) >= 2 {
+				key, _ := Str2Num(strList[0])
+				value, _ := Str2Num(strList[1])
+				arenaShop.BuyReward = append(arenaShop.BuyReward, &serverproto.KeyValueType{
+					Key:   int32(key),
+					Value: int32(value),
+				})
+			}
+		}
+		ConvertArenaShop[data.Id] = arenaShop
+	}
+
+	for _, data := range serverproto.RuneShopRankMapCfgLoader {
+		mapShop := &RushShop{
+			GoodsId:    data.Id,
+			Name:       data.Name,
+			Price:      data.RMB,
+			Activity:   data.RankId,
+			LimitCount: data.RestrictedType,
+			Score:      data.RewardScore,
+		}
+		for _, items := range data.SeverReward {
+			strList := strings.Split(items, ":")
+			if len(strList) >= 2 {
+				key, _ := Str2Num(strList[0])
+				value, _ := Str2Num(strList[1])
+				mapShop.BuyReward = append(mapShop.BuyReward, &serverproto.KeyValueType{
+					Key:   int32(key),
+					Value: int32(value),
+				})
+			}
+		}
+		ConvertMapShop[data.Id] = mapShop
+	}
+
+	//公会战商店
+	for _, data := range serverproto.RuneShopGuildBattleCfgLoader {
+		convertGift := &RushShop{
+			GoodsId:    data.Id,
+			Price:      data.RMB,
+			Name:       data.Name,
+			LimitCount: data.RestrictedType,
+		}
+		for _, reward := range data.Reward {
+			strList := strings.Split(reward, ":")
+			if len(strList) >= 2 {
+				key, _ := Str2Num(strList[0])
+				value, _ := Str2Num(strList[1])
+				convertGift.BuyReward = append(convertGift.BuyReward, &serverproto.KeyValueType{
+					Key:   int32(key),
+					Value: int32(value),
+				})
+			}
+		}
+		ConvertGuildBattle[data.Id] = convertGift
+	}
+
+	for _, data := range serverproto.RuneShopRankPetCfgLoader {
+		mapShop := &RushShop{
+			GoodsId:    data.Id,
+			Name:       data.Name,
+			Price:      data.RMB,
+			Activity:   data.RankId,
+			LimitCount: data.RestrictedType,
+			//	Score:      data.RewardScore,
+		}
+		for _, items := range data.Reward {
+			strList := strings.Split(items, ":")
+			if len(strList) >= 2 {
+				key, _ := Str2Num(strList[0])
+				value, _ := Str2Num(strList[1])
+				mapShop.BuyReward = append(mapShop.BuyReward, &serverproto.KeyValueType{
+					Key:   int32(key),
+					Value: int32(value),
+				})
+			}
+		}
+		ConvertPetShop[data.Id] = mapShop
+	}
+	for _, data := range serverproto.RuneShopRankSkillCfgLoader {
+		mapShop := &RushShop{
+			GoodsId:    data.Id,
+			Name:       data.Name,
+			Price:      data.RMB,
+			Activity:   data.RankId,
+			LimitCount: data.RestrictedType,
+			//	Score:      data.RewardScore,
+		}
+		for _, items := range data.Reward {
+			strList := strings.Split(items, ":")
+			if len(strList) >= 2 {
+				key, _ := Str2Num(strList[0])
+				value, _ := Str2Num(strList[1])
+				mapShop.BuyReward = append(mapShop.BuyReward, &serverproto.KeyValueType{
+					Key:   int32(key),
+					Value: int32(value),
+				})
+			}
+		}
+		ConvertSkillShop[data.Id] = mapShop
+	}
+
+	for _, data := range serverproto.RuneShopRankAidouluCfgLoader {
+		convertIdol := &RushShop{
+			GoodsId:    data.Id,
+			Name:       data.Name,
+			Price:      data.RMB,
+			Activity:   data.RankId,
+			LimitCount: data.RestrictedType,
+			Score:      data.IfRequite,
+			Ticket:     data.RewardScore,
+		}
+		for _, items := range data.SeverReward {
+			strList := strings.Split(items, ":")
+			if len(strList) >= 2 {
+				key, _ := Str2Num(strList[0])
+				value, _ := Str2Num(strList[1])
+				convertIdol.BuyReward = append(convertIdol.BuyReward, &serverproto.KeyValueType{
+					Key:   int32(key),
+					Value: int32(value),
+				})
+			}
+		}
+		ConvertIdolShop[data.Id] = convertIdol
+	}
+}
+
+const (
+	Rush_Type_Tower = 1
+	Rush_Type_Arena = 2
+	Rush_Type_Map   = 3
+	Rush_Type_Pet   = 4
+	Rush_Type_Skill = 5
+)
+
+const (
+	Rush_Reward_Type_FightCount = 1 //战斗次数,或者地图等级
+	Rush_Reward_Type_Rank       = 2 //排行版奖励
+)
+
+type RewardRank struct {
+	RankBegin  int32
+	RankEnd    int32
+	RankLevel  int32 //所在档位
+	RewardList []*serverproto.KeyValueType
+}
+
+type RankList struct {
+	RankRound int32
+	StartDay  int32
+	StartTime string
+	CloseDay  int32
+	CloseTime string
+	RestDay   int32
+	RestTime  string
+	Reward    []*RewardRank
+}
+
+type RewardBase struct {
+	RewardBegin int32
+	RewardEnd   int32
+	RewardLevel int32 //所在档位
+	//	RewardList  []*serverproto.KeyValueType
+	RewardList map[int32]int32
+}
+
+type RushBaseReward struct {
+	Reward []*RewardBase
+}
+type RankActivity struct {
+	RushActivity map[int32]*RankList
+	BaseReward   map[int32]*RushBaseReward
+}
+
+var DaySec int32 = 24 * 60 * 60
+var ConvertRushList = map[int32]*RankActivity{}
+
+func convertRushListCfg() {
+	for _, data := range serverproto.RushListCfgLoader {
+		_, ok := ConvertRushList[data.RankType]
+		if !ok {
+			rankActivity := &RankActivity{
+				RushActivity: map[int32]*RankList{},
+				BaseReward:   map[int32]*RushBaseReward{},
+			}
+			ConvertRushList[data.RankType] = rankActivity
+		}
+		_, ok2 := ConvertRushList[data.RankType].RushActivity[data.RankId]
+		if !ok2 {
+			rankList := &RankList{}
+			rankList.RankRound = data.RankId
+
+			rankList.StartDay = data.StartDay
+			rankList.StartTime = data.StartTime
+			rankList.CloseDay = data.CloseDay
+			rankList.CloseTime = data.CloseTime
+			rankList.RestDay = data.RestDay
+			rankList.RestTime = data.RestTime
+
+			ConvertRushList[data.RankType].RushActivity[data.RankId] = rankList
+		}
+
+		rush, ok3 := ConvertRushList[data.RankType].RushActivity[data.RankId]
+		if ok3 {
+			rewardRank := &RewardRank{
+				RankLevel: data.RankGrade,
+			}
+			if len(data.Rank) >= 1 {
+				strList := strings.Split(data.Rank[0], ":")
+				if len(strList) >= 2 {
+					begin, _ := Str2Num(strList[0])
+					end, _ := Str2Num(strList[1])
+					rewardRank.RankBegin = int32(begin)
+					rewardRank.RankEnd = int32(end)
+				}
+			}
+
+			for _, reward := range data.Reward {
+				strList := strings.Split(reward, ":")
+				if len(strList) >= 2 {
+					key, _ := Str2Num(strList[0])
+					value, _ := Str2Num(strList[1])
+					rewardRank.RewardList = append(rewardRank.RewardList, &serverproto.KeyValueType{
+						Key:   int32(key),
+						Value: int32(value),
+					})
+				}
+			}
+
+			rush.Reward = append(rush.Reward, rewardRank)
+		}
+	}
+
+	for _, data := range serverproto.RushListTargetCfgLoader {
+		_, ok := ConvertRushList[data.RankType]
+		if !ok {
+			continue
+		}
+		//没有这个活动。也不能加载这个活动对应的奖励
+		_, ok2 := ConvertRushList[data.RankType].RushActivity[data.RankId]
+		if !ok2 {
+			continue
+		}
+		_, ok3 := ConvertRushList[data.RankType].BaseReward[data.RankId]
+		if !ok3 {
+			rushBaseReward := &RushBaseReward{}
+			ConvertRushList[data.RankType].BaseReward[data.RankId] = rushBaseReward
+		}
+		rushReward, ok4 := ConvertRushList[data.RankType].BaseReward[data.RankId]
+		if ok4 {
+			rewardRank := &RewardBase{
+				RewardLevel: data.TargetGrade,
+				RewardList:  make(map[int32]int32),
+			}
+			if len(data.Rank) >= 1 {
+				strList := strings.Split(data.Rank[0], ":")
+				if len(strList) >= 2 {
+					begin, _ := Str2Num(strList[0])
+					end, _ := Str2Num(strList[1])
+					rewardRank.RewardBegin = int32(begin)
+					rewardRank.RewardEnd = int32(end)
+				}
+			}
+
+			for _, reward := range data.Reward {
+				strList := strings.Split(reward, ":")
+				if len(strList) >= 2 {
+					key, _ := Str2Num(strList[0])
+					value, _ := Str2Num(strList[1])
+					rewardRank.RewardList[int32(key)] = int32(value)
+					/*
+						rewardRank.RewardList = append(rewardRank.RewardList, &serverproto.KeyValueType{
+							Key:   int32(key),
+							Value: int32(value),
+						})
+					*/
+				}
+			}
+			rushReward.Reward = append(rushReward.Reward, rewardRank)
+		}
+	}
+}
+
+func GetRushActivityTimeStamp(deltaDay int32, deltaTime string) uint64 {
+	loc := util.GetLoc()
+	startUpTime := service.GetServiceStartupTime()
+	if startUpTime < 0 {
+		util.ErrorF("[convertRushListCfg] data error:%v")
+		return 0
+	}
+	startServer := time.Unix(int64(startUpTime/1000), 0).In(loc).Format(util.DATE_FORMAT1)
+	startUpDayStr := util.GetDayByTimeStr1(startServer)
+
+	rushBegin := util.GetTimeByStr(startUpDayStr.Format(util.DATE_FORMAT1) + " " + deltaTime)
+	rushStart := time.Unix(rushBegin.Unix()+int64(deltaDay-1)*int64(DaySec), 0).In(loc)
+
+	return uint64(rushStart.UnixNano() / 1e6)
+}
+
+func GetCurrentRushActivity(RankType int32, RushRound int32) *RankList {
+	rushList, ok := ConvertRushList[RankType]
+	if !ok {
+		return nil
+	}
+
+	nowTime := util.GetCurrentTime()
+	for _, data := range rushList.RushActivity {
+		if RushRound != 0 {
+			if data.RankRound != RushRound {
+				continue
+			}
+		}
+		rushBegin := GetRushActivityTimeStamp(data.StartDay, data.StartTime)
+		rewardEnd := GetRushActivityTimeStamp(data.RestDay, data.RestTime)
+		if rushBegin <= nowTime && nowTime <= rewardEnd {
+			return data
+		}
+	}
+	return nil
+}
+
+func GetNextRushActivity(RankType int32, RushRound int32) *RankList {
+	rushList, ok := ConvertRushList[RankType]
+	if !ok {
+		return nil
+	}
+	nowTime := util.GetCurrentTime()
+	for i := RushRound; i <= int32(len(rushList.RushActivity)); i++ {
+		data, ok := rushList.RushActivity[i]
+		if !ok {
+			continue
+		}
+		if nowTime < GetRushActivityTimeStamp(data.StartDay, data.StartTime) {
+			return data
+		}
+	}
+	return nil
+}
+func GetRushActivityByRound(RankType int32, RushRound int32) *RankList {
+	rushList, ok := ConvertRushList[RankType]
+	if !ok {
+		return nil
+	}
+	for _, data := range rushList.RushActivity {
+		if data.RankRound != RushRound {
+			continue
+		}
+		return data
+	}
+	return nil
+}
+
+func GetRushActivityBaseReward(RushRound int32, RankType int32, score int32, addItemList map[int32]int32) int32 {
+	rushList, ok := ConvertRushList[RankType]
+	if !ok {
+		return 0
+	}
+	rewards, ok2 := rushList.BaseReward[RushRound]
+	if !ok2 {
+		return 0
+	}
+	for _, data := range rewards.Reward {
+		if data.RewardEnd != 0 && data.RewardBegin <= score && score <= data.RewardEnd ||
+			data.RewardEnd == 0 && data.RewardBegin <= score {
+			for key, value := range data.RewardList {
+				addItemList[key] += value
+			}
+			return data.RewardLevel
+		}
+	}
+	return 0
+}
+
+type LevelUpMaterial struct {
+	Materials map[int32]int32
+	AddAttr   map[int32]int32
+	Level     int32
+}
+
+type KeepSakeData struct {
+	KeepSakeId    int32
+	LevelData     map[int32]*LevelUpMaterial
+	LevelDataList []*LevelUpMaterial
+	Job           []int32
+	KeepLevel     int32
+	MaxLevel      int32
+	AllMaterials  map[int32]int32
+}
+
+var ConvertMaterialToKeepSake = map[int32]int32{}
+var ConvertKeepSake = map[int32]*KeepSakeData{}
+
+func convertKeepSakeCfg() {
+	for _, data := range serverproto.KeepSakeCfgLoader {
+		convert := &KeepSakeData{
+			KeepSakeId: data.Id,
+			KeepLevel:  data.CollectionLevel,
+		}
+		convert.LevelData = make(map[int32]*LevelUpMaterial)
+		convert.AllMaterials = make(map[int32]int32)
+
+		for _, jobs := range data.Job {
+			jobId, _ := Str2Num(jobs)
+			convert.Job = append(convert.Job, int32(jobId))
+		}
+		//等級1
+		levelUpMaterial1 := &LevelUpMaterial{}
+		levelUpMaterial1.Materials = make(map[int32]int32)
+		levelUpMaterial1.AddAttr = make(map[int32]int32)
+		for _, material1 := range data.MaterialLevel1 {
+			material := strings.Split(material1, ":")
+			if len(material) >= 2 {
+				itemId, _ := Str2Num(material[0])
+				itemCount, _ := Str2Num(material[1])
+				levelUpMaterial1.Materials[int32(itemId)] = int32(itemCount)
+				ConvertMaterialToKeepSake[int32(itemId)] = data.Id
+				convert.MaxLevel = 1
+				convert.AllMaterials[int32(itemId)] = 1
+			}
+		}
+		for _, attr1 := range data.AddAttrLevel1 {
+			addAttr := strings.Split(attr1, ":")
+			if len(addAttr) >= 2 {
+				attrKey, _ := Str2Num(addAttr[0])
+				attrValue, _ := Str2Num(addAttr[1])
+				levelUpMaterial1.AddAttr[int32(attrKey)] = int32(attrValue)
+			}
+		}
+		levelUpMaterial1.Level = 1
+		convert.LevelData[1] = levelUpMaterial1
+		convert.LevelDataList = append(convert.LevelDataList, levelUpMaterial1)
+
+		//等級2
+		levelUpMaterial2 := &LevelUpMaterial{}
+		levelUpMaterial2.Materials = make(map[int32]int32)
+		levelUpMaterial2.AddAttr = make(map[int32]int32)
+		for _, material2 := range data.MaterialLevel2 {
+			material := strings.Split(material2, ":")
+			if len(material) >= 2 {
+				itemId, _ := Str2Num(material[0])
+				itemCount, _ := Str2Num(material[1])
+				levelUpMaterial2.Materials[int32(itemId)] = int32(itemCount)
+				ConvertMaterialToKeepSake[int32(itemId)] = data.Id
+				convert.MaxLevel = 2
+				convert.AllMaterials[int32(itemId)] = 1
+			}
+		}
+		for _, attr2 := range data.AddAttrLevel2 {
+			addAttr := strings.Split(attr2, ":")
+			if len(addAttr) >= 2 {
+				attrKey, _ := Str2Num(addAttr[0])
+				attrValue, _ := Str2Num(addAttr[1])
+				levelUpMaterial2.AddAttr[int32(attrKey)] = int32(attrValue)
+			}
+		}
+		levelUpMaterial2.Level = 2
+		convert.LevelData[2] = levelUpMaterial2
+		convert.LevelDataList = append(convert.LevelDataList, levelUpMaterial2)
+
+		levelUpMaterial3 := &LevelUpMaterial{}
+		levelUpMaterial3.Materials = make(map[int32]int32)
+		levelUpMaterial3.AddAttr = make(map[int32]int32)
+		for _, material3 := range data.MaterialLevel3 {
+			material := strings.Split(material3, ":")
+			if len(material) >= 2 {
+				itemId, _ := Str2Num(material[0])
+				itemCount, _ := Str2Num(material[1])
+				levelUpMaterial3.Materials[int32(itemId)] = int32(itemCount)
+				ConvertMaterialToKeepSake[int32(itemId)] = data.Id
+				convert.MaxLevel = 3
+				convert.AllMaterials[int32(itemId)] = 1
+			}
+		}
+		for _, attr3 := range data.AddAttrLevel3 {
+			attr := strings.Split(attr3, ":")
+			if len(attr) >= 2 {
+				attrKey, _ := Str2Num(attr[0])
+				attrValue, _ := Str2Num(attr[1])
+				levelUpMaterial3.AddAttr[int32(attrKey)] = int32(attrValue)
+			}
+		}
+		levelUpMaterial3.Level = 3
+		convert.LevelData[3] = levelUpMaterial3
+		convert.LevelDataList = append(convert.LevelDataList, levelUpMaterial3)
+
+		levelUpMaterial4 := &LevelUpMaterial{}
+		levelUpMaterial4.Materials = make(map[int32]int32)
+		levelUpMaterial4.AddAttr = make(map[int32]int32)
+		for _, material4 := range data.MaterialLevel4 {
+			material := strings.Split(material4, ":")
+			if len(material) >= 2 {
+				itemId, _ := Str2Num(material[0])
+				itemCount, _ := Str2Num(material[1])
+				levelUpMaterial4.Materials[int32(itemId)] = int32(itemCount)
+				ConvertMaterialToKeepSake[int32(itemId)] = data.Id
+				convert.MaxLevel = 4
+				convert.AllMaterials[int32(itemId)] = 1
+			}
+		}
+		for _, attr4 := range data.AddAttrLevel4 {
+			attr := strings.Split(attr4, ":")
+			if len(attr) >= 2 {
+				attrKey, _ := Str2Num(attr[0])
+				attrValue, _ := Str2Num(attr[1])
+				levelUpMaterial4.AddAttr[int32(attrKey)] = int32(attrValue)
+			}
+		}
+		levelUpMaterial4.Level = 4
+		convert.LevelData[4] = levelUpMaterial4
+		convert.LevelDataList = append(convert.LevelDataList, levelUpMaterial4)
+
+		levelUpMaterial5 := &LevelUpMaterial{}
+		levelUpMaterial5.Materials = make(map[int32]int32)
+		levelUpMaterial5.AddAttr = make(map[int32]int32)
+		for _, material5 := range data.MaterialLevel5 {
+			material := strings.Split(material5, ":")
+			if len(material) >= 2 {
+				itemId, _ := Str2Num(material[0])
+				itemCount, _ := Str2Num(material[1])
+				levelUpMaterial5.Materials[int32(itemId)] = int32(itemCount)
+				ConvertMaterialToKeepSake[int32(itemId)] = data.Id
+				convert.MaxLevel = 5
+				convert.AllMaterials[int32(itemId)] = 1
+			}
+		}
+		for _, attr5 := range data.AddAttrLevel5 {
+			attr := strings.Split(attr5, ":")
+			if len(attr) >= 2 {
+				attrKey, _ := Str2Num(attr[0])
+				attrValue, _ := Str2Num(attr[1])
+				levelUpMaterial5.AddAttr[int32(attrKey)] = int32(attrValue)
+			}
+		}
+		levelUpMaterial5.Level = 5
+		convert.LevelData[5] = levelUpMaterial5
+		convert.LevelDataList = append(convert.LevelDataList, levelUpMaterial5)
+
+		ConvertKeepSake[data.Id] = convert
+	}
+	for _, val := range ConvertKeepSake {
+		sort.Slice(val.LevelDataList, func(i, j int) bool {
+			return val.LevelDataList[i].Level < val.LevelDataList[j].Level
+		})
+	}
+}
+
+func GetMaxKeepSakeLevel(keepSakeId int32) int32 {
+	data, ok := ConvertKeepSake[keepSakeId]
+	if !ok {
+		return 0
+	}
+	return data.MaxLevel
+}
+
+type SuitCondition struct {
+	cardType int32
+	cardLvl  int32
+	cardCnt  int32
+}
+
+func (this SuitCondition) GetKey() int32 {
+	return this.cardType
+}
+
+func (this SuitCondition) GetLvl() int32 {
+	return this.cardLvl
+}
+
+func (this SuitCondition) GetCnt() int32 {
+	return this.cardCnt
+}
+
+type CardSuitData struct {
+	id               int32
+	suits            []*serverproto.KeyValueType
+	suitTerm         []*SuitCondition
+	SuitTotalCardNum map[int32]int32 //需要同种类型卡片的数量
+}
+
+func (this CardSuitData) GetConditions() []*SuitCondition {
+	return this.suitTerm
+}
+
+func (this CardSuitData) GetSuits() []*serverproto.KeyValueType {
+	return this.suits
+}
+
+func (this CardSuitData) Id() int32 {
+	return this.id
+}
+
+var DbCardSuitData = map[int32]*CardSuitData{}
+var ConvertCardSuit []*CardSuitData
+
+func convertCardSuitNewCfg() {
+	for _, v := range serverproto.CardSuitNewCfgLoader {
+		data := &CardSuitData{
+			SuitTotalCardNum: map[int32]int32{},
+		}
+		data.id = v.Id
+		for _, v1 := range v.Suit1 {
+			k, val := Str2Res(v1)
+			data.suits = append(data.suits, &serverproto.KeyValueType{Key: k, Value: val})
+		}
+		for _, v2 := range v.TriggerConditions {
+			t, l, c := Str2Res_3(v2)
+			data.SuitTotalCardNum[t] += c
+			data.suitTerm = append(data.suitTerm, &SuitCondition{t, l, c})
+		}
+		DbCardSuitData[v.Id] = data
+
+		ConvertCardSuit = append(ConvertCardSuit, data)
+	}
+	sort.Slice(ConvertCardSuit, func(i, j int) bool {
+		return ConvertCardSuit[i].id > ConvertCardSuit[j].id
+	})
+}
+
+type TmapMaterial map[int32]int32
+type StFashionUp struct {
+	level    int32
+	quality  int32 // 品质 1:绿色 2:蓝色 3:紫色 4:金色 5:红色
+	upAttr   int32
+	material TmapMaterial
+}
+
+func (this StFashionUp) Material() TmapMaterial {
+	return this.material
+}
+
+func (this StFashionUp) UpAttr() int32 {
+	return this.upAttr
+}
+
+func CreateKey16Offset(left, right int32) int32 {
+	// 偏移16位作为 左值
+	return left<<16 | right
+}
+
+var DbFashionLevelUp = make(map[int32]*StFashionUp)
+
+func CreateData(dbDate []string) *StFashionUp {
+	data := &StFashionUp{material: make(TmapMaterial)}
+	for _, v1 := range dbDate {
+		id, cnt := Str2Res(v1)
+		data.material[id] = cnt
+	}
+	return data
+}
+
+func covertFashionLevelUpCfg() {
+	for _, v := range serverproto.FashionLevelUpLoader {
+		data1 := CreateData(v.UpMaterial1)
+		data1.level = v.Level
+		data1.quality = 1
+		data1.upAttr = v.UpAttribute
+		DbFashionLevelUp[CreateKey16Offset(data1.level, data1.quality)] = data1
+
+		data2 := CreateData(v.UpMaterial2)
+		data2.level = v.Level
+		data2.quality = 2
+		data2.upAttr = v.UpAttribute
+		DbFashionLevelUp[CreateKey16Offset(data2.level, data2.quality)] = data2
+
+		data3 := CreateData(v.UpMaterial3)
+		data3.level = v.Level
+		data3.quality = 3
+		data3.upAttr = v.UpAttribute
+		DbFashionLevelUp[CreateKey16Offset(data3.level, data3.quality)] = data3
+
+		data4 := CreateData(v.UpMaterial4)
+		data4.level = v.Level
+		data4.quality = 4
+		data4.upAttr = v.UpAttribute
+		DbFashionLevelUp[CreateKey16Offset(data4.level, data4.quality)] = data4
+
+		data5 := CreateData(v.UpMaterial5)
+		data5.level = v.Level
+		data5.quality = 5
+		data5.upAttr = v.UpAttribute
+		DbFashionLevelUp[CreateKey16Offset(data5.level, data5.quality)] = data5
+	}
+}
+
+type StFashionRandom struct {
+	id     int32
+	roleid int32
+	atrid  []int32
+	//refreshCost map[int32]int32
+}
+
+func (this StFashionRandom) GetAtrid() []int32 {
+	return this.atrid[:]
+}
+
+func (this StFashionRandom) GetRoleid() int32 {
+	return this.roleid
+}
+
+var DbFashionResetAttrCost = []map[int32]int32{}
+var DbFashionRandom = []*StFashionRandom{} // make(map[int32]*StFashionRandom)
+func convertFashionRandomCfg() {
+	for _, v := range serverproto.FashionRandomLoader {
+		//id, cnt := Str2Res(v.RefreshCost)
+		data := &StFashionRandom{v.ID, int32(v.RoleId), []int32{}}
+		for _, jobs := range v.AtrId {
+			attrId, _ := Str2Num(jobs)
+			data.atrid = append(data.atrid, int32(attrId))
+		}
+		DbFashionRandom = append(DbFashionRandom, data)
+		//DbFashionRandom[data.roleid] = &data
+	}
+	var globalDb = serverproto.GlobalCfgLoader[int32(serverproto.GlobalType_Global_Fashion_Attr)]
+	if globalDb == nil {
+		panic("299 全局配置错误")
+	}
+	items := strings.Split(globalDb.SVal, ";")
+	for _, i2 := range items {
+		id, cnt := Str2Res(i2)
+		DbFashionResetAttrCost = append(DbFashionResetAttrCost, map[int32]int32{id: cnt})
+	}
+
+}
+
+type StSuitLvlAttr struct {
+	lvl  int32
+	attr *serverproto.KeyValueType
+}
+
+// 套装表
+type StFashionSuit struct {
+	suitId     int32
+	fashionIds []int32
+	mapAttr    map[int32][]*serverproto.KeyValueType
+}
+
+func (this StFashionSuit) Id() int32 {
+	return this.suitId
+}
+
+func (this StFashionSuit) GetIds() []int32 {
+	return this.fashionIds[:]
+}
+
+func (this StFashionSuit) GetMapAttr() map[int32][]*serverproto.KeyValueType {
+	return this.mapAttr
+}
+
+var DbFashionSuit = make(map[int32]*StFashionSuit)
+var DbFashionSuitID = make(map[int32][]*StFashionSuit)
+
+func converFashionSuitCfg() {
+	for _, v := range serverproto.FashionSuitCfgLoader {
+		data := &StFashionSuit{mapAttr: make(map[int32][]*serverproto.KeyValueType)}
+		if len(v.LevelCondition) != len(v.Attribute) {
+			panic("FashionSuitCfg 属性配置和等级配置不对应")
+		}
+		for i, val := range v.LevelCondition {
+			lvl, _ := strconv.Atoi(val)
+			resList := strings.Split(v.Attribute[i], ":")
+			for _, i3 := range resList {
+				values := strings.Split(i3, "-")
+				if len(values) < 2 {
+					continue
+				}
+				id, _ := Str2Num(values[0])
+				attrVar, _ := Str2Num(values[1])
+				data.mapAttr[int32(lvl)] = append(data.mapAttr[int32(lvl)], &serverproto.KeyValueType{Key: int32(id), Value: int32(attrVar)})
+			}
+		}
+		for _, i2 := range v.FashionId {
+			value, _ := Str2Num(i2)
+			data.fashionIds = append(data.fashionIds, int32(value))
+		}
+		data.suitId = v.SuitId
+		DbFashionSuit[v.SuitId] = data
+	}
+
+	for _, v := range serverproto.FashionSuitCfgLoader {
+		data := &StFashionSuit{mapAttr: make(map[int32][]*serverproto.KeyValueType)}
+		if len(v.LevelCondition) != len(v.Attribute) {
+			panic("FashionSuitCfg 属性配置和等级配置不对应")
+		}
+		for i, val := range v.LevelCondition {
+			lvl, _ := strconv.Atoi(val)
+			resList := strings.Split(v.Attribute[i], ":")
+			for _, i3 := range resList {
+				values := strings.Split(i3, "-")
+				if len(values) < 2 {
+					continue
+				}
+				id, _ := Str2Num(values[0])
+				attrVar, _ := Str2Num(values[1])
+				data.mapAttr[int32(lvl)] = append(data.mapAttr[int32(lvl)], &serverproto.KeyValueType{Key: int32(id), Value: int32(attrVar)})
+			}
+		}
+		for _, i2 := range v.FashionId {
+			value, _ := Str2Num(i2)
+			data.fashionIds = append(data.fashionIds, int32(value))
+		}
+		data.suitId = v.SuitId
+		DbFashionSuit[v.SuitId] = data
+
+		for _, id := range data.fashionIds {
+			DbFashionSuitID[id] = append(DbFashionSuitID[id], data)
+		}
+	}
+
+}
+
+// //////////////////////////////////卢恩战令////////////////////
+type StRuneShopExplore struct {
+	round           int32
+	goldExp         int32
+	missionExp      int32
+	missonExpUp     int32
+	rmb             float32
+	sellingBegin    int32
+	startTime       string
+	sellingDuration int32
+	closeTime       string
+	maxlvrewads     map[int32]int32
+	expCost         int32
+}
+
+func (this StRuneShopExplore) StartTime() string {
+	return this.startTime
+}
+
+func (this StRuneShopExplore) CloseTime() string {
+	return this.closeTime
+}
+
+func (this StRuneShopExplore) SellingBegin() int32 {
+	return this.sellingBegin
+}
+
+func (this StRuneShopExplore) SellingDuration() int32 {
+	return this.sellingDuration
+}
+
+func (this StRuneShopExplore) GetRound() int32 {
+	return this.round
+}
+
+func (this StRuneShopExplore) GetRMB() float32 {
+	return this.rmb
+}
+
+func (this StRuneShopExplore) GoldScale() int32 {
+	return this.goldExp
+}
+
+func (this StRuneShopExplore) MissionScale() int32 {
+	return this.missionExp
+}
+
+type GuildWarReward struct {
+	Rank             int32
+	MemberRewardList []*serverproto.KeyValueType
+	LeaderRewardList []*serverproto.KeyValueType
+}
+
+type GuildMvpReward struct {
+	Rank       int32
+	RewardList []*serverproto.KeyValueType
+}
+
+type GuildBattleBuff struct {
+	BuffId  int32
+	BuyData map[int32]*serverproto.KeyValueType
+}
+
+var GuildBattleRankReward = map[int32]*GuildWarReward{}
+var GuildBattleScoreMvpReward = map[int32]*GuildMvpReward{}
+var GuildBattleKillMvpReward = map[int32]*GuildMvpReward{}
+
+var GuildBattleBuffList = map[int32]*GuildBattleBuff{}
+
+func convertGuildWarCfg() {
+	for _, data := range serverproto.GuildWarAgainstCfgLoader {
+		rankReward := &GuildWarReward{
+			Rank: data.Ranking,
+		}
+		for _, deacon := range data.DeaconReword {
+			items := strings.Split(deacon, ":")
+			if len(items) >= 2 {
+				itemId, _ := Str2Num(items[0])
+				itemCount, _ := Str2Num(items[1])
+
+				rankReward.LeaderRewardList = append(rankReward.LeaderRewardList, &serverproto.KeyValueType{
+					Key:   int32(itemId),
+					Value: int32(itemCount),
+				})
+			}
+		}
+		for _, member := range data.GuildsmenReword {
+			items := strings.Split(member, ":")
+			if len(items) >= 2 {
+				itemId, _ := Str2Num(items[0])
+				itemCount, _ := Str2Num(items[1])
+
+				rankReward.MemberRewardList = append(rankReward.MemberRewardList, &serverproto.KeyValueType{
+					Key:   int32(itemId),
+					Value: int32(itemCount),
+				})
+			}
+		}
+		GuildBattleRankReward[data.Ranking] = rankReward
+
+		scoreMvpReward := &GuildMvpReward{
+			Rank: data.PointMvp,
+		}
+		for _, score := range data.PointMvpReword {
+			items := strings.Split(score, ":")
+			if len(items) >= 2 {
+				itemId, _ := Str2Num(items[0])
+				itemCount, _ := Str2Num(items[1])
+
+				scoreMvpReward.RewardList = append(scoreMvpReward.RewardList, &serverproto.KeyValueType{
+					Key:   int32(itemId),
+					Value: int32(itemCount),
+				})
+			}
+		}
+		GuildBattleScoreMvpReward[data.PointMvp] = scoreMvpReward
+
+		killerMvpReward := &GuildMvpReward{
+			Rank: data.PointMvp,
+		}
+		for _, killer := range data.KillerMvpReword {
+			items := strings.Split(killer, ":")
+			if len(items) >= 2 {
+				itemId, _ := Str2Num(items[0])
+				itemCount, _ := Str2Num(items[1])
+
+				killerMvpReward.RewardList = append(killerMvpReward.RewardList, &serverproto.KeyValueType{
+					Key:   int32(itemId),
+					Value: int32(itemCount),
+				})
+			}
+		}
+		GuildBattleKillMvpReward[data.KillerMvp] = killerMvpReward
+	}
+
+	for _, data := range serverproto.GuildWarBuffCfgLoader {
+		convertData := &GuildBattleBuff{
+			BuffId:  data.Id,
+			BuyData: map[int32]*serverproto.KeyValueType{},
+		}
+		for idx, buffData := range data.Price {
+			resType, count := Str2Res(buffData)
+			convertData.BuyData[int32(idx+1)] = &serverproto.KeyValueType{
+				Key:   resType,
+				Value: count,
+			}
+		}
+		GuildBattleBuffList[data.Id] = convertData
+	}
+}
+
+const (
+	GuildBattle_Reward_GuildMember = 1
+	GuildBattle_Reward_GuildLeader = 2
+	GuildBattle_Reward_ScoreMvp    = 3
+	GuildBattle_Reward_KillerMvp   = 4
+)
+
+func GetGuildBattleReward(rewardType int32, rank int32, rewardList []*serverproto.KeyValueType) {
+	if rewardType == GuildBattle_Reward_GuildMember ||
+		rewardType == GuildBattle_Reward_GuildLeader {
+		data, ok := GuildBattleRankReward[rank]
+		if !ok {
+			return
+		}
+		if rewardType == GuildBattle_Reward_GuildMember {
+			for _, items := range data.MemberRewardList {
+				rewardList = append(rewardList, items)
+			}
+		} else if rewardType == GuildBattle_Reward_GuildLeader {
+			for _, items := range data.LeaderRewardList {
+				rewardList = append(rewardList, items)
+			}
+		}
+	} else if rewardType == GuildBattle_Reward_ScoreMvp {
+		data, ok := GuildBattleScoreMvpReward[rank]
+		if !ok {
+			return
+		}
+		for _, items := range data.RewardList {
+			rewardList = append(rewardList, items)
+		}
+	} else if rewardType == GuildBattle_Reward_KillerMvp {
+		data, ok := GuildBattleKillMvpReward[rank]
+		if !ok {
+			return
+		}
+		for _, items := range data.RewardList {
+			rewardList = append(rewardList, items)
+		}
+	}
+}
+
+func (this StRuneShopExplore) MissionUp() int32 {
+	return this.missonExpUp
+}
+
+func (this StRuneShopExplore) ExpCost() int32 {
+	return this.expCost
+}
+
+func (this StRuneShopExplore) MaxAward() map[int32]int32 {
+	return this.maxlvrewads
+}
+
+// var DbRuneShopExplore = make(map[int32]*StRuneShopExplore)
+var DbRuneShopExplore = []*StRuneShopExplore{}
+
+func GetRuneExploreDataByRound(round int32) *StRuneShopExplore {
+	for _, explore := range DbRuneShopExplore {
+		if explore.GetRound() != round {
+			continue
+		}
+		return explore
+	}
+	return nil
+}
+
+func convertRuneShopExploreCfg() {
+	for _, v := range serverproto.RuneShopExploreCfgLoader {
+		data := &StRuneShopExplore{round: v.Round, rmb: v.RMB, sellingBegin: v.SellingBegin,
+			sellingDuration: v.SellingDuration, expCost: v.ExpCost, maxlvrewads: make(map[int32]int32),
+			startTime: v.StartTime, closeTime: v.CloseTime}
+		_, val1 := Str2Res(v.GoldExp)
+		data.goldExp = val1
+		_, val2 := Str2Res(v.MissionExp)
+		data.missionExp = val2
+		up, _ := Str2Num(v.MissonExpUp)
+		data.missonExpUp = data.missionExp * int32(up) / 100
+		for _, i2 := range v.MaxLvRewad {
+			id, cnt := Str2Res(i2)
+			data.maxlvrewads[id] = cnt
+			//data.maxlvrewads = append(data.maxlvrewads, &serverproto.KeyValueType{Key: id,Value: cnt})
+		}
+		DbRuneShopExplore = append(DbRuneShopExplore, data)
+		//DbRuneShopExplore[data.round] = data
+	}
+	sort.Slice(DbRuneShopExplore, func(i, j int) bool {
+		return DbRuneShopExplore[i].GetRound() < DbRuneShopExplore[j].GetRound()
+	})
+}
+
+type StRuneShopExploreReward struct {
+	lv          int32
+	round       int32
+	exp         int32
+	rewards     map[int32]int32
+	cashRewards map[int32]int32
+}
+
+func (this StRuneShopExploreReward) Exp() int32 {
+	return this.exp
+}
+
+func (this StRuneShopExploreReward) Lvl() int32 {
+	return this.lv
+}
+
+func (this StRuneShopExploreReward) GetAward() map[int32]int32 {
+	return this.rewards
+}
+
+func (this StRuneShopExploreReward) GetCashAward() map[int32]int32 {
+	return this.cashRewards
+}
+
+type StMaxData struct {
+	MaxLvl int32
+	MaxExp int32
+}
+
+var DbRuneShopExploreMax = make(map[int32]*StMaxData)
+var DbRuneShopExploreReward = make(map[int32]*StRuneShopExploreReward)
+
+func convertRuneShopExploreRewardCfg() {
+	for _, v := range serverproto.RuneShopExploreRewardCfgLoader {
+		data := &StRuneShopExploreReward{lv: v.Lv, round: v.ActiveRound, exp: v.Exp,
+			rewards: make(map[int32]int32), cashRewards: make(map[int32]int32)}
+		for _, i2 := range v.Reward {
+			id, cnt := Str2Res(i2)
+			data.rewards[id] = cnt
+			//data.rewards = append(data.rewards, &serverproto.KeyValueType{Key: id,Value: cnt})
+		}
+		for _, i3 := range v.CashReward {
+			id, cnt := Str2Res(i3)
+			data.cashRewards[id] = cnt
+			//data.cashRewards = append(data.cashRewards, &serverproto.KeyValueType{Key: id,Value: cnt})
+		}
+		DbRuneShopExploreReward[data.round<<16|data.lv] = data
+		max, ok := DbRuneShopExploreMax[data.round]
+		if !ok {
+			max = &StMaxData{}
+		}
+		max.MaxExp += v.Exp
+		if v.Lv > max.MaxLvl {
+			max.MaxLvl = v.Lv
+		}
+		DbRuneShopExploreMax[data.round] = max
+	}
+}
+
+// 在线累计时间奖励处理
+type OnlineRewardDayInfoST struct {
+	Day             int32
+	Id              int32
+	RewardToTalTime int32                       //累计时间 s
+	RewardList      []*serverproto.KeyValueType //奖励列表
+	RewardCostCoin  int32                       //直接获取奖励消耗金币
+}
+
+var ConvertOnlineRewardList = map[int32][]*OnlineRewardDayInfoST{} //[Day,DayInfo]
+var ConvertOnlineRewardMaxDay int32 = 0
+
+func convertOnlineTimeRewardCfg() {
+	ConvertOnlineRewardList = map[int32][]*OnlineRewardDayInfoST{}
+	for _, cfgData := range serverproto.OnlineRewardsCfgLoader {
+		rewardInfo := &OnlineRewardDayInfoST{
+			Id:              cfgData.Id,
+			Day:             cfgData.Day,
+			RewardToTalTime: cfgData.Time,
+			RewardCostCoin:  cfgData.SpeedUp,
+		}
+		for idx := 0; idx < len(cfgData.Rewards); idx++ {
+			k, v := Str2Res(cfgData.Rewards[idx])
+			if k <= 0 || v <= 0 {
+				continue
+			}
+			rewardInfo.RewardList = append(rewardInfo.RewardList, &serverproto.KeyValueType{
+				Key:   k,
+				Value: v,
+			})
+		}
+		ConvertOnlineRewardList[cfgData.Day] = append(ConvertOnlineRewardList[cfgData.Day], rewardInfo)
+		if ConvertOnlineRewardMaxDay < cfgData.Day {
+			ConvertOnlineRewardMaxDay = cfgData.Day
+		}
+	}
+	//sort
+	for key := range ConvertOnlineRewardList {
+		sort.Slice(ConvertOnlineRewardList[key], func(i, j int) bool {
+			return ConvertOnlineRewardList[key][i].Id <
+				ConvertOnlineRewardList[key][j].Id
+		})
+	}
+}
+
+type StQualityData struct {
+	ItemId       int32
+	QualityPoint int32
+	MaxUse       int32
+}
+
+var DBQualityFruit = map[int32]*StQualityData{}
+
+func convertQualityFruitCfg() {
+	gload, ok := serverproto.GlobalCfgLoader[int32(serverproto.GlobalType_Global_Quality_Fruit_Item)]
+	if !ok {
+		panic("GlobalCfg quality Fruit error")
+		return
+	}
+	lis := strings.Split(gload.SVal, ";")
+	for _, li := range lis {
+		id, value, maxCnt := Str2Res_3(li)
+		DBQualityFruit[id] = &StQualityData{id, value, maxCnt}
+	}
+}
+
+type StJobChangeData struct {
+	Id          int32
+	JobType     int32
+	JobStage    int32 //职业阶数
+	BeforeJobId int32
+	JobBranch   int32
+	AfterJobIds []int32  // 下一阶职业
+	ChangeCond  []string // 转职条件
+	ItemCosts   map[int32]int32
+	Skills      []int32 // 默认装备技能
+	NewSkills   []int32
+}
+
+func (this *StJobChangeData) HasNextJob(jobId int32) bool {
+	for _, v := range this.AfterJobIds {
+		if jobId != v {
+			continue
+		}
+		return true
+	}
+	return false
+}
+
+func (this *StJobChangeData) converRoleData(data *serverproto.JobCfg) *StJobChangeData {
+	this.ItemCosts = make(map[int32]int32)
+	this.Id = data.Id
+	this.JobType = data.JobType
+	this.JobStage = data.JobStage
+	//this.ChangeCond = data.ChangeCond
+	this.BeforeJobId = data.BeforeJobId
+	this.JobBranch = data.JobBranch
+	for _, v := range data.AfterJobId {
+		num, err := Str2Num(v)
+		if err != nil {
+			continue
+		}
+		this.AfterJobIds = append(this.AfterJobIds, int32(num))
+	}
+	for _, v := range data.ItemCost {
+		id, cnt := Str2Res(v)
+		if id <= 0 || cnt <= 0 {
+			continue
+		}
+		this.ItemCosts[id] = cnt //append(this.ItemCosts, &serverproto.KeyValueType{Key:id,Value: cnt})
+	}
+	for _, id := range data.SkillIds {
+		skillId, _ := Str2Num(id)
+		this.Skills = append(this.Skills, int32(skillId))
+	}
+	for _, s := range data.ChangeCond {
+		if len(s) <= 0 {
+			continue
+		}
+		this.ChangeCond = append(this.ChangeCond, s)
+	}
+	return this
+}
+
+func (this *StJobChangeData) converParterData(data *serverproto.ParterCfg) *StJobChangeData {
+	this.ItemCosts = make(map[int32]int32)
+	this.Id = data.ParterId
+	this.JobType = data.JobType
+	this.JobStage = data.JobStage
+	//this.ChangeCond = data.ChangeCond
+	this.BeforeJobId = data.BeforeJobId
+	this.JobBranch = data.JobBranch
+	for _, v := range data.AfterJobId {
+		num, err := Str2Num(v)
+		if err != nil {
+			continue
+		}
+		this.AfterJobIds = append(this.AfterJobIds, int32(num))
+	}
+	for _, v := range data.ItemCost {
+		id, cnt := Str2Res(v)
+		if id <= 0 || cnt <= 0 {
+			continue
+		}
+		this.ItemCosts[id] = cnt //append(this.ItemCosts, &serverproto.KeyValueType{Key:id,Value: cnt})
+	}
+	for _, id := range data.SkillIds {
+		skillId, _ := Str2Res(id)
+		this.Skills = append(this.Skills, int32(skillId))
+	}
+	for _, s := range data.ChangeCond {
+		if len(s) <= 0 {
+			continue
+		}
+		this.ChangeCond = append(this.ChangeCond, s)
+	}
+	return this
+}
+
+var DBJobChange = map[int32]*StJobChangeData{}
+
+// 生成职业表Id
+func GetJobChangeKey(isRoleMain bool, jobId int32) int32 {
+	key := jobId
+	// 伙伴职业Id与主角职业id相同, 伙伴Id增加10倍区分主角职业Id
+	if !isRoleMain {
+		key *= 10
+	}
+	return key
+}
+
+func convertJobChangeCfg() {
+	// 临时记录, key值对应技能表中数据,根据组合参数索引出技能Id,保存到DBJobChange结构中
+	var tmp = map[int32]*StJobChangeData{}
+	var tmpky = map[int32][]*serverproto.KeyValueType{}
+	// 生成技能表位移key值 偏移24位:是否主角数据, 偏移16位:职业类型  偏移8位:技能阶数 后八位:分支值
+	calcKey := func(jobtype, jobstate, JobBranch int32, roleMain bool) int32 {
+		first := int32(1) // 是否是主角表
+		if roleMain == true {
+			first = 0
+		}
+		return first<<24 | jobtype<<16 | jobstate<<8 | JobBranch
+	}
+	//----------------------------------------------------------------------
+	for i, cfg := range serverproto.JobCfgLoader {
+		db := new(StJobChangeData).converRoleData(cfg)
+		DBJobChange[GetJobChangeKey(true, i)] = db
+		tmp[calcKey(db.JobType, db.JobStage, db.JobBranch, true)] = db
+	}
+
+	for i, cfg := range serverproto.ParterCfgLoader {
+		db := new(StJobChangeData).converParterData(cfg)
+		DBJobChange[GetJobChangeKey(false, i)] = db
+		tmp[calcKey(db.JobType, db.JobStage, db.JobBranch, false)] = db
+	}
+	// 从主角技能表解析出 对应的职业
+	for _, skilldb := range serverproto.SkillTreeCfgLoader {
+		key := calcKey(skilldb.JobType, skilldb.JobStage, skilldb.JobBranch, true) // 位移生成 key值
+		if _, ok := tmp[key]; ok {
+			tmpky[key] = append(tmpky[key], &serverproto.KeyValueType{Key: skilldb.SkillId, Value: skilldb.OpenLevel})
+			sort.Slice(tmpky[key], func(i, j int) bool { return tmpky[key][i].Value < tmpky[key][j].Value })
+		} else {
+			panic("技能解析出错")
+		}
+	}
+	// 从伙伴技能表解析出 对应的职业
+	for _, skilldb := range serverproto.ParterSkillTreeCfgLoader {
+		key := calcKey(skilldb.JobType, skilldb.JobStage, skilldb.JobBranch, false)
+		if _, ok := tmp[key]; ok {
+			tmpky[key] = append(tmpky[key], &serverproto.KeyValueType{Key: skilldb.SkillId, Value: skilldb.OpenLevel})
+			sort.Slice(tmpky[key], func(i, j int) bool { return tmpky[key][i].Value < tmpky[key][j].Value })
+		} else {
+			panic("伙伴技能解析出错")
+		}
+	}
+	// 根据等级排序写入对应职业
+	for i, types := range tmpky {
+		data, _ := tmp[i]
+		for _, valueType := range types {
+			data.NewSkills = append(data.NewSkills, valueType.Key)
+		}
+	}
+}
+
+type ConvertSysRewardData struct {
+	TowerLevel int32
+	RewardList map[int32]int32
+}
+
+var ConvertSysRewardList []*ConvertSysRewardData
+
+func convertSysRewardCfg() {
+	for key, val := range serverproto.SysRewardLoader {
+		convertData := &ConvertSysRewardData{
+			TowerLevel: key,
+			RewardList: map[int32]int32{},
+		}
+		for idx := 0; idx < len(val.Reward); idx++ {
+			rewardId, _ := Str2Num(val.Reward[idx])
+			if rewardId > 0 {
+				convertData.RewardList[int32(rewardId)]++
+			}
+		}
+		ConvertSysRewardList = append(ConvertSysRewardList, convertData)
+	}
+	sort.Slice(ConvertSysRewardList, func(i, j int) bool {
+		return ConvertSysRewardList[i].TowerLevel < ConvertSysRewardList[j].TowerLevel
+	})
+}
+
+// 占星
+type ConvertDevine struct {
+	StarCount   int32
+	NormalRate  int32
+	SpecialRate int32
+	ItemCost    map[int32]int32
+	GoldCost    map[int32]int32
+	RewardList  map[int32]int32
+	LuckyTicket int32
+	TicketCount int32
+	ScoreId     int32
+	ScorePoint  int32
+	BroadCast   int32
+}
+
+var ConvertCompetitionDevine = map[int32]*ConvertDevine{}
+
+func convertCompetitionDevineCfg() {
+	for _, data := range serverproto.CompetitionDevineCfgLoader {
+		convertData := &ConvertDevine{
+			StarCount:   data.NowLightNum,
+			NormalRate:  data.Probability,
+			SpecialRate: data.PledgeProbability,
+		}
+		convertData.ItemCost = make(map[int32]int32)
+		convertData.GoldCost = make(map[int32]int32)
+		convertData.RewardList = make(map[int32]int32)
+
+		for _, item := range data.ItemPrice {
+			itemId, itemNum := Str2Res(item)
+			if itemId != 0 && itemNum != 0 {
+				convertData.ItemCost[itemId] += itemNum
+			}
+		}
+
+		for _, item := range data.GoldPrice {
+			itemId, itemNum := Str2Res(item)
+			if itemId != 0 && itemNum != 0 {
+				convertData.GoldCost[itemId] += itemNum
+			}
+		}
+		for _, item := range data.Rewards {
+			itemId, itemNum := Str2Res(item)
+			if itemId != 0 && itemNum != 0 {
+				convertData.RewardList[itemId] += itemNum
+			}
+		}
+
+		if len(data.LuckyPrice) > 0 {
+			luckId, luckyNum := Str2Res(data.LuckyPrice[0])
+			convertData.LuckyTicket = luckId
+			convertData.TicketCount = luckyNum
+		}
+		if len(data.Point) > 0 {
+			scoreId, scoreNum := Str2Res(data.Point[0])
+			convertData.ScoreId = scoreId
+			convertData.ScorePoint = scoreNum
+		}
+		convertData.BroadCast = data.IfBroadcast
+		ConvertCompetitionDevine[data.NowLightNum] = convertData
+	}
+}
+
+var ConvertYuanHangTrail = map[int32]*ConvertYuanHangTrialData{}
+var ConvertYuanHangMaxShipLevel int32 = 0
+
+type ConvertYuanHangTrialData struct {
+	ShipLevel                 int32                       //type id
+	Duration                  int32                       //s
+	ConsumeSpecialItemList    map[int32]int32             //特殊道具消耗
+	ConsumeNormalList         map[int32]int32             //普通金币消耗
+	ShipRefreshSuccessRate    int                         //100 rate
+	ShipRefreshTopLevelCost   []*serverproto.KeyValueType //直接升级到顶级消耗(根据列表优先级消耗)
+	ShipRewardList            map[int32]int32
+	BeAttackNum               int32 //被攻击丢失奖励次数
+	BeAttackScore             int32
+	BeAttackRewardList        map[int32]int32
+	BeAttackRewardListSlice   []*serverproto.KeyValueType
+	BeAttackLoseItemList      map[int32]int32 //被打劫损失奖励
+	BeAttackLoseItemListSlice []*serverproto.KeyValueType
+}
+
+func (this *ConvertYuanHangTrialData) RefreshShip(force bool) (int32, serverproto.ErrorCode) {
+	if force {
+		return ConvertYuanHangMaxShipLevel, serverproto.ErrorCode_ERROR_OK
+	}
+	if this.ShipRefreshSuccessRate <= 0 {
+		return this.ShipLevel, serverproto.ErrorCode_ERROR_CROSS_YUANHANGTRIAL_TOP_SHIPLEVEL
+	}
+
+	randNum := rand.Intn(100) + 1
+	if randNum <= this.ShipRefreshSuccessRate {
+		return this.ShipLevel + 1, serverproto.ErrorCode_ERROR_OK
+	}
+
+	return this.ShipLevel, serverproto.ErrorCode_ERROR_CROSS_YUANHANGTRIAL_REFRESH_FAILED
+}
+
+func convertYuanHangTrailCfg() {
+	for _, data := range serverproto.TransportCfgLoader {
+		trailItem := &ConvertYuanHangTrialData{
+			ShipLevel:              data.ShipLevel,
+			Duration:               data.Duration * 60,
+			ShipRefreshSuccessRate: int(data.Probability),
+			BeAttackNum:            data.RobberyTimes,
+			BeAttackScore:          data.RobberyFraction,
+
+			ConsumeSpecialItemList: map[int32]int32{},
+			ConsumeNormalList:      map[int32]int32{},
+			ShipRewardList:         map[int32]int32{},
+			BeAttackRewardList:     map[int32]int32{},
+			BeAttackLoseItemList:   map[int32]int32{},
+		}
+		if len(data.Consume) >= 1 {
+			k, v := Str2Res(data.Consume[0])
+			if k > 0 && v > 0 {
+				trailItem.ConsumeSpecialItemList[k] += v
+			}
+		}
+		if len(data.Consume) >= 2 {
+			k, v := Str2Res(data.Consume[1])
+			if k > 0 && v > 0 {
+				trailItem.ConsumeNormalList[k] += v
+			}
+		}
+		trailItem.ShipRefreshTopLevelCost = Str2ResSliceList(data.TopLevel)
+		Str2ResMapList(data.TranspoertReward, trailItem.ShipRewardList)
+		Str2ResMapList(data.RobberyReward, trailItem.BeAttackRewardList)
+		for _, str := range data.RobberyReward {
+			k, v := Str2Res(str)
+			if k > 0 && v > 0 {
+				trailItem.BeAttackRewardListSlice = append(trailItem.BeAttackRewardListSlice,
+					&serverproto.KeyValueType{Key: k, Value: v})
+			}
+		}
+		Str2ResMapList(data.RobberyLose, trailItem.BeAttackLoseItemList)
+		for _, str := range data.RobberyLose {
+			k, v := Str2Res(str)
+			if k > 0 && v > 0 {
+				trailItem.BeAttackLoseItemListSlice = append(trailItem.BeAttackLoseItemListSlice,
+					&serverproto.KeyValueType{Key: k, Value: v})
+			}
+		}
+
+		ConvertYuanHangTrail[trailItem.ShipLevel] = trailItem
+
+		if data.ShipLevel > ConvertYuanHangMaxShipLevel {
+			ConvertYuanHangMaxShipLevel = data.ShipLevel
+		}
+	}
+}
+
+type StDbKingTaskData struct {
+	TaskIds      []int32 `csv:"TaskIds"`      //成长任务
+	DailyTaskIds []int32 `csv:"DailyTaskIds"` //今日挑战
+	ActivitiesId int32   `csv:"ActivitiesId"` //活动Id
+}
+
+var ConvertKingTask = map[int32]map[int32]*StDbKingTaskData{}
+
+func GetKingTaskData(AvtivitiesId, day int32) *StDbKingTaskData {
+	avt, ok := ConvertKingTask[AvtivitiesId]
+	if !ok {
+		return nil
+	}
+	data, ok := avt[day]
+	if !ok {
+		return nil
+	}
+	return data
+}
+func convertActivitiesKingTaskCfg() {
+	for _, data := range serverproto.ActivitiesKingTaskCfgLoader {
+		taskItem := &StDbKingTaskData{ActivitiesId: data.ActivitiesId}
+		for _, id := range data.TaskIds {
+			taskId, err := Str2Num(id)
+			if err != nil {
+				panic("convertActivitiesKingTask  TaskIds err")
+			}
+			taskItem.TaskIds = append(taskItem.TaskIds, int32(taskId))
+		}
+		for _, id := range data.DailyTaskIds {
+			taskId, err := Str2Num(id)
+			if err != nil {
+				panic("convertActivitiesKingTask DailyTaskIds err")
+			}
+			taskItem.DailyTaskIds = append(taskItem.DailyTaskIds, int32(taskId))
+		}
+		maptmp, ok := ConvertKingTask[data.ActivitiesId]
+		if !ok {
+			maptmp = make(map[int32]*StDbKingTaskData)
+			ConvertKingTask[data.ActivitiesId] = maptmp
+		}
+		maptmp[data.Day] = taskItem
+	}
+}
+
+type MatchSection struct {
+	LevelRank    int32
+	LeftSection  int32
+	RightSection int32
+}
+
+func (this *MatchSection) InSection(val int32) bool {
+	if this.LeftSection <= val &&
+		this.RightSection >= val {
+		return true
+	}
+	return false
+}
+
+type TopTowerData struct {
+	SelfRankSection *MatchSection
+	MatchSection    []*MatchSection
+}
+type TopTowerRewardData struct {
+	ForceWinCostList map[int32]int32
+	Idx              int32
+	WinRewardList    map[int32]int32
+}
+
+var ConvertTopTowerDataList []*TopTowerData
+var ConvertTopTowerRewardList []*TopTowerRewardData
+
+func convertTopTowerCfg() {
+	for _, data := range serverproto.TopTowerCfgLevelLoader {
+		rankInfo := &TopTowerData{}
+		rankInfo.SelfRankSection = convertTopTowerSectionCfg(data.RankId, 0)
+
+		rankInfo.MatchSection = append(rankInfo.MatchSection,
+			convertTopTowerSectionCfg(data.LevelRank1, 1),
+			convertTopTowerSectionCfg(data.LevelRank2, 2),
+			convertTopTowerSectionCfg(data.LevelRank3, 3),
+			convertTopTowerSectionCfg(data.LevelRank4, 4),
+			convertTopTowerSectionCfg(data.LevelRank5, 5),
+			convertTopTowerSectionCfg(data.LevelRank6, 6),
+			convertTopTowerSectionCfg(data.LevelRank7, 7),
+			convertTopTowerSectionCfg(data.LevelRank8, 8),
+			convertTopTowerSectionCfg(data.LevelRank9, 9),
+			convertTopTowerSectionCfg(data.LevelRank10, 10))
+
+		ConvertTopTowerDataList = append(ConvertTopTowerDataList, rankInfo)
+	}
+
+	for _, data := range serverproto.TopTowerCfgRewardLoader {
+		rewardData := &TopTowerRewardData{
+			Idx:              data.LevelId,
+			ForceWinCostList: map[int32]int32{},
+			WinRewardList:    map[int32]int32{},
+		}
+		Str2ResMapList(data.BuyRoadCost, rewardData.ForceWinCostList)
+		Str2ResMapList(data.RewardItems, rewardData.WinRewardList)
+		ConvertTopTowerRewardList = append(ConvertTopTowerRewardList, rewardData)
+	}
+}
+func convertTopTowerSectionCfg(sectionStr []string, idx int32) *MatchSection {
+	tmpMatchSection := &MatchSection{}
+	v1, _ := Str2Num(sectionStr[0])
+	v2, _ := Str2Num(sectionStr[1])
+	tmpMatchSection.LeftSection = int32(v1)
+	tmpMatchSection.RightSection = int32(v2)
+	tmpMatchSection.LevelRank = idx
+	return tmpMatchSection
+}
+
+type StDbHeadData struct {
+	HeadId       int32
+	HeadType     int32
+	ContinueTime int32 // 时长 (小时)
+	BRestTask    bool  // 每日重置任务
+	Attr         []*serverproto.KeyValueType
+	Condition    map[int32][]int32 // 任务条件
+	ActivateItem map[int32]int32   // 激活消耗
+
+}
+
+var DbHeadData = map[int32]*StDbHeadData{}
+
+func convertHeadDataCfg() {
+	for _, cfg := range serverproto.DesignationCfgLoader {
+		taskItem := &StDbHeadData{HeadId: cfg.ID, HeadType: cfg.Type, Condition: map[int32][]int32{}, ActivateItem: map[int32]int32{}, ContinueTime: cfg.Time}
+		if cfg.RefreshDaily > 0 {
+			taskItem.BRestTask = true
+		} else {
+			taskItem.BRestTask = false
+		}
+		for _, s := range cfg.Attribute {
+			k, v := Str2Res(s)
+			taskItem.Attr = append(taskItem.Attr, &serverproto.KeyValueType{Key: k, Value: v})
+		}
+		for _, v := range cfg.TaskCondition {
+			valueList := strings.Split(v, ":")
+			if len(valueList) >= 2 {
+				taskType, _ := Str2Num(valueList[0])
+				taskItem.Condition[int32(taskType)] = append(taskItem.Condition[int32(taskType)], int32(taskType))
+				for i := 1; i < len(valueList); i++ {
+					taskValue, _ := Str2Num(valueList[i])
+					taskItem.Condition[int32(taskType)] = append(taskItem.Condition[int32(taskType)], int32(taskValue))
+				}
+			}
+		}
+		for _, s := range cfg.TaskConditionItem {
+			if len(s) <= 0 {
+				continue
+			}
+			k, v := Str2Res(s)
+			taskItem.ActivateItem[k] = v
+		}
+		DbHeadData[taskItem.HeadId] = taskItem
+	}
+}
+
+type DemonRewardData struct {
+	Level    int32
+	StageMax uint64
+	StageMin uint64
+	Reward   []*serverproto.KeyValueType
+}
+
+type GuildDemonData struct {
+	ConfigId          int32
+	DemonId           int32
+	DemonLevel        int32
+	StartDay          int32
+	EndDay            int32
+	WeekDay           int32
+	ChallengeCount    int32 //免费战斗次数
+	BuyChallengeCount int32 //最大购买次数
+	ChallengePrice    map[int32]*serverproto.KeyValueType
+	StartTime         string
+	RewardStage       []*DemonRewardData
+	BaseReward        map[int32]int32
+}
+
+type GuildWeekDemonData struct {
+	DemonData []*GuildDemonData
+}
+
+var ConvertGuildDemon = map[int32]*GuildWeekDemonData{}
+
+func convertGuildDemonCfg() {
+	for _, data := range serverproto.GuildDemonCfgLoader {
+		if data.Id == 0 {
+			continue
+		}
+		_, ok := ConvertGuildDemon[data.WeekDay]
+		if !ok {
+			ConvertGuildDemon[data.WeekDay] = &GuildWeekDemonData{}
+		}
+
+		convertData := &GuildDemonData{
+			ConfigId:          data.Id,
+			DemonId:           data.Id,
+			WeekDay:           data.WeekDay,
+			ChallengeCount:    data.FreeChallenge,
+			BuyChallengeCount: data.ChallengeTimes,
+			StartTime:         data.SummonTime,
+			DemonLevel:        data.BossLevel,
+			BaseReward:        map[int32]int32{},
+		}
+
+		if len(data.BossLvCycle) >= 1 {
+			start, end := Str2Res(data.BossLvCycle[0])
+			convertData.StartDay = int32(start)
+			convertData.EndDay = int32(end)
+		}
+
+		damageList := strings.Split(data.DamageSegment, ";")
+		if len(damageList) != len(data.DamageReward)+1 {
+			util.InfoF("convertGuildDemonCfg boss config reward bossId:%v error: %v %v", data.Id, len(damageList), len(data.DamageReward))
+			panic("convertGuildDemonCfg boss config reward error")
+		}
+
+		for i := 0; i < len(data.DamageReward); i++ {
+			convertReward := &DemonRewardData{}
+
+			damage := strings.Split(damageList[i+1], ":")
+			if len(damage) >= 2 {
+				level, _ := Str2Num(damage[0])
+				minDamage, _ := Str2NumU64(damage[1])
+				maxDamage, _ := Str2NumU64(damage[2])
+				convertReward.StageMax = maxDamage
+				convertReward.StageMin = minDamage
+				convertReward.Level = int32(level)
+			}
+
+			//todo 解析伤害区间
+			//解析奖励
+			reward := strings.Split(data.DamageReward[i], ":")
+			if len(reward) >= 2 {
+				itemId, itemNum := Str2Res(data.DamageReward[i])
+				convertReward.Reward = append(convertReward.Reward, &serverproto.KeyValueType{
+					Key:   itemId,
+					Value: itemNum,
+				})
+			}
+			convertData.RewardStage = append(convertData.RewardStage, convertReward)
+		}
+		convertData.ChallengePrice = make(map[int32]*serverproto.KeyValueType)
+
+		for _, baseReward := range data.ChallengeReward {
+			itemId, itemNum := Str2Res(baseReward)
+			convertData.BaseReward[itemId] += itemNum
+		}
+
+		startIndex := int32(1)
+		for _, priceData := range data.ChallengePrice {
+			itemId, itemNum := Str2Res(priceData)
+			convertData.ChallengePrice[startIndex] = &serverproto.KeyValueType{
+				Key:   itemId,
+				Value: itemNum,
+			}
+			startIndex++
+		}
+
+		ConvertGuildDemon[data.WeekDay].DemonData = append(ConvertGuildDemon[data.WeekDay].DemonData, convertData)
+		//util.InfoF("[GetDemonInfo] get guildDemon config [%v] data:%v", int32(data.Id), convertData)
+	}
+}
+
+func GetDemonDataByConfigId(configId int32) *GuildDemonData {
+	for _, weekDemon := range ConvertGuildDemon {
+		for _, demon := range weekDemon.DemonData {
+			if configId == demon.DemonId {
+				return demon
+			}
+		}
+	}
+	return nil
+}
+
+// (int32, int32):(bossId, bossLevel)
+func GetDemonInfo(weekDay int32, curTime time.Time) (*GuildDemonData, int32) {
+	curWeekDay := weekDay
+	//	curTime := util.GetCurrentTimeNow()
+	if curTime.Hour() <= 4 {
+		curWeekDay--
+		if curWeekDay == 0 {
+			curWeekDay = 7
+		}
+	}
+
+	startUpTime := service.GetServiceStartupTime()
+	curServerDay := util.GetDurationDay2(startUpTime, uint64(util.GetTimeMilliseconds()))
+
+	guildDemon, ok := ConvertGuildDemon[int32(curWeekDay)]
+	if !ok {
+		util.InfoF("[GetDemonInfo] get guildDemon config [%v] ", int32(curWeekDay))
+		return nil, 0
+	}
+	demonData := &GuildDemonData{}
+	maxStartDay := int32(0)
+	for _, data := range guildDemon.DemonData {
+		if data.StartDay <= curServerDay && curServerDay <= data.EndDay {
+			return data, curServerDay
+		}
+		if maxStartDay <= data.StartDay {
+			maxStartDay = data.StartDay
+			demonData = data
+		}
+	}
+
+	return demonData, curServerDay
+}
+
+// nextRefreshTime下次刷新的时间戳,取前一天的相关数据
+func GetDemonInfoByTimeStamp(nextRefreshTime uint64) *GuildDemonData {
+	nowTime := util.GetTimeByUint64(nextRefreshTime - 24*3600*1000)
+	curWeekDay := nowTime.Weekday()
+	if curWeekDay == 0 {
+		curWeekDay = 7
+	}
+
+	if nowTime.Hour() <= 4 {
+		curWeekDay--
+		if curWeekDay == 0 {
+			curWeekDay = 7
+		}
+	}
+	startUpTime := service.GetServiceStartupTime()
+	curServerDay := util.GetDurationDay1(startUpTime, nextRefreshTime)
+
+	guildDemon, ok := ConvertGuildDemon[int32(curWeekDay)]
+	if !ok {
+		util.InfoF("[GetDemonInfo] get guildDemon config [%v] ", int32(curWeekDay))
+		return nil
+	}
+	demonData := &GuildDemonData{}
+	maxStartDay := int32(0)
+	for _, data := range guildDemon.DemonData {
+		if data.StartDay <= curServerDay && curServerDay <= data.EndDay {
+			return data
+		}
+		if maxStartDay <= data.StartDay {
+			maxStartDay = data.StartDay
+			demonData = data
+		}
+	}
+	return demonData
+}
+
+type ActivitySignInData struct {
+	SignDay    int32
+	IsDouble   int32
+	VipLevel   int32
+	ActivityId int32
+	RewardList map[int32]int32
+}
+
+type ActivitySignIn struct {
+	SignData map[int32]*ActivitySignInData
+}
+
+var ConvertActivitySignIn = map[int32]*ActivitySignIn{}
+
+func convertActivitySignInCfg() {
+	for _, data := range serverproto.ActivitiesSignInCfgLoader {
+		_, ok := ConvertActivitySignIn[data.ActivitiesId]
+		if !ok {
+			convertData := &ActivitySignIn{
+				SignData: map[int32]*ActivitySignInData{},
+			}
+			ConvertActivitySignIn[data.ActivitiesId] = convertData
+		}
+
+		signData := &ActivitySignInData{
+			RewardList: map[int32]int32{},
+		}
+		signData.VipLevel = data.VipLevel
+		signData.IsDouble = data.SignInType
+		signData.SignDay = data.Day
+		signData.ActivityId = data.ActivitiesId
+
+		for _, reward := range data.SignInReward {
+			itemId, itemCount := Str2Res(reward)
+			signData.RewardList[itemId] += itemCount
+		}
+
+		ConvertActivitySignIn[data.ActivitiesId].SignData[data.Day] = signData
+	}
+}
+
+type IdolBoxData struct {
+	Level       int32
+	BoxCount    int32
+	TicketCount int32
+	Reward      []*serverproto.KeyValueType
+}
+
+var ConvertIdolBoxData = map[int32]*IdolBoxData{}
+
+func convertIdolSeasonCfg() {
+	//解析馈赠宝箱
+	for _, data := range serverproto.CompetitionAidouluCfgLoader {
+		convertData := &IdolBoxData{
+			Level:       data.BoxId,
+			BoxCount:    data.GoodNum,
+			TicketCount: data.ConditionHot,
+		}
+		for _, reward := range data.Rewards {
+			itemId, itemNum := Str2Res(reward)
+			if itemNum > 0 {
+				convertData.Reward = append(convertData.Reward, &serverproto.KeyValueType{
+					Key:   itemId,
+					Value: itemNum,
+				})
+			}
+		}
+
+		ConvertIdolBoxData[data.BoxId] = convertData
+	}
+}
+
+type StProbRewardData struct {
+	Weight   int32
+	ItemId   int32
+	ItemCnt  int32
+	WaitTime int32
+}
+
+type StDbWishBox struct {
+	IsRand      bool
+	ItemId      int32
+	BoxType     int32                    // 类型
+	WaitTime    int32                    // 倒计时
+	LuckyProb   int32                    // 暴击概率
+	SpeedCost   serverproto.KeyValueType // 加速消耗
+	RewardList  []*StProbRewardData      // 许愿奖励
+	LuckyReward []*StProbRewardData      // 暴击奖励
+}
+
+func (this StDbWishBox) GetRewardItem(itemId int32) (ret *StProbRewardData) {
+	for _, i2 := range this.RewardList {
+		if i2.ItemId != itemId {
+			continue
+		}
+		ret = i2
+		break
+	}
+	return
+}
+
+func (this StDbWishBox) GetRandRewardItem() (ret *StProbRewardData) {
+	total := this.RewardList[len(this.RewardList)-1].Weight
+	value := rand.Int31n(total)
+	for _, i2 := range this.RewardList {
+		if value > i2.Weight {
+			continue
+		}
+		ret = i2
+		break
+	}
+	return
+}
+
+var ConvertWishBoxData = map[int32]*StDbWishBox{}
+
+func convertWishCfg() {
+	for _, data := range serverproto.WishCfgLoader {
+		dbData := &StDbWishBox{ItemId: data.Id, BoxType: data.BoxType, WaitTime: data.WishCountdown, LuckyProb: data.LuckyProbability}
+		initWeight := int32(0)
+		for _, i2 := range data.WishReward {
+			rewardItem := strings.Split(i2, ":")
+			if len(rewardItem) < 3 {
+				panic("许愿表配置奖励错误")
+			}
+			weight, itemId, itemcnt := Str2Res_3(i2)
+			initWeight += weight
+			dbData.RewardList = append(dbData.RewardList, &StProbRewardData{Weight: int32(initWeight), ItemId: int32(itemId), ItemCnt: int32(itemcnt), WaitTime: data.WishCountdown})
+		}
+		sort.Slice(dbData.RewardList, func(i, j int) bool {
+			return dbData.RewardList[i].Weight < dbData.RewardList[j].Weight
+		})
+		if initWeight > 0 {
+			dbData.IsRand = true
+		}
+		initWeight = 0
+		for _, i2 := range data.LuckyReward {
+			rewardItem := strings.Split(i2, ":")
+			if len(rewardItem) < 3 {
+				panic("许愿表配置暴击奖励错误")
+			}
+			weight, itemId, itemcnt := Str2Res_3(i2)
+			initWeight += weight
+			dbData.LuckyReward = append(dbData.LuckyReward, &StProbRewardData{Weight: int32(initWeight), ItemId: int32(itemId), ItemCnt: int32(itemcnt), WaitTime: data.WishCountdown})
+		}
+		sort.Slice(dbData.LuckyReward, func(i, j int) bool {
+			return dbData.LuckyReward[i].Weight < dbData.LuckyReward[j].Weight
+		})
+
+		for _, i2 := range data.AccelerateCost {
+			dbData.SpeedCost.Key, dbData.SpeedCost.Value = Str2Res(i2)
+		}
+		ConvertWishBoxData[data.Id] = dbData
+	}
+}
+
+type CombineServer struct {
+	Id          int32
+	ServerList  []*serverproto.KeyValueType
+	CombineTime uint64
+	Notice      string
+}
+
+var ConvertCombineServerData = map[int32]*CombineServer{}
+
+func ConvertCombinedServer() {
+	//热跟新的时候需要重新处理
+	ConvertCombineServerData = make(map[int32]*CombineServer)
+
+	for _, data := range serverproto.CombinedServiceCfgLoader {
+		combineData := &CombineServer{}
+		combineData.Id = data.Id
+
+		loc := util.GetLoc()
+
+		if data.Time != "" {
+			sTime, err1 := time.ParseInLocation(util.DATE_FORMAT, data.Time, loc)
+			if err1 != nil {
+				util.PanicF("combineData endTime err:%v", err1)
+			}
+			combineData.CombineTime = uint64(sTime.UnixNano() / 1e6)
+		}
+
+		for _, servers := range data.Number {
+			start, end := Str2Res(servers)
+			combineData.ServerList = append(combineData.ServerList, &serverproto.KeyValueType{
+				Key:   start,
+				Value: end,
+			})
+		}
+		combineData.Notice = data.Tips
+		ConvertCombineServerData[data.Id] = combineData
+	}
+}
+
+func CheckInCombined(zoneId int32) (bool, uint64) {
+	data, ok := ConvertCombineServerData[1]
+	if !ok {
+		return false, 0
+	}
+	/*
+		nowTime := util.GetCurrentTime()
+		if data.CombineTime > nowTime {
+			return false
+		}
+	*/
+
+	for _, server := range data.ServerList {
+		if server.Key <= zoneId && zoneId <= server.Value {
+			return true, data.CombineTime
+		}
+	}
+	return false, 0
+}

+ 901 - 0
RO_Server_Trunk-branch_0.1.39/roserver/baseserver/model/base_config_global.go

@@ -0,0 +1,901 @@
+package model
+
+import (
+	"rocommon/util"
+	"roserver/serverproto"
+	"strings"
+)
+
+var GlobalAttrPetNotInheritHeroList []serverproto.Attr //宠物不继承给玩家的属性列表
+var ChatWorldRoleLevel int32 = 0
+var ChatWorldMapLevel int32 = 0
+var ChatWorldTime uint64 = 0
+var GlobalRoleOriginalAttrPoint int32 = 0
+
+var GlobalDaoChangChallengeCount int32 = 0
+var GlobalDaoChangByCount int32 = 0
+var GlobalDaoChangRewardCount int32 = 0
+var GlobalDaoChangRankMinLevel int32 = 0
+var GlobalArenaByCountCost = map[int32]int32{}
+var GlobalMailIdArenaTopReward int32 = 0
+var GlobalMailIdArenaScoreLevelReward int32 = 0
+var GlobalMailIdBossOwnerReward int32 = 0
+var GlobalMailIdBossOtherReward int32 = 0
+var GlobalMailIdExpeditionReward int32 = 4
+var GlobalMailIdActivitiesReward int32 = 5
+var GlobalMailIdActivitiesCurRechargeReward int32 = 28
+var GlobalMailIdInvitationDelMember int32 = 6
+var GlobalMailIdVipLevelUp int32 = 7
+var GlobalMailIdPayReward int32 = 8
+var GlobalMailRuneExplore int32 = 22
+
+var GlobalRuneGiftGoldShopResetVersion int32 = 0
+
+//var GlobalMailIdMormalMonthCard int32 = 9
+//var GlobalMailIdVipMonthCard int32 = 10
+
+var GlobalSystemMsgItemList = map[int32]struct{}{} //获得稀有道具播报系统公告
+
+var GlobalSocialSubNumLimit int32 = 99
+var GlobalSocialFansNumLimit int32 = 999
+var GlobalSocialBlackNumLimit int32 = 99
+var GlobalFemaleHead int32
+var GlobalMaleHead int32
+var GlobalWorldBossChallengeCount int32 = 0
+var GlobalIncomeTime int32 = 0
+var GlobalIncomeLimitTime int32 = 0
+
+//evil
+var GlobalEvilRefreshConsume = map[int32]int32{}
+var GlobalEviChallengeCost int32 = 0
+var GlobalEvilExpLimit int32 = 0
+
+//CreateItemList
+var GlobalCreateItemList = map[int32]int32{}
+var GlobalCreateRoleMailReward = map[int32]int32{}
+
+//SystemMessageType
+var GlobalSystemMessageTypeArenaWinStreak = 0
+
+//competition
+var GlobalCompetitionSectionFactor float32 = 0.75
+var GlobalCompetitionSectionTotal int64 = 750
+var GlobalCompetitionScoreItem = map[int32]*serverproto.KeyValueType{} //通缉令兑换积分
+var GlobalCompetitionScoreItemFactor []*serverproto.KeyValueTypeList   //通缉令兑换积分权重
+
+//guild
+var GlobalGuildApplyListMax int32 = 0
+var GlobalGuildVicePreNum int32 = 0
+var GlobalGuildJoinLevel int32 = 0
+var GlobalGuildRoleApplyMax int32 = 0
+var GlobalGuildLogMaxCount int32 = 0
+var GlobalGuildBuildBadge int32 = 0
+var GlobalGuildMinNameStringLen int32 = 0
+var GlobalGuildMaxNameStringLen int32 = 0
+
+var GlobalGuildMinSearchStringLen int32 = 0
+var GlobalGuildMaxSearchStringLen int32 = 0
+
+var GlobalGuildHeadFrame int32 = 0
+
+//公会战
+var GlobalGuildBattleRewardTime uint64 = 5 * 1000 //5s 公会战收益时间间隔(秒)
+var GlobalGuildBattleChallengeNum int32 = 10      //公会战单场挑战次数
+var GlobalGuildBattleBuyChallengeCost uint64 = 0
+var GlobalGuildBattleRebornCost uint64 = 0
+var GlobalGuildBattleFightPower int32 = 0
+var GlobalGuildBattleWinMaxScore int32 = 0
+var GlobalGuildBattleRebornCdTime uint64 = 60 * 1000 //虚弱时间
+
+//宠物技能升级消耗(领悟消耗)
+var GlobalPetSkillUpConsume int32 = 0
+var GlobalPetAdvanceLimit []int32
+var GlobalPetDecomposeItemList = map[int32]*serverproto.KeyValueType{} //分解获得的道具
+var GlobalPetAssistCD int32 = 0                                        //援助设置CD时间
+var GlobalNormalPetDecompose int32 = 0
+var GlobalPet1LevelDecompose []*serverproto.KeyValueType
+var GlobalVipPetDecompose int32 = 0
+var GlobalPetDecomposeNormal = map[uint32]*serverproto.KeyValueType{} //
+var GlobalPetDecomposeMin = map[uint32]*serverproto.KeyValueType{}    //
+var GlobalPetDecomposeMvp = map[uint32]*serverproto.KeyValueType{}    //
+var GlobalPetQiyueUnlockCost []serverproto.KeyValueType               //宠物觉醒槽位解析消耗
+var GlobalPetQiyueMaxSlotNum = 4                                      //宠物觉醒最大可解锁槽位
+var GlobalPetQiyueNatureRate int32 = 1000                             //宠物契约相同属性额外继承属性比例
+//远征之门
+var GlobalExpeditionGuildCallForHelpCDTime uint64 = 0
+var GlobalExpeditionGuildHelpNum int32 = 0
+var GlobalExpeditionGuildBeHelpedNum int32 = 0
+var GlobalExpeditionChallengeNum int32 = 0
+var GlobalExpeditionHelpRewardList = map[int32]int32{}
+var GlobalExpeditionResetRankScore int32 = 0
+
+//invitation
+var GlobalInvitationClickNum int32 = 10
+var GlobalInvitationClickMasterRes int32 = 10
+var GlobalInvitationClickMemberRes int32 = 10
+
+var GlobalQuickBattleTimes int32 = 0
+var GlobalRMBToVipExpRMB int32 = 0
+var GlobalRMBToVipExpVip int32 = 0
+
+//冲榜 爬塔, 道场
+var GlobalMailIdRushTower int32 = 11
+var GlobalMailIdRushArena int32 = 12
+var GlobalRushTowerFightCount int32 = 0
+var GlobalRushDaoFightCount int32 = 0
+
+var GlobalMailRushPetBaseReward int32 = 25
+var GlobalMailRushPetRankReward int32 = 24
+
+var GlobalMailRushSkillBaseReward int32 = 30
+var GlobalMailRushSkillRankReward int32 = 29
+
+//
+var GlobalMailIdRushMap int32 = 15
+var GlobalMailRushMapBaseReward int32 = 16
+
+//冲榜邮件Rank奖励ID
+var GlobalRushTowerRewardList []*serverproto.KeyValueType //爬塔冲榜奖励
+var GlobalRushArenaRewardList []*serverproto.KeyValueType //英灵殿冲榜奖励
+//冲榜邮件战斗次数奖励ID
+var GlobalMailRushTowerBaseReward int32 = 13
+var GlobalMailRushDaoBaseReward int32 = 14
+
+var GloablMailDivineReward int32 = 27
+
+var GloablMailIdolFansReward int32 = 32
+
+//公会战会长奖励
+var GlobalMailGuildBattlePreReward int32 = 18
+
+//公会战成员奖励
+var GlobalMailGuildBattleMemReward int32 = 19
+
+//积分奖励
+var GlobalMailGuildBattleScoreReward int32 = 20
+
+//击杀奖励
+var GlobalMailGuildBattleKillerReward int32 = 21
+
+//公会魔王
+var GlobalMailGuildDemonReward int32 = 31
+
+//14天连续登录补领需要金币
+var GlobalActivities14DaysLogin int32 = 0
+
+//百人道场
+var GlobalDaoChang100RewardInterval uint64 = 5 * 60 * 1000
+var GlobalDaoChang100BaseRewardList = map[int32]int32{}
+var GlobalDaoChang100ChallengeCount int32 = 3
+var GlobalDaoChang100TotalRewardTime uint64 = 48 * 60 * 60 * 1000
+var GlobalDaoChangBuyCostList []*serverproto.KeyValueType
+var GlobalDaoChangUnlockMapLevelId int32 = 0
+var GlobalDaoChang100BattleCheck []float64 //百人道场最低战力校验配置参数(A1;A2;A3)
+var GlobalArenaBattleCheck []float64       //英灵殿最低战力校验配置参数(A1;A2;A3)
+
+//问卷调查奖励
+var GlobalQuestionRewardList = map[int32]int32{}
+
+var GlobalKeepSakeCrystalToMaterial = map[int32]int32{}
+var GlobalKeepSakeMaterialToCrystal = map[int32]int32{}
+
+//职业更换
+var GlobalReplaceJobMainHeroLevel = 30                      //主角登记
+var GlobalReplaceJobHeroLevel = 30                          //伙伴等级
+var GlobalReplaceJobConsumeList []*serverproto.KeyValueType //更换职业消耗
+
+//作弊处理
+var GlobalCheatBanTime = map[int32]uint64{}
+var GlobalMaxCheatBanTime uint64 = 0
+var GlobalMaxCheatBanNum int32 = 0
+var GlobalCheatPersonalChat ConvertCheatMsgData
+var GlobalCheatPublicChat ConvertCheatMsgData
+
+var GlobalGuildKickMemberCount int32 = 0
+
+//玩家累计充值档位
+var GlobalTotalRechargeList []*serverproto.KeyValueType
+
+var GlobalExchangeGuildPresident int32 = 7
+
+var GlobalCashShopReward []*serverproto.KeyValueType
+var GlobalCashShopCostId int32 = 40
+var GlobalCashShopCostCount int32 = 100
+var GlobalPetSkillUpCost int32 = 0
+
+var GlobalPetLevelScore int32 = 0
+var GlobalPetSkillScore int32 = 0
+
+var GlobalPetQualityScore []*serverproto.KeyValueType
+
+//远航试炼
+var GlobalCrossYuanHangTrialMaxNum int32 = 0         //远航每日出发次数上限
+var GlobalCrossYuanHangTrialRewardNum int32 = 0      //远航打劫获得奖励有效次数(每日重置)
+var GlobalCrossYuanHangTrialViewMaxNum int32 = 0     //远航单次同屏所需显示人数上限
+var GlobalCrossYuanHangTrialRankListMaxNum int32 = 0 //远航抢夺排行榜记录数量上限
+var GlobalCrossYuanHangTrialOpenTimeBeginTime string
+var GlobalCrossYuanHangTrialOpenTimeEndTime string
+var GlobalCrossTopTowerOpenTimeBeginTime string
+var GlobalCrossTopTowerOpenTimeEndTime string
+var GlobalCrossMaxFightPowerRankVal int32
+var GlobalCrossMaxFightPowerFightInfoUpdateTime int32
+
+var GlobalGuildDemonBroadCastLevel int32 = 0
+
+//技能装备(神器)重铸
+var GlobalSkillEquipReforgeMinStart int32
+var GlobalSkillEquipReforgePoolList []int32
+var GlobalSkillEquipShiftCost = map[int32]*serverproto.KeyValueType{}
+
+var GlobalCruiseMax int32 = 0
+
+var GlobalCompetitonDayRewardLevel int32 = 0
+
+var GlobalWishSlotMaxCnt int32 = 0
+var GlobalWishSlotCost = serverproto.KeyValueType{}
+
+type IdolDayReward struct {
+	Id        int32
+	StartTime string
+	EndTime   string
+	ItemId    int32
+	ItemCount int32
+}
+
+var GlobalCompetitionIdolDayReward = map[int32]*IdolDayReward{}
+
+var GlobalCardLevelExchange = map[int32]*serverproto.KeyValueType{} //
+func ConvertOldRedisGlobalCfg() {
+	convertGlobalCfg()
+}
+func convertGlobalCfg() {
+	//宠物不继承给玩家的属性列表
+	tmpAttrStrList := strings.Split(getGlobalCfgValS(230), ";")
+	for idx := 0; idx < len(tmpAttrStrList); idx++ {
+		tmpAttrId, _ := Str2Num(tmpAttrStrList[idx])
+		if tmpAttrId > 0 {
+			GlobalAttrPetNotInheritHeroList = append(GlobalAttrPetNotInheritHeroList, serverproto.Attr(tmpAttrId))
+		}
+	}
+
+	//玩家发言条件
+	if cfgData, ok := serverproto.GlobalCfgLoader[int32(serverproto.GlobalType_Global_Chat_World_Role_Level)]; ok {
+		strList := strings.Split(cfgData.SVal, ";")
+		for idx := range strList {
+			key, value := Str2Res(strList[idx])
+			if key == int32(serverproto.TaskType_Base_Level) {
+				ChatWorldRoleLevel = value
+			} else if key == int32(serverproto.TaskType_Level_Battle_Count) {
+				ChatWorldMapLevel = value
+			}
+		}
+	}
+	//玩家聊天发言间隔时长(S)
+	if cfgData, ok := serverproto.GlobalCfgLoader[int32(serverproto.GlobalType_Global_Chat_World_Time)]; ok {
+		ChatWorldTime = uint64(cfgData.IVal * 1000)
+	}
+
+	//初始化可添加的属性点
+	GlobalRoleOriginalAttrPoint = getGlobalCfgValI(serverproto.GlobalType_Global_Role_Original_AddAttrPoint)
+	//道场挑战次数
+	GlobalDaoChangChallengeCount = getGlobalCfgValI(serverproto.GlobalType_Global_Arena_DaoChang_Challenge)
+	//英灵殿可购买挑战次数
+	GlobalDaoChangByCount = getGlobalCfgValI(serverproto.GlobalType_Global_Arena_DaoChang_Buy_Count)
+	//道场胜利奖励次数
+	GlobalDaoChangRewardCount = getGlobalCfgValI(serverproto.GlobalType_Global_Arena_DaoChang_Reward_count)
+	//英灵殿匹配对象最低等级
+	GlobalDaoChangRankMinLevel = getGlobalCfgValI(serverproto.GlobalType_Global_Arena_DaoChang_RankMin_Level)
+
+	//英灵殿购买挑战次数消耗
+	if cfgData, ok := serverproto.GlobalCfgLoader[int32(serverproto.GlobalType_Global_Arena_DaoChang_Buy_Cost)]; ok {
+		costStrList := strings.Split(cfgData.SVal, ";")
+		for idx := range costStrList {
+			key, value := Str2Res(costStrList[idx])
+			if key > 0 && value > 0 {
+				GlobalArenaByCountCost[key] += value
+			}
+		}
+	}
+	//英灵殿排名奖励邮件ID
+	GlobalMailIdArenaTopReward = getGlobalCfgValI(serverproto.GlobalType_Global_MailId_Arena_Top_Reward)
+	//英灵殿段位奖励邮件ID
+	GlobalMailIdArenaScoreLevelReward = getGlobalCfgValI(serverproto.GlobalType_Global_MailId_Arena_ScoreLevel_Reward)
+	//枯树枝召唤奖励邮件ID
+	GlobalMailIdBossOwnerReward = getGlobalCfgValI(serverproto.GlobalType_Global_MailId_Boss_Owner_Reward)
+	//枯树枝参与奖励邮件ID
+	GlobalMailIdBossOtherReward = getGlobalCfgValI(serverproto.GlobalType_Global_MailId_Boss_Other_Reward)
+
+	//获得稀有道具播报系统公告
+	tmpGlobalSystemMsgItemList := strings.Split(getGlobalCfgValS(serverproto.GlobalType_Global_SystemMsg_Item), ";")
+	for idx := 0; idx < len(tmpGlobalSystemMsgItemList); idx++ {
+		msgItemId, _ := Str2Num(tmpGlobalSystemMsgItemList[idx])
+		if msgItemId > 0 {
+			GlobalSystemMsgItemList[int32(msgItemId)] = struct{}{}
+		}
+	}
+
+	//关注列表人数上限
+	GlobalSocialSubNumLimit = getGlobalCfgValI(serverproto.GlobalType_Global_Social_SubNum_Limit)
+	if GlobalSocialSubNumLimit <= 0 {
+		GlobalSocialSubNumLimit = 99
+	}
+	//粉丝列表人数上限
+	GlobalSocialFansNumLimit = getGlobalCfgValI(serverproto.GlobalType_Global_Social_FansNum_Limit)
+	if GlobalSocialFansNumLimit <= 0 {
+		GlobalSocialFansNumLimit = 999
+	}
+	//屏蔽列表人数上限
+	GlobalSocialBlackNumLimit = getGlobalCfgValI(serverproto.GlobalType_Global_Social_BlackNum_Limit)
+	if GlobalSocialBlackNumLimit <= 0 {
+		GlobalSocialBlackNumLimit = 99
+	}
+
+	//init head
+	if cfgData, ok := serverproto.GlobalCfgLoader[int32(serverproto.GlobalType_Global_Init_Head_Portrait)]; ok {
+		strList := strings.Split(cfgData.SVal, ";")
+		if len(strList) >= 2 {
+			value, _ := Str2Num(strList[0])
+			GlobalFemaleHead = int32(value)
+			value2, _ := Str2Num(strList[1])
+			GlobalMaleHead = int32(value2)
+		} else {
+			util.InfoF("load head failed %v", len(strList))
+		}
+	}
+
+	//world boss challenge count
+	GlobalWorldBossChallengeCount = getGlobalCfgValI(serverproto.GlobalType_Global_World_Boss_ChallengeNum_Limit)
+
+	//income
+	GlobalIncomeTime = getGlobalCfgValI(serverproto.GlobalType_Global_Battle_Income_Time)
+	GlobalIncomeLimitTime = getGlobalCfgValI(serverproto.GlobalType_Global_Battle_Limit_Time)
+
+	//evil
+	GlobalEvilRefreshConsumeStrList := strings.Split(getGlobalCfgValS(serverproto.GlobalType_Global_Evil_Consume), ";")
+	for idx := 0; idx < len(GlobalEvilRefreshConsumeStrList); idx++ {
+		key, val := Str2Res(GlobalEvilRefreshConsumeStrList[idx])
+		if key > 0 && val > 0 {
+			GlobalEvilRefreshConsume[key] = val
+		}
+	}
+	GlobalEviChallengeCost = getGlobalCfgValI(serverproto.GlobalType_Global_Evil_Challenge_Cost)
+	GlobalEvilExpLimit = getGlobalCfgValI(serverproto.GlobalType_Global_Evil_Exp_Limit)
+
+	//CreateItemList
+	GlobalCreateItemListStr := strings.Split(getGlobalCfgValS(serverproto.GlobalType_Global_Create_Item_List), ";")
+	for idx := 0; idx < len(GlobalCreateItemListStr); idx++ {
+		key, val := Str2Res(GlobalCreateItemListStr[idx])
+		if key > 0 && val > 0 {
+			GlobalCreateItemList[key] = val
+		}
+	}
+	GlobalCreateRoleMailStr := strings.Split(getGlobalCfgValS(serverproto.GlobalType_Global_Create_Role_Reward), ";")
+	for idx := 0; idx < len(GlobalCreateRoleMailStr); idx++ {
+		key, val := Str2Res(GlobalCreateRoleMailStr[idx])
+		if key > 0 && val > 0 {
+			GlobalCreateRoleMailReward[key] = val
+		}
+	}
+
+	//GlobalSystemMessageTypeArenaWinStreak
+	sysStr := getGlobalCfgValS(serverproto.GlobalType_Global_Competition_Streak_Win)
+	GlobalSystemMessageTypeArenaWinStreak, _ = Str2Num(sysStr)
+
+	//Competition
+	//赛季公式计算参数
+	competitionSectionStr := getGlobalCfgValS(serverproto.GlobalType_Global_Competition_Factor)
+	factor, total := Str2Res(competitionSectionStr)
+	if factor > 0 {
+		GlobalCompetitionSectionFactor = float32(factor) / 10000
+	}
+	if total > 0 {
+		GlobalCompetitionSectionTotal = int64(total)
+	}
+
+	//赛季获取积分道具
+	var tmpFactor int32 = 0
+	var tmpLeftScore int32 = 0
+	tmpStrList := strings.Split(getGlobalCfgValS(serverproto.GlobalType_Global_Competition_ScoreItem), ";")
+	for idx := 0; idx < len(tmpStrList); idx++ {
+		key, v1, v2 := Str2Res_3(tmpStrList[idx])
+		if key > 0 && v1 > 0 && v2 > 0 {
+			tmpLeftScore = v1 //初始积分
+			GlobalCompetitionScoreItem[key] = &serverproto.KeyValueType{Key: v1, Value: v2}
+		} else {
+			key, v1 = Str2Res(tmpStrList[idx])
+			if key > 0 && v1 > 0 {
+				GlobalCompetitionScoreItem[key] = &serverproto.KeyValueType{Key: v1, Value: 0}
+			}
+		}
+	}
+	GlobalCompetitionScoreItemFactor = []*serverproto.KeyValueTypeList{}
+	tmpStrList = strings.Split(getGlobalCfgValS(serverproto.GlobalType_Global_Competition_ScoreItem_Factor), ";")
+	for idx := 0; idx < len(tmpStrList); idx++ {
+		v1, v2 := Str2Res(tmpStrList[idx])
+		if v1 > 0 && v2 > 0 {
+			tmpFactor += v2
+			GlobalCompetitionScoreItemFactor = append(GlobalCompetitionScoreItemFactor, &serverproto.KeyValueTypeList{
+				Key:       tmpFactor, //权重
+				ValueList: []int32{tmpLeftScore, v1},
+			})
+			tmpLeftScore = v1
+		}
+	}
+	tmpLeftScore = 0
+
+	GlobalGuildApplyListMax = getGlobalCfgValI(serverproto.GlobalType_Global_Guild_Apply_List_Max)
+	GlobalGuildVicePreNum = getGlobalCfgValI(serverproto.GlobalType_Global_Guild_VicePre_Num)
+	GlobalGuildJoinLevel = getGlobalCfgValI(serverproto.GlobalType_Global_Guild_Join_Level)
+	GlobalGuildRoleApplyMax = getGlobalCfgValI(serverproto.GlobalType_Global_Guild_Role_Apply_Max)
+	GlobalGuildLogMaxCount = getGlobalCfgValI(serverproto.GlobalType_Global_Guild_Log_Max_Count)
+	GlobalGuildBuildBadge = getGlobalCfgValI(serverproto.GlobalType_Global_Guild_OnBuild_Badge)
+	//公会名字
+	guildNameStr := getGlobalCfgValS(serverproto.GlobalType_Global_Guild_Name_String_Len)
+	guildNameMin, guildNameMax := Str2Res(guildNameStr)
+	if guildNameMin > 0 {
+		GlobalGuildMinNameStringLen = guildNameMin
+	}
+	if guildNameMax > 0 {
+		GlobalGuildMaxNameStringLen = guildNameMax
+	}
+
+	guildSearchStr := getGlobalCfgValS(serverproto.GlobalType_Global_Guild_Search_String_Len)
+	guildSearchMin, guildSearchMax := Str2Res(guildSearchStr)
+	if guildSearchMin > 0 {
+		GlobalGuildMinSearchStringLen = guildSearchMin
+	}
+	if guildSearchMax > 0 {
+		GlobalGuildMaxSearchStringLen = guildSearchMax
+	}
+
+	//petskill
+	GlobalPetSkillUpConsume = getGlobalCfgValI(serverproto.GlobalType_Global_Pet_SkillUp_Consume)
+	GlobalPetAdvanceLimit = []int32{}
+	GlobalPetAdvanceLimitStrList := strings.Split(getGlobalCfgValS(serverproto.GlobalType_Global_Pet_Advance_Limit), ";")
+	for idx := 0; idx < len(GlobalPetAdvanceLimitStrList); idx++ {
+		val, _ := Str2Num(GlobalPetAdvanceLimitStrList[idx])
+		if val > 0 {
+			GlobalPetAdvanceLimit = append(GlobalPetAdvanceLimit, int32(val))
+		}
+	}
+	//宠物分解
+	GlobalPetDecomposeMultiStr := strings.Split(getGlobalCfgValS(serverproto.GlobalType_Global_Decompose_Pet_Stone_Noraml), ";")
+	for idx := 0; idx < len(GlobalPetDecomposeMultiStr); idx++ {
+		level, itemId, itemNum := Str2Res_3(GlobalPetDecomposeMultiStr[idx])
+		if itemNum > 0 {
+			GlobalPetDecomposeNormal[uint32(level)] = &serverproto.KeyValueType{
+				Key:   itemId,
+				Value: itemNum,
+			}
+		}
+	}
+	GlobalPetDecomposeMinStr := strings.Split(getGlobalCfgValS(serverproto.GlobalType_Global_Decompose_Pet_Stone_Min), ";")
+	for idx := 0; idx < len(GlobalPetDecomposeMinStr); idx++ {
+		level, itemId, itemNum := Str2Res_3(GlobalPetDecomposeMinStr[idx])
+		if itemNum > 0 {
+			GlobalPetDecomposeMin[uint32(level)] = &serverproto.KeyValueType{
+				Key:   itemId,
+				Value: itemNum,
+			}
+		}
+	}
+	GlobalPetDecomposeMvpStr := strings.Split(getGlobalCfgValS(serverproto.GlobalType_Global_Decompose_Pet_Stone_Mvp), ";")
+	for idx := 0; idx < len(GlobalPetDecomposeMvpStr); idx++ {
+		level, itemId, itemNum := Str2Res_3(GlobalPetDecomposeMvpStr[idx])
+		if itemNum > 0 {
+			GlobalPetDecomposeMvp[uint32(level)] = &serverproto.KeyValueType{
+				Key:   itemId,
+				Value: itemNum,
+			}
+		}
+	}
+	GlobalPetDecomposeItemListStr := strings.Split(getGlobalCfgValS(serverproto.GlobalType_Global_Pet_Decompose), ";")
+	for idx := 0; idx < len(GlobalPetDecomposeItemListStr); idx++ {
+		v1, v2, v3 := Str2Res_3(GlobalPetDecomposeItemListStr[idx])
+		if v1 > 0 && v2 > 0 && v3 > 0 {
+			GlobalPetDecomposeItemList[v1] = &serverproto.KeyValueType{Key: v2, Value: v3}
+		}
+	}
+	//宠物契约
+	qiyueListStr := strings.Split(getGlobalCfgValS(serverproto.GlobalType_Global_PetQiyue_Slot_Unlock_Cost), ";")
+	for idx := 0; idx < len(qiyueListStr); idx++ {
+		k, v := Str2Res(qiyueListStr[idx])
+		if k > 0 && v > 0 {
+			GlobalPetQiyueUnlockCost = append(GlobalPetQiyueUnlockCost, serverproto.KeyValueType{Key: k, Value: v})
+		}
+	}
+	GlobalPetQiyueMaxSlotNum = len(GlobalPetQiyueUnlockCost)
+	GlobalPetQiyueNatureRate = getGlobalCfgValI(serverproto.GlobalType_Global_PetQiyue_Nature_Attr)
+
+	GlobalPetAssistCD = getGlobalCfgValI(serverproto.GlobalType_Global_Pet_Assist_CD)
+	GlobalNormalPetDecompose = getGlobalCfgValI(serverproto.GlobalType_Global_Normal_Pet_Decomposed)
+	GlobalVipPetDecompose = getGlobalCfgValI(serverproto.GlobalType_Global_Vip_Pet_Decomposed)
+	GlobalPet1LevelDecompose = []*serverproto.KeyValueType{}
+	tmpStrList = strings.Split(getGlobalCfgValS(serverproto.GlobalType_Global_Pet_1Level_Decompose_Res), ";")
+	for idx := 0; idx < len(tmpStrList); idx++ {
+		k, v := Str2Res(tmpStrList[idx])
+		GlobalPet1LevelDecompose = append(GlobalPet1LevelDecompose,
+			&serverproto.KeyValueType{Key: k, Value: v})
+	}
+
+	GlobalGuildHeadFrame = getGlobalCfgValI(serverproto.GlobalType_Global_Guild_Head_Frame)
+
+	//expedition
+	GlobalExpeditionGuildCallForHelpCDTime = uint64(getGlobalCfgValI(serverproto.GlobalType_Global_Expedition_GuildCallForHelpCDTime))
+	GlobalExpeditionGuildCallForHelpCDTime *= 60 * 1000
+	GlobalExpeditionGuildHelpNum = getGlobalCfgValI(serverproto.GlobalType_Global_Expedition_Help_Num)
+	GlobalExpeditionGuildBeHelpedNum = getGlobalCfgValI(serverproto.GlobalType_Global_Expedition_Be_Help_Num)
+	GlobalExpeditionChallengeNum = getGlobalCfgValI(serverproto.GlobalType_Global_Expedition_Challenge_Num)
+	helpStr := strings.Split(getGlobalCfgValS(serverproto.GlobalType_Global_Expedition_Help_Reward), ";")
+	for idx := 0; idx < len(helpStr); idx++ {
+		key, val := Str2Res(helpStr[idx])
+		if key > 0 && val > 0 {
+			GlobalExpeditionHelpRewardList[key] += val
+		}
+	}
+	//invitation
+	GlobalInvitationClickNum = getGlobalCfgValI(serverproto.GlobalType_Global_Invitation_Click_Num)
+	GlobalInvitationClickMasterRes = getGlobalCfgValI(serverproto.GlobalType_Global_Invitation_Click_Res_Master)
+	GlobalInvitationClickMemberRes = getGlobalCfgValI(serverproto.GlobalType_Global_Invitation_Click_Res_Member)
+
+	GlobalQuickBattleTimes = getGlobalCfgValI(serverproto.GlobalType_Global_Quick_Battle_Times)
+
+	rmbToVipStr := strings.Split(getGlobalCfgValS(serverproto.GlobalType_Global_RMB_To_VipExp), ":")
+	if len(rmbToVipStr) >= 2 {
+		value, _ := Str2Num(rmbToVipStr[0])
+		GlobalRMBToVipExpRMB = int32(value)
+		value2, _ := Str2Num(rmbToVipStr[1])
+		GlobalRMBToVipExpVip = int32(value2)
+	}
+
+	GlobalRushTowerFightCount = getGlobalCfgValI(serverproto.GlobalType_Global_Rush_Tower_Count_Reward)
+	rushTowerStr := strings.Split(getGlobalCfgValS(serverproto.GlobalType_Global_Rush_Tower_Count_Reward), ";")
+	for _, data := range rushTowerStr {
+		strList := strings.Split(data, ":")
+		if len(strList) >= 2 {
+			key, _ := Str2Num(strList[0])
+			value, _ := Str2Num(strList[1])
+			GlobalRushTowerRewardList = append(GlobalRushTowerRewardList, &serverproto.KeyValueType{
+				Key:   int32(key),
+				Value: int32(value),
+			})
+		}
+	}
+	GlobalRushDaoFightCount = getGlobalCfgValI(serverproto.GlobalType_Global_Rush_Arena_Count_Reward)
+	rushArenaStr := strings.Split(getGlobalCfgValS(serverproto.GlobalType_Global_Rush_Arena_Count_Reward), ";")
+	for _, data := range rushArenaStr {
+		strList := strings.Split(data, ":")
+		if len(strList) >= 2 {
+			key, _ := Str2Num(strList[0])
+			value, _ := Str2Num(strList[1])
+			GlobalRushArenaRewardList = append(GlobalRushArenaRewardList, &serverproto.KeyValueType{
+				Key:   int32(key),
+				Value: int32(value),
+			})
+		}
+	}
+
+	GlobalActivities14DaysLogin = getGlobalCfgValI(serverproto.GlobalType_Global_Activities_14DaysLogin)
+
+	//百人道场
+	GlobalDaoChang100RewardInterval = uint64(getGlobalCfgValI(serverproto.GlobalType_Global_DaoChang100_RewardInterval))
+	GlobalDaoChang100RewardInterval = GlobalDaoChang100RewardInterval * 1000
+	GlobalDaoChang100ChallengeCount = getGlobalCfgValI(serverproto.GlobalType_Global_DaoChang100_ChallengeCount)
+	tmpRewardStrList := strings.Split(getGlobalCfgValS(serverproto.GlobalType_Global_DaoChang100_BaseRewardList), ";")
+	for idx := 0; idx < len(tmpRewardStrList); idx++ {
+		k, v := Str2Res(tmpRewardStrList[idx])
+		if k > 0 && v > 0 {
+			GlobalDaoChang100BaseRewardList[k] += v
+		}
+	}
+	GlobalDaoChang100TotalRewardTime = uint64(getGlobalCfgValI(serverproto.GlobalType_Global_DaoChang100_TotalRewardTime))
+	GlobalDaoChang100TotalRewardTime *= 60 * 60 * 1000
+	tmpRewardStrList = strings.Split(getGlobalCfgValS(serverproto.GlobalType_Global_DaoChang100_ChallengeCountByCost), ";")
+	for idx := 0; idx < len(tmpRewardStrList); idx++ {
+		k, v := Str2Res(tmpRewardStrList[idx])
+		if k > 0 && v > 0 {
+			GlobalDaoChangBuyCostList = append(GlobalDaoChangBuyCostList, &serverproto.KeyValueType{Key: k, Value: v})
+		}
+	}
+
+	//百人道场最低战力校验配置参数(A1;A2;A3)
+	tmpStrList = strings.Split(getGlobalCfgValS(serverproto.GlobalType_Global_DaoChang100_Battle_Check), ";")
+	for idx := 0; idx < len(tmpStrList); idx++ {
+		f, err := Str2Float32(tmpStrList[idx])
+		if err == nil {
+			GlobalDaoChang100BattleCheck = append(GlobalDaoChang100BattleCheck, float64(f))
+		}
+	}
+	//英灵殿最低战力校验配置参数(A1;A2;A3)
+	tmpStrList = strings.Split(getGlobalCfgValS(serverproto.GlobalType_Global_Arena_Battle_Check), ";")
+	for idx := 0; idx < len(tmpStrList); idx++ {
+		f, err := Str2Float32(tmpStrList[idx])
+		if err == nil {
+			GlobalArenaBattleCheck = append(GlobalArenaBattleCheck, float64(f))
+		}
+	}
+	//问卷礼包
+	GlobalQuestionRewardList = map[int32]int32{}
+	tmpRewardStrList = strings.Split(getGlobalCfgValS(serverproto.GlobalType_Global_Question_Reward), ";")
+	for idx := 0; idx < len(tmpRewardStrList); idx++ {
+		k, v := Str2Res(tmpRewardStrList[idx])
+		if k > 0 && v > 0 {
+			GlobalQuestionRewardList[k] += v
+		}
+	}
+
+	tmpKeepSakeList := strings.Split(getGlobalCfgValS(serverproto.GlobalType_Global_KeepSake_Crystal_To_Material), ";")
+	for _, keepSake := range tmpKeepSakeList {
+		strList := strings.Split(keepSake, ":")
+		if len(strList) >= 2 {
+			key, _ := Str2Num(strList[0])
+			value, _ := Str2Num(strList[1])
+			GlobalKeepSakeCrystalToMaterial[int32(key)] += int32(value)
+		}
+	}
+	tmpKeepSakePieceList := strings.Split(getGlobalCfgValS(serverproto.GlobalType_Global_KeepSake_Material_To_Crystal), ";")
+	for _, keepSake := range tmpKeepSakePieceList {
+		strList := strings.Split(keepSake, ":")
+		if len(strList) >= 2 {
+			key, _ := Str2Num(strList[0])
+			value, _ := Str2Num(strList[1])
+			GlobalKeepSakeMaterialToCrystal[int32(key)] += int32(value)
+		}
+	}
+
+	//职业更换
+	tmpStrList = strings.Split(getGlobalCfgValS(serverproto.GlobalType_Global_ReplaceJob_Level), ";")
+	if len(tmpStrList) >= 2 {
+		GlobalReplaceJobMainHeroLevel, _ = Str2Num(tmpStrList[0])
+		GlobalReplaceJobHeroLevel, _ = Str2Num(tmpStrList[1])
+	}
+	tmpStrList = strings.Split(getGlobalCfgValS(serverproto.GlobalType_Global_ReplaceJob_Consume), ";")
+	for idx := 0; idx < len(tmpStrList); idx++ {
+		k, v := Str2Res(tmpStrList[idx])
+		GlobalReplaceJobConsumeList = append(GlobalReplaceJobConsumeList,
+			&serverproto.KeyValueType{Key: k, Value: v})
+	}
+
+	//作弊处理cheat
+	tmpStrList = strings.Split(getGlobalCfgValS(serverproto.GlobalType_Global_Cheat_Ban_Time), ";")
+	for idx := 0; idx < len(tmpStrList); idx++ {
+		k, v := Str2Res(tmpStrList[idx])
+		if k <= 0 || v <= 0 {
+			continue
+		}
+		GlobalCheatBanTime[k] = uint64(v) * 60
+		if GlobalMaxCheatBanNum < k {
+			GlobalMaxCheatBanNum = k
+			GlobalMaxCheatBanTime = GlobalCheatBanTime[k]
+		}
+	}
+	tmpStrList = strings.Split(getGlobalCfgValS(serverproto.GlobalType_Global_Cheat_Chat_Personal), ";")
+	if len(tmpStrList) >= 5 {
+		valTime, _ := Str2Num(tmpStrList[0])
+		valLevel, _ := Str2Num(tmpStrList[1])
+		valNum, _ := Str2Num(tmpStrList[2])
+		valContentNum, _ := Str2Num(tmpStrList[3])
+		valRecharge, _ := Str2Num(tmpStrList[4])
+
+		GlobalCheatPersonalChat.ChatDuration = uint64(valTime * 60 * 1000)
+		GlobalCheatPersonalChat.Level = int32(valLevel)
+		GlobalCheatPersonalChat.RechargeNum = int32(valRecharge)
+		GlobalCheatPersonalChat.ParamList = append(GlobalCheatPersonalChat.ParamList, valNum, valContentNum)
+	}
+	tmpStrList = strings.Split(getGlobalCfgValS(serverproto.GlobalType_Global_Cheat_Chat_Public), ";")
+	if len(tmpStrList) >= 5 {
+		valTime, _ := Str2Num(tmpStrList[0])
+		valLevel, _ := Str2Num(tmpStrList[1])
+		valNum, _ := Str2Num(tmpStrList[2])
+		valContentNum, _ := Str2Num(tmpStrList[3])
+		valRecharge, _ := Str2Num(tmpStrList[4])
+
+		GlobalCheatPublicChat.ChatDuration = uint64(valTime * 60 * 1000)
+		GlobalCheatPublicChat.Level = int32(valLevel)
+		GlobalCheatPublicChat.RechargeNum = int32(valRecharge)
+		GlobalCheatPublicChat.ParamList = append(GlobalCheatPublicChat.ParamList, valNum, valContentNum)
+	}
+
+	GlobalGuildKickMemberCount = getGlobalCfgValI(serverproto.GlobalType_Global_Guild_Kick_Max_Count)
+
+	GlobalTotalRechargeList = []*serverproto.KeyValueType{}
+	tmpStrList = strings.Split(getGlobalCfgValS(serverproto.GlobalType_Global_TotalRecharge_List), ";")
+	for idx := 0; idx < len(tmpStrList); idx++ {
+		tmpRecharge, err := Str2Num(tmpStrList[idx])
+		if err != nil {
+			continue
+		}
+		GlobalTotalRechargeList = append(GlobalTotalRechargeList, &serverproto.KeyValueType{
+			Key:   int32(idx + 1),
+			Value: int32(tmpRecharge),
+		})
+	}
+
+	GlobalGuildBattleFightPower = getGlobalCfgValI(serverproto.GlobalType_Global_Guild_Battle_FightPower)
+	GlobalGuildBattleWinMaxScore = getGlobalCfgValI(serverproto.GlobalType_Global_Guild_Battle_WinScore)
+
+	_, rebornPrice := Str2Res(getGlobalCfgValS(serverproto.GlobalType_Global_Guild_Battle_Buy_Reborn))
+	GlobalGuildBattleRebornCost = uint64(rebornPrice)
+
+	GlobalGuildBattleRebornCdTime = uint64(getGlobalCfgValI(serverproto.GlobalType_Global_Guild_Battle_Reborn_CD)) * 1000
+
+	_, challengePrice := Str2Res(getGlobalCfgValS(serverproto.GlobalType_Global_Guild_Battle_Buy_challenge))
+	GlobalGuildBattleBuyChallengeCost = uint64(challengePrice)
+
+	GlobalExchangeGuildPresident = getGlobalCfgValI(serverproto.GlobalType_Global_Guild_Exchange_President)
+
+	if cfgData, ok := serverproto.GlobalCfgLoader[int32(serverproto.GlobalType_Global_Cash_Shop_Exchange_Cost)]; ok {
+		strList := strings.Split(cfgData.SVal, ":")
+		if len(strList) >= 2 {
+			itemId, _ := Str2Num(strList[0])
+			GlobalCashShopCostId = int32(itemId)
+			itemCount, _ := Str2Num(strList[1])
+			GlobalCashShopCostCount = int32(itemCount)
+		} else {
+			util.InfoF("load cash shop config failed %v", len(strList))
+		}
+	}
+
+	cashShopStrList := strings.Split(getGlobalCfgValS(serverproto.GlobalType_Global_Cash_Shop_Exchange_Reward), ";")
+	for idx := 0; idx < len(cashShopStrList); idx++ {
+		itemId, itemCount := Str2Res(cashShopStrList[idx])
+		if itemId != 0 && itemCount != 0 {
+			GlobalCashShopReward = append(GlobalCashShopReward, &serverproto.KeyValueType{
+				Key:   int32(itemId),
+				Value: int32(itemCount),
+			})
+		}
+	}
+
+	GlobalPetSkillUpCost = getGlobalCfgValI(serverproto.GlobalType_Global_Pet_SkillUp_Cost_Pet)
+
+	calcPetScore, okScore := serverproto.GlobalCfgLoader[int32(serverproto.GlobalType_Global_Rush_Pet_Calc_Score)]
+	if okScore {
+		strList := strings.Split(calcPetScore.SVal, ";")
+		if len(strList) >= 2 {
+			petLevelArg, _ := Str2Num(strList[0])
+			GlobalPetLevelScore = int32(petLevelArg)
+			petSkillArg, _ := Str2Num(strList[1])
+			GlobalPetSkillScore = int32(petSkillArg)
+		}
+	}
+
+	calcPetScoreList := strings.Split(getGlobalCfgValS(serverproto.GlobalType_Global_Pet_Quality_Calc_Score), ";")
+	for idx := 0; idx < len(calcPetScoreList); idx++ {
+		quality, score := Str2Res(calcPetScoreList[idx])
+		if quality > 0 && score > 0 {
+			GlobalPetQualityScore = append(GlobalPetQualityScore, &serverproto.KeyValueType{
+				Key:   int32(quality),
+				Value: int32(score),
+			})
+		}
+	}
+
+	GlobalRuneGiftGoldShopResetVersion = getGlobalCfgValI(serverproto.GlobalType_Global_Rune_GiftBag_Label_4_Reset)
+
+	//远航试炼
+	GlobalCrossYuanHangTrialMaxNum = getGlobalCfgValI(serverproto.GlobalType_Global_YuanHangTrialMaxNum)
+	GlobalCrossYuanHangTrialRewardNum = getGlobalCfgValI(serverproto.GlobalType_Global_CrossYuanHangTrialRewardNum)
+	GlobalCrossYuanHangTrialViewMaxNum = getGlobalCfgValI(serverproto.GlobalType_Global_CrossYuanHangTrialViewMaxNum)
+	GlobalCrossYuanHangTrialRankListMaxNum = getGlobalCfgValI(serverproto.GlobalType_Global_CrossYuanHangTrialRankListMaxNum)
+	tmpStrList = strings.Split(getGlobalCfgValS(serverproto.GlobalType_Global_CrossYuanHangTrialOpenTime), ";")
+	if len(tmpStrList) >= 2 {
+		GlobalCrossYuanHangTrialOpenTimeBeginTime = tmpStrList[0]
+		GlobalCrossYuanHangTrialOpenTimeEndTime = tmpStrList[1]
+		//tmpStr1 := util.GetDayByTimeStr2(util.GetTimeMilliseconds())
+		//tmpStartTimeStr := tmpStr1.Format(util.DATE_FORMAT1) + " " + tmpStrList[0]
+		//tmpTime := util.GetTimeByStr(tmpStartTimeStr)
+		//util.InfoF("CrossYuanHangTrial OpenTime=%v", tmpTime.String())
+
+		//tmpEndTimeStr := tmpStr1.Format(util.DATE_FORMAT1) + " " + tmpStrList[1]
+		//tmpTime = util.GetTimeByStr(tmpEndTimeStr)
+		//util.InfoF("CrossYuanHangTrial endTime=%v", tmpTime.String())
+	}
+	//巅峰之塔
+	tmpStrList = strings.Split(getGlobalCfgValS(serverproto.GlobalType_Global_CrossTopTowerOpenTime), ";")
+	if len(tmpStrList) >= 2 {
+		GlobalCrossTopTowerOpenTimeBeginTime = tmpStrList[0]
+		GlobalCrossTopTowerOpenTimeEndTime = tmpStrList[1]
+		//tmpStr1 := util.GetDayByTimeStr2(util.GetTimeMilliseconds())
+		//tmpStartTimeStr := tmpStr1.Format(util.DATE_FORMAT1) + " " + tmpStrList[0]
+		//tmpTime := util.GetTimeByStr(tmpStartTimeStr)
+		//util.InfoF("TopTower OpenTime=%v", tmpTime.String())
+
+		//tmpEndTimeStr := tmpStr1.Format(util.DATE_FORMAT1) + " " + tmpStrList[1]
+		//tmpTime = util.GetTimeByStr(tmpEndTimeStr)
+		//util.InfoF("TopTower endTime=%v", tmpTime.String())
+	}
+	GlobalCrossMaxFightPowerRankVal = getGlobalCfgValI(serverproto.GlobalType_Global_CrossMaxFightPowerRankVal)
+	GlobalCrossMaxFightPowerFightInfoUpdateTime = getGlobalCfgValI(serverproto.GlobalType_Global_CrossMaxFightPowerFightInfoUpdateTime)
+
+	GlobalGuildDemonBroadCastLevel = getGlobalCfgValI(serverproto.GlobalType_Global_GuildDemon_BroadCast_Level)
+
+	GlobalSkillEquipReforgeMinStart = getGlobalCfgValI(serverproto.GlobalType_Global_SKillEquip_ReforgeCost)
+	reforgePoolList := strings.Split(getGlobalCfgValS(serverproto.GlobalType_Global_SKillEquip_ReforgeCost), ":")
+	for _, poolStr := range reforgePoolList {
+		configId, err := Str2Num(poolStr)
+		if err != nil {
+			continue
+		}
+		GlobalSkillEquipReforgePoolList = append(GlobalSkillEquipReforgePoolList, int32(configId))
+	}
+	shiftCost := strings.Split(getGlobalCfgValS(serverproto.GlobalType_Global_SKillEquip_ShiftCost), ";")
+	for _, Str := range shiftCost {
+		v1, v2, v3 := Str2Res_3(Str)
+		if v1 <= 0 || v2 <= 0 || v3 <= 0 {
+			continue
+		}
+		GlobalSkillEquipShiftCost[v1] = &serverproto.KeyValueType{Key: v2, Value: v3}
+	}
+
+	idolDayReward := strings.Split(getGlobalCfgValS(serverproto.GlobalType_Global_Competition_Idol_Day_Reward), ";")
+	for _, idolReward := range idolDayReward {
+		convertIdol := &IdolDayReward{}
+
+		detail := strings.Split(idolReward, ":")
+		if len(detail) >= 9 {
+			id, _ := Str2Num(detail[0])
+			convertIdol.Id = int32(id)
+
+			convertIdol.StartTime = detail[1] + ":" + detail[2] + ":" + detail[3]
+			convertIdol.EndTime = detail[4] + ":" + detail[5] + ":" + detail[6]
+
+			itemId, _ := Str2Num(detail[7])
+			itemCount, _ := Str2Num(detail[8])
+			convertIdol.ItemId = int32(itemId)
+			convertIdol.ItemCount = int32(itemCount)
+		}
+
+		GlobalCompetitionIdolDayReward[convertIdol.Id] = convertIdol
+	}
+
+	globalCfg2, ok2 := serverproto.GlobalCfgLoader[int32(serverproto.GlobalType_Global_Cruise_Max)]
+	if ok2 {
+		GlobalCruiseMax = globalCfg2.IVal
+	}
+
+	GlobalCompetitonDayRewardLevel = getGlobalCfgValI(serverproto.GlobalType_Global_Competition_Idol_Day_Reward)
+
+	GlobalWishSlotMaxCnt = getGlobalCfgValI(serverproto.GlobalType_Global_Unlock_WishBox_Slot)
+
+	strCost := getGlobalCfgValS(serverproto.GlobalType_Global_Unlock_WishBox_Slot)
+	itemId, itemCnt := Str2Res(strCost)
+	GlobalWishSlotCost = serverproto.KeyValueType{Key: itemId, Value: itemCnt}
+
+	cardLevelExchange := strings.Split(getGlobalCfgValS(serverproto.GlobalType_Global_Card_Level_Exchange), ";")
+	for _, cardSourceStr := range cardLevelExchange {
+		detail := strings.Split(cardSourceStr, ":")
+		if len(detail) >= 3 {
+			level, _ := Str2Num(detail[0])
+			itemId, _ := Str2Num(detail[1])
+			itemNum, _ := Str2Num(detail[2])
+
+			GlobalCardLevelExchange[int32(level)] = &serverproto.KeyValueType{
+				Key:   int32(itemId),
+				Value: int32(itemNum),
+			}
+		}
+	}
+}
+func getGlobalCfgValI(idx serverproto.GlobalType) int32 {
+	if cfgData, ok := serverproto.GlobalCfgLoader[int32(idx)]; ok {
+		return cfgData.IVal
+	}
+	return 0
+}
+func getGlobalCfgValS(idx serverproto.GlobalType) string {
+	if cfgData, ok := serverproto.GlobalCfgLoader[int32(idx)]; ok {
+		return cfgData.SVal
+	}
+	return ""
+}
+
+//恶意聊天
+type ConvertCheatMsgData struct {
+	ChatDuration uint64 //ms
+	Level        int32
+	//1,私聊对象数量,聊天字数大于3
+	//2,相同聊天内容条数
+	ParamList   []int
+	RechargeNum int32 //充值金额
+}

+ 486 - 0
RO_Server_Trunk-branch_0.1.39/roserver/baseserver/model/client_user.go

@@ -0,0 +1,486 @@
+package model
+
+import (
+	"errors"
+	"fmt"
+	"rocommon"
+	"rocommon/rpc"
+	"rocommon/util"
+	"roserver/baseserver/router"
+	"roserver/serverproto"
+	"sort"
+	"strconv"
+	"sync"
+	"time"
+	"unsafe"
+)
+
+const (
+	CLIENT_STATE_CONNECTED         = 1
+	CLIENT_STATE_DISJOIN_RECONNECT = 2 //断线状态等待重连
+	CLIENT_STATE_DISJOIN           = 3 //断线状态等待移除列表
+)
+const CLIENT_TIME_OUT_DURATION = 30 * 60
+
+//
+//var clientDisJoinReconnect = func(m *StateMachineCore, data interface{}) int32 {
+//	//移除clientUser的Session相关信息,但是保存节点服务器相关信息
+//	parent := unsafe.Pointer(m)
+//	cli := (*ClientUser)(parent)
+//
+//	ClientMag.reconnectClientList.Store(cli.OpenId, cli)
+//
+//	return CLIENT_STATE_DISJOIN_RECONNECT
+//}
+
+var clientConnected = func(m *StateMachineCore, data interface{}) int32 {
+	//移除clientUser的Session相关信息,但是保存节点服务器相关信息
+	parent := unsafe.Pointer(m)
+	cli := (*ClientUser)(parent)
+
+	//oldCliUser := ClientMag.GetConnectedFromOpenId(cli.OpenId)
+	//if oldCliUser != nil {
+	//	oldCliUser.ClientSession = nil
+	//	ClientMag.connectedClientList.Delete(cli.OpenId)
+	//}
+	openId := ConvertPlatform(cli.OpenId, cli.Platform)
+	ClientMag.connectedClientList.Store(openId, cli)
+
+	return CLIENT_STATE_CONNECTED
+}
+
+//主线程中不要对结构中的数据做修改,否则会有多线程冲突(或者加锁进行操作)
+type ClientUser struct {
+	StateMachineCore
+	serviceNode   sync.RWMutex
+	ClientSession rocommon.Session
+	LastPingTime  time.Time
+
+	//绑定的后端服务器节点
+	ServiceTargets map[string]*ServiceBackend //每种类型的服务只会绑定一个节点
+	gateID         ClientID
+
+	//登陆验证使用
+	OpenId    string
+	Platform  string
+	LoginData []byte
+
+	SeqId uint32 //包序列号,判断合法性
+
+	//收到消息数量
+	msgTime      uint64
+	msgCount     uint32
+	invalidCount uint32 //触发非法次数
+
+	//压力测试性能使用
+	kvTimeLock       sync.Mutex
+	kvBossRewardTime map[int32][]*TempKVSt
+	kvIndex          int32
+}
+
+type TempKVSt struct {
+	ClientKVTime     uint64
+	RecvClientKVTime uint64
+	MsgName          string
+}
+
+type ClientID struct {
+	SessID     uint64 //客户端在网管上的sessionid
+	ServiceID  string //客户端所在的网关
+	SessIdList []uint64
+}
+
+type ServiceBackend struct {
+	ServiceName string
+	ServiceID   string
+}
+
+func NewUser(cliSession rocommon.Session) *ClientUser {
+	cli := &ClientUser{
+		ClientSession: cliSession,
+		gateID: ClientID{
+			SessID:    cliSession.ID(),
+			ServiceID: GateServiceID,
+		},
+		ServiceTargets:   map[string]*ServiceBackend{},
+		kvBossRewardTime: map[int32][]*TempKVSt{},
+	}
+	cli.init()
+
+	return cli
+}
+
+func (this *ClientUser) init() {
+	//注册状态机
+	this.InitState()
+	this.RegisterState(CLIENT_STATE_CONNECTED, clientConnected)
+}
+
+func (this *ClientUser) ConnectReset(cliSession rocommon.Session) error {
+	//关闭之前维护的session
+	//通过无读写默认进行关闭
+	this.ClientSession.(rocommon.ContextSet).SetContextData("user", nil, "ConnectReset")
+
+	this.gateID.SessID = cliSession.ID()
+	ret := BindUser2Session(this, cliSession)
+	if ret != nil {
+		return ret
+	}
+
+	//从重连队列中移除
+	this.SeqId = 0
+	this.msgTime = 0
+	this.msgCount = 0
+	this.invalidCount = 0
+
+	if this.state != CLIENT_STATE_CONNECTED {
+		this.RemoveConnected()
+		this.SwitchState(CLIENT_STATE_CONNECTED, nil)
+	}
+	return nil
+}
+
+func (this *ClientUser) RemoveConnected() {
+	openId := ConvertPlatform(this.OpenId, this.Platform)
+	ClientMag.connectedClientList.Delete(openId)
+}
+
+func (this *ClientUser) Ping() {
+	this.LastPingTime = util.GetCurrentTimeNow()
+}
+
+//gate把接收到的数据直接发送到后端服务器节点
+func (this *ClientUser) ClientDirect2Backend(serviceId string, msgId int, seqId uint32, msgData []byte, serviceType string) error {
+	//获得后端服务器节点,并发送
+	service := GetServiceNode(serviceId)
+	if service == nil {
+		return errors.New(fmt.Sprintf("server nod not find ClientDirect2Backend:%v %v %v", serviceType, msgId, serviceId))
+	}
+
+	//压力测试性能使用
+	kvItem, ok := router.ReqAckKVList[msgId]
+	if ok {
+		this.kvTimeLock.Lock()
+		nowTime := util.GetTimeMilliseconds()
+		this.kvBossRewardTime[kvItem.AckMsgId] = append(this.kvBossRewardTime[kvItem.AckMsgId],
+			&TempKVSt{
+				RecvClientKVTime: nowTime,
+				MsgName:          kvItem.ReqMsgName,
+			})
+		this.kvTimeLock.Unlock()
+	}
+
+	//if msgId == 1173 {
+	//	this.kvTimeLock.Lock()
+	//	tmpMsg1, _, _ := rpc.DecodeMessage(msgId, msgData)
+	//	recordTime := tmpMsg1.(*serverproto.CSPlayerBossRewardReq).RecordTimeStamp
+	//	nowTime := util.GetTimeMilliseconds()
+	//	util.DebugF("ClientKVTime=%v nowtime=%v", recordTime, nowTime)
+	//	this.kvBossRewardTime = append(this.kvBossRewardTime, &TempKVSt{
+	//		RecvClientKVTime: nowTime,
+	//		ClientKVTime:     recordTime,
+	//	})
+	//	this.kvTimeLock.Unlock()
+	//}
+
+	//用户ID绑定处理
+	service.Send(&serverproto.GateTransmitAck{
+		MsgId:    uint32(msgId),
+		MsgData:  msgData,
+		ClientId: this.gateID.SessID,
+		SeqId:    seqId,
+		//KvTime:   util.GetTimeMilliseconds(),
+	})
+
+	//短时间内收到大量消息
+	if this.msgTime <= 0 {
+		nowTime := util.GetCurrentTime()
+		this.msgTime = nowTime
+	}
+	this.msgCount++
+	if this.msgCount >= 30 {
+		nowTime := util.GetCurrentTime()
+		if nowTime-this.msgTime <= 5 {
+			this.invalidCount++
+		}
+
+		//log.Printf("msgcount=%v invalidCount=%v deltime=%v", this.msgCount, this.invalidCount, nowTime-this.msgTime)
+		if this.invalidCount >= 3 {
+			this.msgTime = 0
+			this.invalidCount = 0
+			this.msgCount = 0
+			util.ErrorF("ClientDirect2Backend=%v %v %v %v| short time recv too many msg", serviceType, msgId, serviceId, this.OpenId)
+			return errors.New(fmt.Sprintf("ClientDirect2Backend=%v %v %v %v| short time recv too many msg", serviceType, msgId, serviceId, this.OpenId))
+		}
+
+		this.msgTime = nowTime
+		this.msgCount = 0
+	}
+
+	return nil
+}
+
+type PerformKVTimeSt struct {
+	AckMsgId  int32
+	TotalNum  int32
+	CurTime   uint64 //最近这次消耗时间
+	TotalTime uint64
+	MsgName   string
+	BeginTime uint64
+	NowTime   uint64
+	LeftNum   int
+	PerNum    int32
+	MaxPerNum int32
+}
+
+var performTime uint64 = 0
+var performKvTime = map[int32]*PerformKVTimeSt{}
+var performKvLock sync.Mutex
+
+func (this *ClientUser) KvTestBossReward(msgId int32) {
+	nowTime := util.GetTimeMilliseconds()
+	var delTime uint64 = 0
+	leftNum := 0
+	msgName := ""
+	this.kvTimeLock.Lock()
+	if len(this.kvBossRewardTime[msgId]) > 0 {
+		delTime = nowTime - this.kvBossRewardTime[msgId][0].RecvClientKVTime
+		msgName = this.kvBossRewardTime[msgId][0].MsgName
+		this.kvBossRewardTime[msgId] = append(this.kvBossRewardTime[msgId][:0], this.kvBossRewardTime[msgId][1:]...)
+		leftNum = len(this.kvBossRewardTime[msgId])
+	}
+	this.kvTimeLock.Unlock()
+
+	if msgName == "" {
+		return
+	}
+	//if msgId == 1067 {
+	//	util.DebugF("delTimeLimit msgid=%v deltime=%v", msgId, delTime)
+	//}
+
+	var printfList []PerformKVTimeSt
+	performKvLock.Lock()
+	performItem, ok := performKvTime[msgId]
+	if ok {
+		performItem.TotalNum++
+		performItem.TotalTime += delTime
+		performItem.CurTime = delTime
+		performItem.NowTime = uint64(util.GetTimeSeconds())
+		performItem.LeftNum = leftNum
+	} else {
+		performItem = &PerformKVTimeSt{
+			TotalTime: delTime,
+			TotalNum:  1,
+			AckMsgId:  msgId,
+			MsgName:   msgName,
+			BeginTime: uint64(util.GetTimeSeconds()),
+			NowTime:   uint64(util.GetTimeSeconds()),
+			LeftNum:   leftNum,
+			CurTime:   delTime,
+		}
+		performKvTime[msgId] = performItem
+	}
+	tmpPerNum := int32(performItem.NowTime - performItem.BeginTime)
+	if tmpPerNum > 0 {
+		tmpPerNum = performItem.TotalNum / tmpPerNum
+	} else {
+		tmpPerNum = performItem.TotalNum
+	}
+	performItem.PerNum = tmpPerNum
+	if tmpPerNum > performItem.MaxPerNum {
+		performItem.MaxPerNum = tmpPerNum
+	}
+
+	if performTime <= 0 {
+		performTime = nowTime
+	} else if nowTime-performTime >= 1000 {
+		performTime = nowTime
+		for _, val := range performKvTime {
+			printfList = append(printfList, *val)
+		}
+	}
+	performKvLock.Unlock()
+
+	if len(printfList) > 0 {
+		sort.Slice(printfList, func(i, j int) bool {
+			return printfList[i].AckMsgId < printfList[j].AckMsgId
+		})
+		printfListStr := ""
+		for idx := 0; idx < len(printfList); idx++ {
+			//msgIdStr := strconv.Itoa(int(printfList[idx].AckMsgId))
+			tmpTime := float64(printfList[idx].TotalTime) / float64(printfList[idx].TotalNum)
+			printfListStr += "	\n" +
+				strconv.FormatInt(int64(printfList[idx].CurTime), 10) + "-" + strconv.FormatInt(int64(tmpTime), 10) + "(ms)	| " +
+				strconv.FormatInt(int64(printfList[idx].PerNum), 10) + "-" + strconv.FormatInt(int64(printfList[idx].MaxPerNum), 10) + "(num/s) 	| " +
+				strconv.Itoa(int(printfList[idx].TotalNum)) + "(total) 	| " +
+				strconv.Itoa(printfList[idx].LeftNum) + "(left) " + printfList[idx].MsgName
+		}
+		util.DebugF("printfListStr=%v", printfListStr)
+	}
+
+	//if len(this.kvBossRewardTime) > 0 {
+	//	delTime := nowTime - this.kvBossRewardTime[0].ClientKVTime
+	//	delTime1 := nowTime - this.kvBossRewardTime[0].RecvClientKVTime
+	//	delTime2 := this.kvBossRewardTime[0].RecvClientKVTime - this.kvBossRewardTime[0].ClientKVTime
+	//	this.kvIndex++
+	//	//if delTime > 0 {
+	//	//	util.DebugF("kvtime cid=%v idx=%v 1073time=%v", this.ClientSession.ID(), this.kvIndex, delTime)
+	//	//}
+	//	util.DebugF("kvtime cid=%v idx=%v time=%v time1=%v time2=%v | %v", this.ClientSession.ID(),
+	//		this.kvIndex, delTime, delTime1, delTime2,
+	//		this.kvBossRewardTime[0].ClientKVTime, this.kvBossRewardTime[0].RecvClientKVTime)
+	//	this.kvBossRewardTime = append(this.kvBossRewardTime[:0], this.kvBossRewardTime[1:]...)
+	//}
+	//this.kvTimeLock.Unlock()
+}
+
+func (this *ClientUser) ClientDirect2BackendByServiceName(serviceName string, msgId int, seqId uint32, msgData []byte, serviceType string) error {
+	serviceId := this.GetServiceBackend(serviceName)
+	//获得后端服务器节点,并发送
+	service := GetServiceNode(serviceId)
+	if service == nil {
+		return errors.New(fmt.Sprintf("server nod not find[ClientDirect2BackendByServiceName]:%v %v %v", serviceType, msgId, serviceId))
+	}
+
+	//用户ID绑定处理
+	service.Send(&serverproto.GateTransmitAck{
+		MsgId:    uint32(msgId),
+		MsgData:  msgData,
+		ClientId: this.gateID.SessID,
+		SeqId:    seqId,
+	})
+
+	return nil
+}
+
+//gate发送消息到后端指定服务器节点,例如serviceName为game,就是发送到game服务器
+func (this *ClientUser) Client2Backend(serviceName string, msg interface{}) error {
+	serviceId := this.GetServiceBackend(serviceName)
+	//获得后端服务器节点,并发送
+	service := GetServiceNode(serviceId)
+	if service == nil {
+		return errors.New(fmt.Sprintf("server nod not find[Client2Backend]:%v %v", serviceId, msg))
+	}
+
+	msgData, info, err := rpc.EncodeMessage(msg)
+	if err != nil {
+		return err
+	}
+
+	//用户ID绑定处理
+	service.Send(&serverproto.GateTransmitAck{
+		MsgId:    uint32(info.ID),
+		MsgData:  msgData,
+		ClientId: this.gateID.SessID,
+	})
+
+	return nil
+}
+
+func (this *ClientUser) Broadcast2Backend(msg interface{}) {
+	this.serviceNode.RLock()
+	defer this.serviceNode.RUnlock()
+
+	//todo...
+	// 发送到该用户绑定的后端节点上,也许有不同类型的服务器节点需绑定
+	for _, node := range this.ServiceTargets {
+		nodeSess := GetServiceNode(node.ServiceID)
+		if nodeSess != nil {
+			nodeSess.Send(msg)
+		}
+	}
+
+}
+
+//绑定用户需要发送到后台服务器的节点信息
+func (this *ClientUser) SetServiceBackend(serviceName string, serviceID string) {
+	this.serviceNode.Lock()
+	defer this.serviceNode.Unlock()
+	//每种类型的服务只会绑定一个节点
+	if data, ok := this.ServiceTargets[serviceName]; ok {
+		data.ServiceID = serviceID
+		return
+	}
+	this.ServiceTargets[serviceName] = &ServiceBackend{
+		ServiceName: serviceName,
+		ServiceID:   serviceID,
+	}
+}
+
+//根据服务器类型获取后端服务器节点信息
+func (this *ClientUser) GetServiceBackend(serviceName string) string {
+	this.serviceNode.RLock()
+	defer this.serviceNode.RUnlock()
+
+	if data, ok := this.ServiceTargets[serviceName]; ok {
+		return data.ServiceID
+	}
+	return ""
+}
+
+///ClientUserManager
+type ClientUserManager struct {
+	StateMachineCore
+	//reconnectClientList sync.Map //[openId, cli]
+	connectedClientList sync.Map //[Openid, cli]
+}
+
+func NewClientUserManager() *ClientUserManager {
+	mag := &ClientUserManager{
+		connectedClientList: sync.Map{},
+	}
+	mag.InitState()
+
+	return mag
+}
+
+///game节点挂了,踢掉这个game上的玩家
+func (this *ClientUserManager) OnLogicDisJoin(serviceId string) {
+	//todo...
+	//for _,cli :=range this.clientUserList {
+	//	if cli.GetServiceBackend(SERVICE_NODE_TYPE_GAME_STR) == serviceId {
+	//	}
+	//}
+}
+
+func (this *ClientUserManager) AddClient(cliSession rocommon.Session, openId, platform string) *ClientUser {
+	cli := NewUser(cliSession)
+	cli.OpenId = openId
+	cli.Platform = platform
+	cli.SwitchState(CLIENT_STATE_CONNECTED, nil)
+	return cli
+}
+
+func (this *ClientUserManager) GetConnectedFromOpenId(openId, platform string) *ClientUser {
+	openId = ConvertPlatform(openId, platform)
+	//如果是服务器重启可能不存在cliUser,这边需要做判空处理
+	cli, ok := this.connectedClientList.Load(openId)
+	if !ok {
+		return nil
+	}
+
+	cliUser := cli.(*ClientUser)
+	if cliUser != nil {
+		return cliUser
+	}
+	return nil
+}
+
+func (this *ClientUserManager) RemoveConnectedFromOpenId(openId, platform string) {
+	openId = ConvertPlatform(openId, platform)
+	_, ok := this.connectedClientList.Load(openId)
+	if !ok {
+		return
+	}
+	this.connectedClientList.Delete(openId)
+}
+
+func (this *ClientUserManager) ClientUserReBindOpenId(oldOpenId, newOpenid, platform string, cli *ClientUser) {
+	oldOpenId = ConvertPlatform(oldOpenId, platform)
+	newOpenid = ConvertPlatform(newOpenid, platform)
+	this.connectedClientList.Delete(oldOpenId)
+
+	cli.OpenId = newOpenid
+	cli.Platform = platform
+	ClientMag.connectedClientList.Store(newOpenid, cli)
+}

+ 66 - 0
RO_Server_Trunk-branch_0.1.39/roserver/baseserver/model/elastic_log_def.go

@@ -0,0 +1,66 @@
+package model
+
+import (
+	"bytes"
+	"context"
+	"rocommon/service"
+	"rocommon/util"
+	"runtime"
+	"strconv"
+	"time"
+)
+
+type ElasticLogST struct {
+	Uid      uint64    `json:"uid"` //用户唯一ID
+	NickName string    `json:"nickname"`
+	LogTime  time.Time `json:"logtime"`
+	OpenId   string    `json:"openid"`
+	LogType  string    `json:"logtype"`  //日志类型,例如是登录日志,消费日志等
+	LogDesc  string    `json:"logdesc"`  //描述
+	LogLine  string    `json:"logline"`  //代码行信息
+	NodeZone int       `json:"nodezone"` //服务器节点信息
+	NodeId   int       `json:"nodeid"`
+	NodeType int       `json:"nodetype"`
+	Param1   int       `json:"param1"`
+}
+
+/*
+LogType:
+RoleRegister
+RoleOnline
+RoleOnlineNum
+RoleOffline
+*/
+
+//ro index 数据,后续可以添加其他索引模式的log数据
+func ElasticPutLogInfo(logInfo *ElasticLogST) {
+	if service.GetElastic() != nil {
+		//ServerNodeInfo
+		logInfo.NodeZone = service.GetServiceConfig().Node.Zone
+		logInfo.NodeId = service.GetServiceConfig().Node.Id
+		logInfo.NodeType = service.GetServiceConfig().Node.Type
+		logInfo.LogTime = util.GetCurrentTimeNow()
+
+		_, file, line, ok := runtime.Caller(1)
+		if !ok {
+			file = "???"
+			line = 0
+		}
+		strBuf := bytes.NewBufferString(file)
+		strBuf.WriteString(":")
+		strBuf.WriteString(strconv.Itoa(line))
+		logInfo.LogLine = strBuf.String()
+
+		ctx := context.Background()
+		go func() {
+			_, err := service.GetElastic().Index().Index("ro").BodyJson(logInfo).Do(ctx)
+			if err != nil {
+				util.InfoF("ElasticPutLogInfo uuid=%v err=%v", logInfo.Uid, err)
+				return
+			}
+			//util.InfoF("ElasticPutLogInfo logtype= uuid=%v ok line=%v", logInfo.LogType, logInfo.Uid, logInfo.LogLine)
+		}()
+	} else {
+		//util.InfoF("ElasticPutLogInfo uuid=%v elastic is nil", logInfo.Uid)
+	}
+}

+ 145 - 0
RO_Server_Trunk-branch_0.1.39/roserver/baseserver/model/front_proc.go

@@ -0,0 +1,145 @@
+package model
+
+import (
+	"errors"
+	"fmt"
+	"rocommon"
+	"rocommon/rpc"
+	"rocommon/socket"
+	"rocommon/util"
+)
+
+//todo...
+var (
+	GateServiceID    string //gate server id 可以用type,group,id来组合
+	ClientSessionMag socket.SessionManager
+
+	ErrSessionNotFound          = errors.New("session node not found")
+	ErrServiceNodeNotFound      = errors.New("service node not found")
+	ErrServiceNodeSdInfoInvalid = errors.New("service node sd info not found")
+)
+
+func CreateUser(cliSession rocommon.Session, openId, platform string) *ClientUser {
+	//todo...
+	user := ClientMag.AddClient(cliSession, openId, platform)
+
+	//绑定到对应的session上(一个session对应一个玩家)
+	cliSession.(rocommon.ContextSet).SetContextData("user", user, "CreateUser")
+	return user
+}
+
+//session获取用户
+func Session2User(cliSession rocommon.Session) *ClientUser {
+	if cliSession == nil {
+		return nil
+	}
+	if data, ok := cliSession.(rocommon.ContextSet).GetContextData("user"); ok {
+		//todo...
+		//外层有设置nil的地方这边需要判断一下
+		if data == nil {
+			return nil
+		}
+		return data.(*ClientUser)
+	}
+	return nil
+}
+
+func BindUser2Session(cliUser *ClientUser, cliSession rocommon.Session) error {
+	if cliSession == nil {
+		return ErrSessionNotFound
+	}
+
+	oldCli := Session2User(cliSession)
+	//用户已经绑定
+	if oldCli != nil {
+		return errors.New("user has been bind")
+	}
+
+	//绑定到对应的session上(一个session对应一个玩家)
+	cliSession.(rocommon.ContextSet).SetContextData("user", cliUser, "BinUser2Session")
+	cliUser.ClientSession = cliSession
+	return nil
+}
+
+func GetUserBySessionID(sessionID uint64) *ClientUser {
+	return Session2User(ClientSessionMag.GetSession(sessionID))
+}
+
+func GetClientSession(cliSessionId uint64) rocommon.Session {
+	return ClientSessionMag.GetSession(cliSessionId)
+}
+
+//将消息广播列表中的客户端
+func BroadCastClient(uidList []uint64, msg interface{}) {
+	msgData, info, err := rpc.EncodeMessage(msg)
+	if err != nil {
+		return
+	}
+
+	ackMsg := &rocommon.TransmitPacket{
+		MsgData: msgData,
+		MsgId:   uint32(info.ID),
+	}
+	for _, data := range uidList {
+		sess := GetClientSession(data)
+		if sess == nil {
+			continue
+		}
+		sess.Send(ackMsg)
+	}
+}
+
+//绑定客户端连接到后台服务
+//CSLoginReq消息的第一次绑定
+func BindClientToBackendNew(serviceID string, cliSession rocommon.Session, openId, platform string) (*ClientUser, error) {
+	//检查是否存在serviceID对应的服务器(远程服务器的一个连接session)
+	serviceNode := GetServiceNode(serviceID)
+	if serviceNode == nil {
+		return nil, ErrServiceNodeNotFound
+	}
+	//检查服务器节点信息是否存在
+	sd := Session2Context(serviceNode)
+	if sd == nil {
+		return nil, ErrServiceNodeSdInfoInvalid
+	}
+
+	cliUser := Session2User(cliSession)
+	//用户已经绑定
+	if cliUser != nil {
+		return nil, errors.New(fmt.Sprintf("user has been bind:%v", cliUser))
+	}
+
+	cliUser = CreateUser(cliSession, openId, platform)
+	//成功登陆gameserver后,把成功的gameserver写入到数据中(离线数据失效后,删除对应的绑定信息,在gameserver中做处理)
+	cliUser.SetServiceBackend(sd.Name, sd.ID)
+	//log.Println("[BindClientToBackend] success")
+	return cliUser, nil
+}
+
+func BindClientToBackend(serviceID string, cliSession rocommon.Session) (*ClientUser, bool) {
+	cliUser := Session2User(cliSession)
+	util.WarnF("Session2User cliUser=%v", cliUser)
+	if cliUser == nil {
+		return cliUser, false
+	}
+
+	if serviceID == "" {
+		return cliUser, false
+	}
+
+	util.WarnF("BindClientToBackend serviceID=%v", serviceID)
+	serviceNodeSess := GetServiceNode(serviceID)
+	util.WarnF("BindClientToBackend serviceNodeSess=%v", serviceNodeSess)
+	if serviceNodeSess == nil {
+		RemoveServiceNodeByName(serviceID)
+		return cliUser, false
+	}
+
+	sd := Session2Context(serviceNodeSess)
+	if sd == nil {
+		return cliUser, false
+	}
+
+	cliUser.SetServiceBackend(sd.Name, sd.ID)
+	return cliUser, true
+}

+ 27 - 0
RO_Server_Trunk-branch_0.1.39/roserver/baseserver/model/gate_model.go

@@ -0,0 +1,27 @@
+package model
+
+import (
+	"rocommon"
+)
+
+var (
+	updateList []interface{}
+
+	ClientMag *ClientUserManager
+)
+
+type GateUpdate struct {
+	rocommon.UpdateModule //eventqueue.go
+}
+
+func (this *GateUpdate) Init() {
+	//不加到更新列表中,有多线程冲突
+	ClientMag = NewClientUserManager()
+}
+
+func (this *GateUpdate) Update(ms uint64) {
+	//对管理器进行更新操作
+	for _, data := range updateList {
+		data.(rocommon.UpdateLogic).Update(ms)
+	}
+}

+ 190 - 0
RO_Server_Trunk-branch_0.1.39/roserver/baseserver/model/msg.go

@@ -0,0 +1,190 @@
+package model
+
+import (
+	"errors"
+	"fmt"
+	"rocommon"
+	"rocommon/rpc"
+	"rocommon/util"
+	"roserver/serverproto"
+)
+
+///////////////////////////////////////RecvGateMsgEvent
+//recv send event -> ProcEvent
+//来自gate的消息
+type RecvGateMsgEvent struct {
+	Sess     rocommon.Session
+	Message  interface{}
+	ClientID uint64 //当前消息是来自哪个网关的客户端,gate回复消息时使用
+	MsgSeqId uint32
+	KvTime   uint64
+}
+
+func (this *RecvGateMsgEvent) Session() rocommon.Session {
+	return this.Sess
+}
+
+func (this *RecvGateMsgEvent) Msg() interface{} {
+	return this.Message
+}
+func (this *RecvGateMsgEvent) SeqId() uint32 {
+	return this.MsgSeqId
+}
+func (this *RecvGateMsgEvent) KVTime() uint64 {
+	return 0
+}
+
+//接收到消息处理后并回复消息(如果需要回复调用该接口)
+func (this *RecvGateMsgEvent) Replay(msg interface{}) error {
+	data, info, err := rpc.EncodeMessage(msg)
+	if err != nil {
+		return errors.New(fmt.Sprintf("replay msg encode err:%v", err))
+	}
+	//透传给gate服务器,然后再发送给客户端
+	this.Sess.Send(&serverproto.ServiceTransmitAck{
+		MsgId:    uint32(info.ID),
+		MsgData:  data,
+		ClientId: this.ClientID,
+	})
+
+	return nil
+}
+
+///////////////////////////////////////RecvServiceMsgEvent
+//来自game的消息
+type RecvServiceMsgEvent struct {
+	Sess         rocommon.Session
+	Message      interface{}
+	ClientID     uint64
+	ClientIDList []uint64
+	ServiceID    string
+	IsMaster     bool
+}
+
+func (this *RecvServiceMsgEvent) Session() rocommon.Session {
+	return this.Sess
+}
+
+func (this *RecvServiceMsgEvent) Msg() interface{} {
+	return this.Message
+}
+func (this *RecvServiceMsgEvent) SeqId() uint32 {
+	return 0
+}
+func (this *RecvServiceMsgEvent) KVTime() uint64 {
+	return 0
+}
+
+//接收到消息处理后并回复消息(如果需要回复调用该接口)
+func (this *RecvServiceMsgEvent) Replay(msg interface{}) error {
+	data, info, err := rpc.EncodeMessage(msg)
+	if err != nil {
+		return errors.New(fmt.Sprintf("replay msg encode err:%v", err))
+	}
+	//todo...需要重新获取一次sess,session可能不存在
+	this.Sess.Send(&serverproto.ServiceTransmitAck{
+		MsgId:        uint32(info.ID),
+		MsgData:      data,
+		ClientId:     this.ClientID,
+		ClientIdList: this.ClientIDList,
+	})
+
+	return nil
+}
+
+///////////////////////////////////////RecvRouterServiceMsgEvent
+//来自game的消息
+type RecvRouterServiceMsgEvent struct {
+	Sess         rocommon.Session
+	Message      interface{}
+	ClientID     uint64
+	ClientIDList []uint64
+	ServiceID    string
+	IsMaster     bool
+	FromZone     int32
+}
+
+func (this *RecvRouterServiceMsgEvent) Session() rocommon.Session {
+	return this.Sess
+}
+
+func (this *RecvRouterServiceMsgEvent) Msg() interface{} {
+	return this.Message
+}
+func (this *RecvRouterServiceMsgEvent) SeqId() uint32 {
+	return 0
+}
+func (this *RecvRouterServiceMsgEvent) KVTime() uint64 {
+	return 0
+}
+
+//接收到消息处理后并回复消息(如果需要回复调用该接口)
+func (this *RecvRouterServiceMsgEvent) Replay(msg interface{}) error {
+	data, info, err := rpc.EncodeMessage(msg)
+	if err != nil {
+		return errors.New(fmt.Sprintf("replay msg encode err=%v msg=%v", err, msg))
+	}
+
+	this.Sess.Send(&serverproto.ServiceTransmitRouterNtf{
+		MsgId:    uint32(info.ID),
+		MsgData:  data,
+		ClientId: this.ClientID,
+		FromZone: this.FromZone,
+	})
+
+	return nil
+}
+
+func HandleBackendMessage(userHandler func(ev rocommon.ProcEvent, cliID ClientID)) func(ev rocommon.ProcEvent) {
+	return func(e rocommon.ProcEvent) {
+		//util.InfoF("receive msg=%v |%v", e.Msg(), reflect.TypeOf(e.Msg()))
+		switch in := e.(type) {
+		case *RecvGateMsgEvent: //BackendTCPEventHook
+			cId := ClientID{}
+			cId.SessID = in.ClientID
+			if ctx := Session2Context(e.Session()); ctx != nil {
+				cId.ServiceID = ctx.ID
+			}
+			userHandler(in, cId)
+
+			//from benchmark test
+			//begin
+			//tmpInfo := rocommon.MessageInfoByMsg(e.Msg())
+			//tmpData, _ := tmpInfo.Codec.Marshal(e.Msg())
+			//tmpDataStr := base64.StdEncoding.EncodeToString((tmpData).([]byte))
+			//nowTime := util.GetTimeMilliseconds()
+			//if tmpInfo.ID > 1010 {
+			//	util.InfoF("receivemsg msgid=%v msgdata=%v msgtime=%v msg=%v msgtype=%v", tmpInfo.ID, tmpDataStr, nowTime, e.Msg(), reflect.TypeOf(e.Msg()))
+			//}
+			//end
+
+		case *RecvServiceMsgEvent:
+			cId := ClientID{
+				SessID:     in.ClientID,
+				ServiceID:  in.ServiceID, //来自哪个服务器节点的信息
+				SessIdList: in.ClientIDList,
+			}
+			userHandler(in, cId)
+		case *RecvRouterServiceMsgEvent:
+			cId := ClientID{
+				SessID:     in.ClientID,
+				ServiceID:  in.ServiceID, //来自哪个服务器节点的信息
+				SessIdList: in.ClientIDList,
+			}
+			userHandler(in, cId)
+		}
+	}
+}
+
+func ServiceReplay(ev rocommon.ProcEvent, msg interface{}) {
+	if e, ok := ev.(rocommon.ReplayEvent); ok {
+		err := e.Replay(msg)
+		if err != nil {
+			util.InfoF("replay msg err:%v", err.Error())
+		} else {
+			//log.Println("replay msg ok:", msg)
+		}
+	} else {
+		util.PanicF("the given event must be a ReplayEvent!!! msg:%v", msg)
+	}
+}

+ 273 - 0
RO_Server_Trunk-branch_0.1.39/roserver/baseserver/model/orm_common.go

@@ -0,0 +1,273 @@
+package model
+
+import (
+	"encoding/base64"
+	"rocommon"
+	"rocommon/service"
+	"rocommon/util"
+)
+
+const (
+	SDKPlatform_PC        = "PC"
+	SDKPlatform_Quick     = "SDKQuick"
+	SDKPlatform_Hw_Quick  = "SDKHwQuick"
+	SDKPlatform_NBSDK     = "SDKNB"
+	SDKPlatform_UniSDK    = "SDKUni" //SDKUni
+	SDKPlatform_YouYi     = "SDKYOUYI"
+	SDKPlatform_YouYi_IOS = "SDKYOUYI_IOS"
+
+	/* sub_platform
+	changemeng_xjgl    畅梦包
+	changemeng_gdt_xjgl  畅梦广通包
+
+	quick_wy_gzyw 网易quick
+	wangyi_youyi  游易网易
+	*/
+)
+
+const (
+	//服务器关闭/开启注册功能
+	ServerPrefix            = "server:reg"
+	ServerCompetitionPrefix = "server:com"
+
+	//地图通关进度排名
+	MapRankPrefix = "rank:map"
+	//历史最大战力
+	MaxFightPowerRankPrefix = "rank:fight"
+
+	//当前积分排行(用来匹配使用)
+	ArenaRankMatchPrefix = "rank:arenamatch"
+	//当前积分排行(参加过玩家的积分排行)
+	ArenaRankPrefix    = "rank:arena"
+	ArenaPreRankPrefix = "rank:arenapre" //上赛季参赛玩家积分排行列表
+	//积分达到对应段位后的排行(积分下降后从该排行榜中移除)
+	ArenaTopRankPrefix = "rank:arenatop"
+	//rank:arenatop1 历史top排行
+
+	//competition
+	//赛季对应大地图排行数据
+	CompetitionMapRankPrefix         = "rank:comp:map"   //1
+	CompetitionScoreRankPrefix       = "rank:com:score"  //2
+	CompetitionDuoBaoScoreRankPrefix = "rank:com:wheel"  //3
+	CompetitionZhanBuScoreRankPrefix = "rank:com:zhanbu" //4
+	CompetitionIdolScoreRankPrefix   = "rank:com:idol"   //5
+
+	CompetitionIdolBoxRankPrefix  = "rank:com:idolbox"
+	CompetitionIdolFansVotePrefix = "rank:com:idolfans"
+
+	TowerLevelRankPrefix      = "rank:tower"
+	TowerFightpowerRankPrefix = "rank:towerfight"
+
+	CardCollectRankPrefix = "rank:cardcollect"
+
+	KeepSakeCollectRankPrefix = "rank:keepsakecollect"
+
+	//战斗记录(不包括过程数据)
+	BattleRecordMapPrefix = "brecord:map"
+	//战斗过程详细数据,结构序列化数据,key-val格式用来设置过期使用
+	BattleRecordDetailPrefix = "brecord"
+	//验证存储合法性
+	BattleRecordDetailCheckPrefix = "brecord:id"
+
+	//公会base
+	GuildBasePrefix = "guild:guildbase"
+	//公会成员
+	GuildMemberPrefix = "guild:guildmember"
+	//公会申请列表
+	GuildApplyPrefix = "guild:guildapply"
+	//公会日志列表
+	GuildLogPrefix = "guild:guildlog"
+	//玩家申请列表
+	RoleApplyPrefix = "guild:roleapply"
+	//公会名字索引
+	GuildNameIndexPrefix = "guild:nameindex"
+	//公会
+	GuildRoleToGuildPrefix = "guild:roletoguildindex"
+	//公会最新ID
+	GuildCurGuildIdPrefix = "guild:curguildidindex"
+	//公会推荐列表
+	GuildRecommendPrefix = "guild:recommendindex"
+	//公会boss
+	GuildBossPrefix = "guild:bossindex"
+
+	//公会魔王
+	GuildDemonPrefix = "guild:guilddemon"
+	//公会魔王奖励
+	GuildDemonRewardPrefix = "guild:guilddemonreward"
+	//公会魔王,公会最总伤害排名
+	GuildDemonGuildPrefix = "guild:demonguildindex"
+	//公会魔王,公会MVP伤害排名
+	GuildDemonMVPPrefix = "guild:demonmvpindex"
+
+	//爬塔排行榜系统数据
+	RushTowerPrefix = "tower:rushtower"
+	//爬塔最终榜单
+	RushTowerRankPrefix = "tower:rushrank"
+
+	//爬塔排行榜系统数据
+	RushArenaPrefix = "arena:rusharena"
+	//爬塔最终榜单
+	RushArenaRankPrefix = "arena:rushrank"
+
+	//推图冲榜积分榜
+	RushMapScorePrefix = "arena:rushmapscore"
+	//推图冲榜系统数据
+	RushMapPrefix = "arena:rushmap"
+	//推图冲榜最终积分榜
+	RushMapRankPrefix = "arena:rushmaprank"
+	//勇士积分排行榜
+	ExpeditionScoreRankPrefix = "rank:expedition"
+
+	//宠物冲榜相关
+	RushPetScorePrefix = "pet:rushpetscore"
+	//宠物冲榜系统数据
+	RushPetPrefix = "pet:rushpet"
+	//宠物冲榜最终数据
+	RushPetRankPrefix = "pet:rushpetrank"
+	//宠物冲榜,宠物数据
+	RushPetDataPrefix = "pet:rushpetdatarank"
+
+	//技能冲榜相关
+	RushSkillScorePrefix = "pet:rushskillscore"
+	//技能冲榜系统数据
+	RushSkillPrefix = "pet:rushskill"
+	//技能冲榜最终数据
+	RushSkillRankPrefix = "pet:rushskillrank"
+
+	//pay
+	PayOrderPrefix         = "pay"        //所有订单信息
+	PayOrderOKIdListPrefix = "payoklist:" //成功但是没有获取奖励的订单id payoklist:uid
+
+	//百人道场
+	DaoChang100Prefix              = "dc100"          //map有数据表示挑战过该位置(机器人/玩家)
+	DaoChang100RewardPrefix        = "dc100posreward" //list占位奖励列表
+	RoleDaoChang100Prefix          = "role_dc100"     //map
+	RoleDaoChang100LogPrefix       = "role_dc100_log"
+	RoleDaoChang100GuildRankPrefix = "dc100guild"
+	RoleDaoChang100WheeLogPrefix   = "dc100wheel_log" //百人道场转盘日志
+
+	//精彩活动
+	ActivitiesCollectionDataPrefix = "act:num"
+)
+
+// 排行榜每日重置时使用,切记!!!
+func GetRankScoreDailyReset(val uint64, passTime uint64) uint64 {
+	//score
+	var scoreStr = val
+	if scoreStr >= (1 << 40) {
+		scoreStr = (1 << 40) - 1
+	}
+	//时间修改成以一天内的时间
+	tmpTime := util.GetCurrentTimeNow()
+	passTime = uint64(tmpTime.Hour()*60*60+tmpTime.Minute()*60+tmpTime.Second()+tmpTime.Day()) * 1000
+	scoreStr <<= 24
+	scoreStr |= 0xfffffffff - passTime/50
+	return scoreStr
+}
+func GetValByRankScoreDailyReset(score float64) uint64 {
+	val := uint64(score) >> 24
+	return val
+}
+
+// 通用排行榜积分处理
+func GetRankScoreCommon(val uint64, passTime uint64) uint64 {
+	//score
+	var scoreStr = val
+	if scoreStr >= (1 << 28) {
+		scoreStr = (1 << 28) - 1
+	}
+	scoreStr <<= 36
+	scoreStr |= 0xfffffffff - passTime/50
+	return scoreStr
+}
+func GetValByRankScoreCommon(score float64) uint64 {
+	val := uint64(score) >> 36
+	return val
+}
+
+type CompetitionType int32
+
+const (
+	CompetitionType_ZhaoMu CompetitionType = iota + 1 //招募季
+	CompetitionType_XuanBa                            //选拔季 贡献道具获取积分
+	CompetitionType_DuoBao                            //夺宝季 转盘获取积分
+	CompetitionType_ZhanBu                            //占卜季
+	CompetitionType_Idol                              //偶像季
+)
+
+// 数据库相关操作
+func GetMessageFromRedis(module, key string, msg interface{}) error {
+	ret, err := service.GetRedis().Get(module + key).Result()
+	if err != nil {
+		if err != service.NIL {
+			util.InfoF("GetMessageFromRedis get key=%v err=%v\n", module+key, err)
+		}
+		return err
+	}
+	if ret == "" {
+		//util.InfoF("key(%v:%v)->val empty", module, key)
+		return nil
+	}
+
+	return GetDecodeMessage(msg, ret)
+}
+
+func SetMessageToRedis(module, key string, msg interface{}) error {
+	msgData, err := rocommon.GetCodec().Marshal(msg)
+	if err != nil {
+		return err
+	}
+	msgStr := base64.StdEncoding.EncodeToString(msgData.([]byte))
+	ret, err := service.GetRedis().Set(module+key, msgStr, 0).Result()
+	if err != nil {
+		util.InfoF("SetMessageToRedis err=%v ret=%v", module+key, ret)
+		return err
+	}
+	//log.Printf("[SetMessageToRedis] [%v]ret:%v\n", module + key, ret)
+	return nil
+}
+
+func GetEncodeMessage(msg interface{}) (error, string) {
+	msgData, err := rocommon.GetCodec().Marshal(msg)
+	if err != nil {
+		return err, ""
+	}
+	msgStr := base64.StdEncoding.EncodeToString(msgData.([]byte))
+	return nil, msgStr
+}
+
+func GetDecodeMessage(msg interface{}, msgStr string) error {
+	str, err := base64.StdEncoding.DecodeString(msgStr)
+	if err != nil {
+		//log.Printf("[GetMessageFromRedis] [%v] err:%v\n", module + key, err)
+		return err
+	}
+	return rocommon.GetCodec().Unmarshal(str, msg)
+}
+
+func ExistKey(key string) bool {
+	ret, err := service.GetRedis().Exists(key).Result()
+	if err != nil {
+		return false
+	}
+	return ret > 0
+}
+
+func SetDataToRedis(key string, data string) error {
+	ret, err := service.GetRedis().Set(key, data, 0).Result()
+	if err != nil {
+		util.InfoF("[SetDataToRedis] err:[%v]ret:%v", key, ret)
+		return err
+	}
+	//log.Printf("[SetMessageToRedis] [%v]ret:%v\n", module + key, ret)
+	return nil
+}
+
+// 区分不同平台
+func ConvertPlatform(openId, platform string) string {
+	if platform == SDKPlatform_YouYi || platform == SDKPlatform_YouYi_IOS {
+		//除了quick和nb其他渠道都要加上渠道标识
+		openId = platform + openId
+	}
+	return openId
+}

+ 404 - 0
RO_Server_Trunk-branch_0.1.39/roserver/baseserver/model/service_con.go

@@ -0,0 +1,404 @@
+package model
+
+import (
+	"math/rand"
+	"rocommon"
+	"rocommon/service"
+	"rocommon/util"
+	"sync"
+)
+
+//远端服务器节点处理
+
+var (
+	serviceNode sync.RWMutex
+	//服务器节点之间的连接
+	serviceConnBySID = map[string]rocommon.Session{}
+	//跨服router节点使用
+	serviceConnByZone = map[int][]string{} //[zone][sid...]
+	//auth节点另外再存一份一份,提高效率
+	authConnBySID = map[string]rocommon.Session{}
+
+	dbSelectIndex     = 0
+	authSelectIndex   = 0
+	socialSelectIndex = 0
+	gameSelectIndex   = 0
+	mapSelectIndex    = 0
+	bossSelectIndex   = 0
+)
+
+//服务器节点类型枚举
+//服务器类型节点Type:[1 gate] [2 game] [3 db] [4 auth] [5 social chat mail] [10 map] [11 map router] [12 pev] [13 boss]
+//20 crossrouter跨服路由  21crossserver跨服玩家节点
+const (
+	SERVICE_NODE_TYPE_GATE     = 1
+	SERVICE_NODE_TYPE_GATE_STR = "gate"
+
+	SERVICE_NODE_TYPE_GAME     = 2
+	SERVICE_NODE_TYPE_GAME_STR = "game"
+
+	SERVICE_NODE_TYPE_DB     = 3
+	SERVICE_NODE_TYPE_DB_STR = "db"
+
+	SERVICE_NODE_TYPE_AUTH     = 4
+	SERVICE_NODE_TYPE_AUTH_STR = "auth"
+
+	SERVICE_NODE_TYPE_SOCIAL     = 5
+	SERVICE_NODE_TYPE_SOCIAL_STR = "social"
+
+	SERVICE_NODE_TYPE_RANK     = 6
+	SERVICE_NODE_TYPE_RANK_STR = "rank"
+
+	SERVICE_NODE_TYPE_GUILD     = 7
+	SERVICE_NODE_TYPE_GUILD_STR = "guild"
+
+	SERVICE_NODE_TYPE_AOI     = 10
+	SERVICE_NODE_TYPE_AOI_STR = "aoi"
+
+	SERVICE_NODE_TYPE_MAP_ROUTER     = 11
+	SERVICE_NODE_TYPE_MAP_ROUTER_STR = "maprouter"
+
+	SERVICE_NODE_TYPE_PVE     = 12
+	SERVICE_NODE_TYPE_PVE_STR = "pve"
+
+	SERVICE_NODE_TYPE_BOSS     = 13
+	SERVICE_NODE_TYPE_BOSS_STR = "battleboss"
+
+	SERVICE_NODE_TYPE_WEBGM     = 14
+	SERVICE_NODE_TYPE_WEBGM_STR = "gmweb"
+
+	SERVICE_NODE_TYPE_BATTLERECORD     = 15
+	SERVICE_NODE_TYPE_BATTLERECORD_STR = "battlerecord"
+
+	//跨服使用
+	//局部跨服(部分服务器跨服)
+	SERVICE_NODE_TYPE_CROSSROUTER     = 20
+	SERVICE_NODE_TYPE_CROSSROUTER_STR = "crossrouter"
+	SERVICE_NODE_TYPE_CROSSSERVER     = 21
+	SERVICE_NODE_TYPE_CROSSSERVER_STR = "crossserver" //跨服玩法(远航试炼)
+	SERVICE_NODE_TYPE_CROSSRANK       = 22
+	SERVICE_NODE_TYPE_CROSSRANK_STR   = "crossrank" //跨服排行榜
+
+	//全局跨服使用(所有服务器跨服)
+	SERVICE_NODE_TYPE_GLOBALCROSSROUTER     = 30
+	SERVICE_NODE_TYPE_GLOBALCROSSROUTER_STR = "gcrossrouter"
+	SERVICE_NODE_TYPE_GLOBALCROSSMAP        = 31
+	SERVICE_NODE_TYPE_GLOBALCROSSMAP_STR    = "gcrossmap"
+)
+
+//需要加锁处理(后续放到主线程队列中做处理)
+func AddServiceNode(session rocommon.Session, sid, name string, from string) {
+	serviceNode.Lock()
+	defer serviceNode.Unlock()
+
+	serverType, zone, index, err := service.ParseServiceID(sid)
+	if err == nil {
+		session.(rocommon.ContextSet).SetContextData("ctx",
+			&service.ETCDServiceDesc{
+				ID:    sid,
+				Name:  name,
+				Type:  serverType,
+				Zone:  zone,
+				Index: index,
+			}, "AddServiceNode")
+		serviceConnBySID[sid] = session
+		if serverType == SERVICE_NODE_TYPE_SOCIAL {
+			serviceConnByZone[zone] = append(serviceConnByZone[zone], sid)
+		} else if serverType == SERVICE_NODE_TYPE_AUTH {
+			authConnBySID[sid] = session
+		}
+		util.InfoF("[AddServiceNode_%v] %v", from, sid)
+	} else {
+		util.WarnF("[AddServiceNode_%v] %v err:%v", from, sid, err)
+	}
+}
+
+func RemoveServiceNode(session rocommon.Session) string {
+	retSID := ""
+	if session == nil {
+		return retSID
+	}
+
+	ctx := Session2Context(session)
+	if ctx != nil {
+		serviceNode.Lock()
+		delete(serviceConnBySID, ctx.ID)
+		delete(authConnBySID, ctx.ID)
+		zoneNodeList, ok := serviceConnByZone[ctx.Zone]
+		if ok {
+			for idx := 0; idx < len(zoneNodeList); idx++ {
+				if zoneNodeList[idx] == ctx.ID {
+					serviceConnByZone[ctx.Zone] =
+						append(serviceConnByZone[ctx.Zone][:idx], serviceConnByZone[ctx.Zone][idx+1:]...)
+					break
+				}
+			}
+
+		}
+		serviceNode.Unlock()
+		if ctx.Type == SERVICE_NODE_TYPE_GATE {
+			retSID = ctx.ID
+		}
+		retSID = ctx.ID
+		util.InfoF("[RemoveServiceNode]service nod conn removed sessionId:%v sid:%v", session.ID(), ctx.ID)
+	} else {
+		util.InfoF("[RemoveServiceNode]service nod conn removed sessionId:%v", session.ID())
+	}
+	return retSID
+}
+
+func Session2Context(serviceSess rocommon.Session) *service.ETCDServiceDesc {
+	if raw, ok := serviceSess.(rocommon.ContextSet).GetContextData("ctx"); ok {
+		return raw.(*service.ETCDServiceDesc)
+	}
+	return nil
+}
+
+func RemoveServiceNodeByName(sid string) {
+	if sid == "" {
+		return
+	}
+	serviceNode.Lock()
+	delete(serviceConnBySID, sid)
+	_, zone, _, _ := service.ParseServiceID(sid)
+	zoneNodeList, ok := serviceConnByZone[zone]
+	if ok {
+		for idx := 0; idx < len(zoneNodeList); idx++ {
+			if zoneNodeList[idx] == sid {
+				serviceConnByZone[zone] =
+					append(serviceConnByZone[zone][:idx], serviceConnByZone[zone][idx+1:]...)
+				break
+			}
+		}
+
+	}
+	delete(authConnBySID, sid)
+	serviceNode.Unlock()
+}
+
+//给定sid获得和服务器节点连接的session
+func GetServiceNode(sid string) rocommon.Session {
+	serviceNode.RLock()
+	defer serviceNode.RUnlock()
+
+	if sess, ok := serviceConnBySID[sid]; ok {
+		return sess
+	}
+	return nil
+}
+
+//获取指定服务器的节点名称列表
+func GetAllServiceNodeByName(serviceName string) []string {
+	serviceNode.RLock()
+	defer serviceNode.RUnlock()
+
+	var serviceNodeList []string
+	for _, node := range serviceConnBySID {
+		if raw, ok := node.(rocommon.ContextSet).GetContextData("ctx"); ok {
+			sid := raw.(*service.ETCDServiceDesc)
+			if sid.Name == serviceName {
+				serviceNodeList = append(serviceNodeList, sid.ID)
+			}
+		}
+	}
+	return serviceNodeList
+}
+
+//获取指定服务器的index列表
+func GetAllServiceNodeIdByName(serviceName string) []int32 {
+	serviceNode.RLock()
+	defer serviceNode.RUnlock()
+
+	var serviceIdList []int32
+	for _, node := range serviceConnBySID {
+		if raw, ok := node.(rocommon.ContextSet).GetContextData("ctx"); ok {
+			sid := raw.(*service.ETCDServiceDesc)
+			if sid.Name == serviceName {
+				serviceIdList = append(serviceIdList, int32(sid.Index))
+			}
+		}
+	}
+	return serviceIdList
+}
+
+func GetAllSocialServiceNodeByZone(zone int, serviceName string) []string {
+	serviceNode.RLock()
+	defer serviceNode.RUnlock()
+
+	if zoneNodeList, ok := serviceConnByZone[zone]; ok {
+		return zoneNodeList
+	}
+	return nil
+}
+
+func GetAllZoneSocialServiceNode(serviceName string) []string {
+	serviceNode.RLock()
+	defer serviceNode.RUnlock()
+
+	var retNodeList []string
+	for _, node := range serviceConnByZone {
+		if len(node) > 0 {
+			retNodeList = append(retNodeList, node[0])
+		}
+	}
+	return retNodeList
+}
+
+//根据区组中的ID来获取对应服务器类型节点
+func GetServiceNodeById(serviceName string, id int) string {
+	serviceNode.RLock()
+	defer serviceNode.RUnlock()
+
+	for _, node := range serviceConnBySID {
+		if raw, ok := node.(rocommon.ContextSet).GetContextData("ctx"); ok {
+			sid := raw.(*service.ETCDServiceDesc)
+			if sid.Name == serviceName && sid.Index == id {
+				return sid.ID
+			}
+		}
+	}
+	return ""
+}
+
+func GetServiceNodeAndSession(serviceName string, serviceTypeName string, id uint64) (string, rocommon.Session) {
+	if serviceName != "" {
+		tmpSess := GetServiceNode(serviceName)
+		if tmpSess == nil {
+			RemoveServiceNodeByName(serviceName)
+		} else {
+			return serviceName, tmpSess
+		}
+	}
+
+	util.WarnF("GetServiceNodeAndSession serviceTypeName=%v id=%v", serviceTypeName, id)
+	tmpServiceName, tmpSess := SelectServiceNodeAndSession(serviceTypeName, id)
+	util.WarnF("GetServiceNodeAndSession tmpServiceName=%v tmpSess=%v", tmpServiceName, tmpSess)
+	if tmpServiceName != "" {
+		return tmpServiceName, tmpSess
+	} else {
+		return "", nil
+	}
+}
+
+func SelectServiceNodeAndSession(serviceName string, id uint64) (string, rocommon.Session) {
+	serviceNode := SelectServiceNode(serviceName, id)
+	if serviceNode == "" {
+		return serviceNode, nil
+	}
+
+	serviceSess := GetServiceNode(serviceNode)
+	if serviceSess == nil {
+		RemoveServiceNodeByName(serviceNode)
+		for {
+			serviceNode = SelectServiceNode(serviceName, 0)
+			if serviceNode == "" {
+				break
+			}
+			serviceSess = GetServiceNode(serviceNode)
+			if serviceSess == nil {
+				RemoveServiceNodeByName(serviceNode)
+			} else {
+				break
+			}
+		}
+	}
+	return serviceNode, serviceSess
+}
+
+func SelectServiceNode(serviceName string, id uint64) string {
+	if id == 0 {
+		id = uint64(rand.Int31n(100))
+	}
+	switch serviceName {
+	case SERVICE_NODE_TYPE_DB_STR:
+		return selectServiceNode(serviceName, id)
+	case SERVICE_NODE_TYPE_AUTH_STR:
+		return SelectAuthServiceNode(serviceName, id)
+	case SERVICE_NODE_TYPE_SOCIAL_STR:
+		return selectServiceNode(serviceName, id)
+	case SERVICE_NODE_TYPE_GAME_STR:
+		return selectServiceNode(serviceName, id)
+	case SERVICE_NODE_TYPE_AOI_STR:
+		return selectServiceNode(serviceName, id)
+		//return selectAoiServiceNode(serviceName)
+	case SERVICE_NODE_TYPE_MAP_ROUTER_STR:
+		return selectServiceNode(serviceName, id)
+	case SERVICE_NODE_TYPE_BOSS_STR:
+		return selectServiceNode(serviceName, id)
+	case SERVICE_NODE_TYPE_RANK_STR:
+		return selectAoiServiceNode(serviceName)
+	case SERVICE_NODE_TYPE_GUILD_STR:
+		return selectServiceNode(serviceName, id)
+	case SERVICE_NODE_TYPE_BATTLERECORD_STR:
+		return selectServiceNode(serviceName, id)
+	case SERVICE_NODE_TYPE_WEBGM_STR:
+		return selectServiceNode(serviceName, id)
+	case SERVICE_NODE_TYPE_CROSSROUTER_STR:
+		return selectServiceNode(serviceName, id)
+	}
+	return ""
+}
+
+//id确定的某一个服务器节点
+func selectServiceNode(serviceName string, id uint64) string {
+	serviceNode.RLock()
+	defer serviceNode.RUnlock()
+
+	var retIDList []string
+	for _, node := range serviceConnBySID {
+		if raw, ok := node.(rocommon.ContextSet).GetContextData("ctx"); ok {
+			sid := raw.(*service.ETCDServiceDesc)
+			if sid.Name == serviceName {
+				retIDList = append(retIDList, sid.ID)
+			}
+		}
+	}
+	if len(retIDList) <= 0 {
+		return ""
+	}
+	modNum := int(id % uint64(len(retIDList)))
+	return retIDList[modNum]
+}
+
+func SelectAuthServiceNode(serviceName string, sessionId uint64) string {
+	serviceNode.RLock()
+	defer serviceNode.RUnlock()
+
+	nodeLen := len(authConnBySID)
+	if nodeLen <= 0 {
+		return ""
+	}
+	selectIdx := int(sessionId % uint64(nodeLen))
+	idx := 0
+	for _, node := range authConnBySID {
+		if idx == selectIdx {
+			if raw, ok := node.(rocommon.ContextSet).GetContextData("ctx"); ok {
+				sid := raw.(*service.ETCDServiceDesc)
+				if sid.Name == serviceName {
+					//需要通知服务器状态
+					return sid.ID
+				}
+			}
+		}
+		idx++
+	}
+	return ""
+}
+
+//todo..
+// 选择负载较低的节点进入
+func selectAoiServiceNode(serviceName string) string {
+	serviceNode.RLock()
+	defer serviceNode.RUnlock()
+
+	for _, node := range serviceConnBySID {
+		if raw, ok := node.(rocommon.ContextSet).GetContextData("ctx"); ok {
+			sid := raw.(*service.ETCDServiceDesc)
+			if sid.Name == serviceName {
+				//需要通知服务器状态
+				return sid.ID
+			}
+		}
+	}
+	return ""
+}

+ 72 - 0
RO_Server_Trunk-branch_0.1.39/roserver/baseserver/model/state_machine.go

@@ -0,0 +1,72 @@
+package model
+
+import (
+	"rocommon/util"
+)
+
+type StateMachine interface {
+	SwitchState(state int32, data interface{})
+	RegisterState(state int32, proc StateProcessor) bool
+	GetState() int32
+}
+
+const MAX_RECURSIVE = 16 //最大递归层数
+
+type StateProcessor func(sm *StateMachineCore, data interface{}) int32
+type StateMachineCore struct {
+	procMap map[int32]StateProcessor
+	state   int32 //状态
+}
+
+func (this *StateMachineCore) InitState() {
+	this.procMap = map[int32]StateProcessor{}
+	this.state = 0
+}
+
+//状态机切换
+func (this *StateMachineCore) SwitchState(state int32, data interface{}) {
+	this.state = this.procState(state, 1, data)
+}
+
+func (this *StateMachineCore) RegisterState(state int32, proc StateProcessor) bool {
+	if _, ok := this.procMap[state]; ok {
+		util.ErrorF("StateMachineCore has been register")
+		this.procMap[state] = proc
+		return true
+	}
+	this.procMap[state] = proc
+	return true
+}
+
+func (this *StateMachineCore) GetState() int32 {
+	return this.state
+}
+
+//返回值表示下一个状态
+func (this *StateMachineCore) DoState(state int32, data interface{}) int32 {
+	return this.procState(state, 1, data)
+}
+
+//num表示递归累加次数
+func (this *StateMachineCore) procState(state int32, num int32, data interface{}) int32 {
+	if num >= MAX_RECURSIVE {
+		util.PanicF("State machine reach max MAX_RECURSIVE")
+		return state
+	}
+	if this.GetState() == state {
+		return state
+	}
+	if len(this.procMap) <= 0 {
+		return state
+	}
+
+	if proc, ok := this.procMap[state]; !ok {
+		return state
+	} else {
+		newState := proc(this, data)
+		if newState != state {
+			return this.procState(newState, num+1, data)
+		}
+		return state
+	}
+}

+ 468 - 0
RO_Server_Trunk-branch_0.1.39/roserver/baseserver/model/util.go

@@ -0,0 +1,468 @@
+package model
+
+import (
+	"errors"
+	"math/rand"
+	"rocommon/service"
+	"rocommon/util"
+	"roserver/serverproto"
+	"strconv"
+	"strings"
+	"time"
+)
+
+var lastTimeStamp uint64 = 0
+var sequence = 0
+
+const (
+	STAMP_SHIFT_BITS    = 22     //时间戳左移位数
+	ZONE_MASK           = 32768  //2^15 15位->32767
+	ZONE_MASK_MULTI     = 0x7fff //15位
+	SEQUENCE_MASK       = 0xfff  //12位
+	SEQUENCE_BITS       = 12     //序列号位数
+	SEQUENCE_MASK_MULTI = 0xffff
+	//SEQUENCE_BITS_MULTI  = 16 //序列号12位
+	SEQUENCE_BITS_MULTI  = 20 //序列号12位
+	TIMESTAMP_BITS_MULTI = 32 //时间戳占用位数
+	LOGIC_BITS           = 5  //logic ID 5占位
+	LOGIC_MASK           = 0x1f
+	LOGIC_MASK64         = 0x0000000000007fff
+	ZONE_MASK64_MULTI    = 0x000000000000FFC0
+)
+
+//role uuid
+func GenerateUid() uint64 {
+	serviceConfig := service.GetServiceConfig()
+	zone := serviceConfig.Node.Zone
+	id := serviceConfig.Node.Id
+	return GUIDCreate(zone, id)
+}
+func GenerateUidByZone(zone int) uint64 {
+	serviceConfig := service.GetServiceConfig()
+	if zone <= 0 {
+		zone = serviceConfig.Node.Zone
+	}
+	id := serviceConfig.Node.Id
+	return GUIDCreate(zone, id)
+}
+
+func ParseUid(uid uint64) (zone, id int32) {
+	id = int32(uid & LOGIC_MASK)
+	zone = int32((uid >> LOGIC_BITS) & LOGIC_MASK64)
+	return
+}
+
+func GUIDCreate(zone, id int) uint64 {
+	currentTimeStamp := uint64(time.Now().Unix())
+	if lastTimeStamp == 0 {
+		lastTimeStamp = currentTimeStamp
+	}
+
+	//zone[2^12] id[2^8]
+	if zone >= ZONE_MASK || id >= 256 {
+		util.ErrorF("GUIDCreate zone=%v[%v] id=%v[%v] invalid", zone, ZONE_MASK, id, 256)
+		return 0
+	}
+	if lastTimeStamp == currentTimeStamp {
+		sequence++
+		if sequence > SEQUENCE_MASK {
+			//一秒内尝试的数量超过上限
+			return 0
+		}
+	} else {
+		lastTimeStamp = currentTimeStamp
+		sequence = 1
+	}
+
+	//zone 		-> 2^15
+	//logicid 	-> 2^5
+	var uid uint64 = 0
+	//前32位时间戳(秒)
+	uid |= lastTimeStamp << TIMESTAMP_BITS_MULTI
+	//12位序列号
+	uid |= uint64(sequence&SEQUENCE_MASK_MULTI) << SEQUENCE_BITS_MULTI
+	//15位区域id
+	uid |= uint64(zone&ZONE_MASK_MULTI) << LOGIC_BITS
+	//左后是逻辑ID(服务器id)
+	uid |= uint64(id & LOGIC_MASK)
+	return uid
+}
+
+func GUIDCreateTest(zone, id int) uint64 {
+	currentTimeStamp := uint64(time.Now().Unix())
+	if lastTimeStamp == 0 {
+		lastTimeStamp = currentTimeStamp
+	}
+
+	if zone > ZONE_MASK {
+		return 0
+	}
+	if lastTimeStamp == currentTimeStamp {
+		sequence++
+		if sequence > 256 {
+			//一秒内尝试的数量超过上限
+			return 0
+		}
+	} else {
+		lastTimeStamp = currentTimeStamp
+		sequence = 1
+	}
+
+	var uid uint64 = 0
+	//前32位时间戳(秒)
+	uid |= (lastTimeStamp >> 1) << 23
+	//16位序列号
+	uid |= uint64(sequence&SEQUENCE_MASK_MULTI) << 15
+	//8位区域id
+	uid |= uint64(zone&ZONE_MASK_MULTI) << 5
+	//左后是逻辑ID(服务器id)
+	uid |= uint64(id & LOGIC_MASK)
+	return uid
+}
+
+//item id
+var uuidLow uint32 = 0
+var uuidHigh uint32 = 1
+
+func UUIDCreate() uint64 {
+	if uuidLow == 0 {
+		uuidLow = uint32(time.Now().Unix())
+	}
+	uuidHigh++
+	uuid := uint64(uuidHigh)
+	uuid <<= 32
+	uuid += uint64(uuidLow)
+	return uuid
+}
+
+//是否同一天(24点)
+func IsSameDay(source int64) bool {
+	loc := util.GetLoc()
+	nowTime := time.Unix(util.GetTimeSeconds(), 0).In(loc)
+	sourceTime := time.Unix(source, 0).In(loc)
+
+	if nowTime.YearDay() != sourceTime.YearDay() {
+		return true
+	}
+
+	return false
+}
+
+//是否是同一天(24点)
+func IsSameDayMs(sourceMs uint64) int {
+	loc := util.GetLoc()
+	timeS := int64(sourceMs / 1000)
+	timeMS := int64(sourceMs % 1000)
+	tempTime := time.Unix(timeS, timeMS).In(loc)
+	nowTime := time.Unix(util.GetTimeSeconds(), 0).In(loc)
+	nt1 := nowTime.YearDay()
+	nt2 := tempTime.YearDay()
+	if nt1 != nt2 {
+		return nt1 - nt2
+	}
+	return 0
+}
+
+//判断是否是同一天true不天, false同一天(凌晨晨5点)
+func IsDailyResetHour5(sourceMs uint64) bool {
+	if sourceMs <= 0 {
+		return false
+	}
+
+	tempTime := util.GetTimeByUint64(sourceMs)
+	nowTime := util.GetCurrentTimeNow()
+
+	nt1 := nowTime.YearDay()
+	nt2 := tempTime.YearDay()
+	deltaDay := nt1 - nt2
+	if nowTime.Year() != tempTime.Year() {
+		if isLeapYear(tempTime.Year()) {
+			deltaDay = 366 - nt2
+		} else {
+			deltaDay = 365 - nt2
+		}
+		deltaDay += nt1
+	}
+
+	if deltaDay < 0 {
+		return false
+	} else if deltaDay == 0 {
+		if tempTime.Hour() < 5 && nowTime.Hour() >= 5 {
+			return true
+		}
+	} else if deltaDay == 1 {
+		if tempTime.Hour() < 5 || tempTime.Hour() >= 5 && nowTime.Hour() >= 5 {
+			return true
+		}
+	} else {
+		return true
+	}
+
+	return false
+}
+
+func isLeapYear(year int) bool {
+	if year%4 == 0 && year%100 != 0 || year%400 == 0 {
+		return true
+	}
+	return false
+}
+
+func Str2Num(str string) (int, error) {
+	if str == "" {
+		return 0, nil
+	}
+	str = strings.Replace(str, "\u00A0", "", -1)
+	str = strings.Replace(str, "\u0020", "", -1)
+	str = strings.Replace(str, "\u0009", "", -1)
+	num, e := strconv.ParseInt(str, 10, 32)
+	if e != nil {
+		return 0, errors.New("service invalid num convert error:" + str)
+	} else {
+		return int(num), nil
+	}
+}
+
+func Str2NumU64(str string) (uint64, error) {
+	str = strings.Replace(str, "\u00A0", "", -1)
+	str = strings.Replace(str, "\u0020", "", -1)
+	num, e := strconv.ParseUint(str, 10, 64)
+	if e != nil {
+		return 0, errors.New("service invalid num convert error:" + str)
+	} else {
+		return num, nil
+	}
+}
+
+func Str2Float32(str string) (float32, error) {
+	str = strings.Replace(str, "\u00A0", "", -1)
+	str = strings.Replace(str, "\u0020", "", -1)
+	num, e := strconv.ParseFloat(str, 32)
+	if e != nil {
+		return 0, errors.New("service invalid num convert error:" + str)
+	} else {
+		return float32(num), nil
+	}
+}
+
+func Str2Float32_2(str string) (float32, float32) {
+	resList := strings.Split(str, ":")
+	if len(resList) > 1 {
+		resType, _ := Str2Float32(resList[0])
+		resValue, _ := Str2Float32(resList[1])
+		return resType, resValue
+	}
+	return 0, 0
+}
+
+func Str2Res(str string) (int32, int32) {
+	resList := strings.Split(str, ":")
+	if len(resList) > 1 {
+		resType, _ := Str2Num(resList[0])
+		resValue, _ := Str2Num(resList[1])
+		return int32(resType), int32(resValue)
+	}
+	return 0, 0
+}
+func Str2ResBySep(str string, sep string) (int32, int32) {
+	resList := strings.Split(str, sep)
+	if len(resList) > 1 {
+		resType, _ := Str2Num(resList[0])
+		resValue, _ := Str2Num(resList[1])
+		return int32(resType), int32(resValue)
+	}
+	return 0, 0
+}
+
+func Str2Res_3(str string) (int32, int32, int32) {
+	resList := strings.Split(str, ":")
+	if len(resList) >= 3 {
+		value1, _ := Str2Num(resList[0])
+		value2, _ := Str2Num(resList[1])
+		value3, _ := Str2Num(resList[2])
+		return int32(value1), int32(value2), int32(value3)
+	}
+	return 0, 0, 0
+}
+
+func Str2Res_4(str string) (int32, int32, int32, int32) {
+	resList := strings.Split(str, ":")
+	if len(resList) >= 4 {
+		value1, _ := Str2Num(resList[0])
+		value2, _ := Str2Num(resList[1])
+		value3, _ := Str2Num(resList[2])
+		value4, _ := Str2Num(resList[3])
+		return int32(value1), int32(value2), int32(value3), int32(value4)
+	}
+	return 0, 0, 0, 0
+}
+func Str2Res_5(str string) (int32, int32, int32, int32, int32) {
+	resList := strings.Split(str, ":")
+	if len(resList) >= 5 {
+		value1, _ := Str2Num(resList[0])
+		value2, _ := Str2Num(resList[1])
+		value3, _ := Str2Num(resList[2])
+		value4, _ := Str2Num(resList[3])
+		value5, _ := Str2Num(resList[4])
+		return int32(value1), int32(value2), int32(value3), int32(value4), int32(value5)
+	}
+	return 0, 0, 0, 0, 0
+}
+
+//最小堆
+type MinHeap struct {
+	ItemList []int32
+}
+
+func (h *MinHeap) Len() int {
+	return len(h.ItemList)
+}
+func (h *MinHeap) Less(i, j int) bool {
+	return h.ItemList[i] < h.ItemList[j]
+}
+
+func (h *MinHeap) Swap(i, j int) {
+	h.ItemList[i], h.ItemList[j] = h.ItemList[j], h.ItemList[i]
+}
+
+func (h *MinHeap) Push(item interface{}) {
+	h.ItemList = append(h.ItemList, item.(int32))
+}
+func (h *MinHeap) Pop() (ret interface{}) {
+	l := len(h.ItemList)
+	h.ItemList, ret = h.ItemList[:l-1], h.ItemList[l-1]
+	return
+}
+
+//随机打乱数组Fisher-Yates随机置乱算法
+func GenRandomArray(selfArray []int32) []int32 {
+	if len(selfArray) <= 0 {
+		return nil
+	}
+
+	rand.Seed(time.Now().UnixNano())
+	for i := len(selfArray) - 1; i > 0; i-- {
+		randNum := rand.Intn(i + 1)
+		selfArray[i], selfArray[randNum] = selfArray[randNum], selfArray[i]
+	}
+	return selfArray
+}
+func GenRandomArrayByLen(numLen int) []int32 {
+	if numLen <= 0 {
+		return nil
+	}
+
+	rand.Seed(time.Now().UnixNano())
+	var selfArray []int32
+	for idx := 0; idx < numLen; idx++ {
+		selfArray = append(selfArray, int32(idx+1))
+	}
+	for i := len(selfArray) - 1; i > 0; i-- {
+		randNum := rand.Intn(i + 1)
+		selfArray[i], selfArray[randNum] = selfArray[randNum], selfArray[i]
+	}
+	return selfArray
+}
+
+//字符串相似度算法
+func MessageLD(s, t string, ignoreCase bool) int {
+	if ignoreCase {
+		s = strings.ToLower(s)
+		t = strings.ToLower(t)
+	}
+	d := make([][]int, len(s)+1)
+	for i := range d {
+		d[i] = make([]int, len(t)+1)
+	}
+	for i := range d {
+		d[i][0] = i
+	}
+	for j := range d[0] {
+		d[0][j] = j
+	}
+	for j := 1; j <= len(t); j++ {
+		for i := 1; i <= len(s); i++ {
+			if s[i-1] == t[j-1] {
+				d[i][j] = d[i-1][j-1]
+			} else {
+				min := d[i-1][j]
+				if d[i][j-1] < min {
+					min = d[i][j-1]
+				}
+				if d[i-1][j-1] < min {
+					min = d[i-1][j-1]
+				}
+				d[i][j] = min + 1
+			}
+		}
+
+	}
+	return d[len(s)][len(t)]
+}
+
+//二倍均值算法,count剩余个数,amount剩余金额
+func DoubleAverage(count, amount int64) int64 {
+	//最小钱
+	min := int64(1)
+	if count <= 0 {
+		count = 1
+	}
+	if count == 1 {
+		//返回剩余金额
+		return amount
+	}
+
+	//计算最大可用金额,min最小是1分钱,减去的min,下面会加上,避免出现0分钱
+	max := amount - min*count
+	if max < 0 {
+		return 0
+	}
+	//计算最大可用平均值
+	avg := max / count
+	//二倍均值基础加上最小金额,防止0出现,作为上限
+	avg2 := 2*avg + min
+	//随机红包金额序列元素,把二倍均值作为随机的最大数
+	//rand.Seed(time.Now().UnixNano())
+	//加min是为了避免出现0值,上面也减去了min
+	x := rand.Int63n(avg2) + min
+	return x
+}
+
+/*
+使用说明
+	rand.Seed(time.Now().UnixNano())
+	var sumAmount int64 = 0
+	var remainAmount int64 = 2
+	rewardNum := 10
+	for idx := 0; idx < rewardNum; idx++ {
+		delAmount := DoubleAverage(int64(rewardNum-idx), int64(remainAmount))
+		remainAmount -= delAmount
+		sumAmount += delAmount
+		log.Printf("delAmount=%v", delAmount)
+	}
+	log.Printf("sumAmount=%v", sumAmount)
+*/
+
+func Str2ResMapList(strList []string, resList map[int32]int32) {
+	for _, str := range strList {
+		k, v := Str2Res(str)
+		if k <= 0 || v <= 0 {
+			continue
+		}
+		resList[k] += v
+	}
+}
+func Str2ResSliceList(strList []string) []*serverproto.KeyValueType {
+	var outList []*serverproto.KeyValueType
+	for _, str := range strList {
+		k, v := Str2Res(str)
+		if k <= 0 || v <= 0 {
+			continue
+		}
+		outList = append(outList, &serverproto.KeyValueType{
+			Key:   k,
+			Value: v,
+		})
+	}
+	return outList
+}

+ 65 - 0
RO_Server_Trunk-branch_0.1.39/roserver/baseserver/router/msg_router.go

@@ -0,0 +1,65 @@
+package router
+
+import "strings"
+
+var (
+	//消息对应的路由规则,消息流转
+	routeByMsgName = map[string]*MsgRouteRule{}
+	routeByMsgID   = map[int]*MsgRouteRule{}
+)
+
+const (
+	//1局部跨服 2全局跨服
+	CrossMode_Type_Section = 1
+	CrossMode_Type_Global  = 2
+)
+
+//消息路由节点
+type MsgRouteRule struct {
+	MsgName     string //消息名称
+	ServiceName string //路由到的服务器
+	Mod         string
+	MsgID       int
+	CrossMode   int32 //1局部跨服 2全局跨服
+}
+
+type MsgRouteList struct {
+	Rules []*MsgRouteRule
+}
+
+//添加路由信息
+func AddRouteRule(rule *MsgRouteRule) {
+	if rule.MsgID == 0 {
+		panic("routerule msgid = 0, run MakeProto.sh please")
+	}
+
+	//是否需要跨服
+	if strings.Contains(rule.Mod, "cross") {
+		rule.CrossMode = CrossMode_Type_Section
+	}
+	if strings.Contains(rule.Mod, "gcross") {
+		rule.CrossMode = CrossMode_Type_Global
+	}
+
+	routeByMsgName[rule.MsgName] = rule
+	routeByMsgID[rule.MsgID] = rule
+}
+
+func ClearRuteRUle() {
+	routeByMsgName = map[string]*MsgRouteRule{}
+	routeByMsgID = map[int]*MsgRouteRule{}
+}
+
+func GetRuleByMsgID(msgId int) *MsgRouteRule {
+	if rule, ok := routeByMsgID[msgId]; ok {
+		return rule
+	}
+	return nil
+}
+
+func GetRuleByMsgName(msgName string) *MsgRouteRule {
+	if rule, ok := routeByMsgName[msgName]; ok {
+		return rule
+	}
+	return nil
+}

+ 614 - 0
RO_Server_Trunk-branch_0.1.39/roserver/baseserver/router/route_table.go

@@ -0,0 +1,614 @@
+package router
+
+type ReqAckKVInfo struct {
+	ReqMsgId   int32
+	AckMsgId   int32
+	ReqMsgName string
+}
+var(
+	RouteTable = new(MsgRouteList)
+	//req和ack回复确认匹配协议号
+	ReqAckKVList = map[int]ReqAckKVInfo{}
+)
+
+func addRule(name string, service string, mod string, id int) {
+	rule := &MsgRouteRule{
+		MsgName: name,
+		ServiceName: service,
+		Mod: mod,
+		MsgID: id,
+	}
+	RouteTable.Rules = append(RouteTable.Rules, rule)
+	AddRouteRule(rule)
+}
+
+//初始化路由信息,或者从服务器发现etcd中获取
+func init(){
+	addRule("CSLoginReq","game,auth","game",1002)
+	addRule("CSReconnectReq","game","game",1004)
+	addRule("CSCreateRoleReq","game","game",1007)
+	addRule("CSNameReq","game","game",1009)
+	addRule("CSGetServerTimeReq","game","game",1016)
+	addRule("CSAddAttrPointReq","game","game",1020)
+	addRule("CSResetAttrPointReq","game","game",1022)
+	addRule("CSActiveHeadReq","game","game",1025)
+	addRule("CSHeadInfoReq","game","game",1027)
+	addRule("CSSetHeadIdReq","game","game",1029)
+	addRule("CSRenameReq","game","game",1031)
+	addRule("CSChangeHeadFrameReq","game","game",1033)
+	addRule("CSHeadFrameInfoReq","game","game",1035)
+	addRule("CSUseHeadFrameItemReq","game","game",1038)
+	addRule("CSHeroLevelUpReq","game","game",1040)
+	addRule("CSHeroAdvanceReq","game","game",1042)
+	addRule("CSHeroBattleReq","game","game",1044)
+	addRule("CSHeroChipDecomposeReq","game","game",1050)
+	addRule("CSHeroStrengthReq","game","game",1052)
+	addRule("CSHeroChangeJobReq","game","game",1054)
+	addRule("CSHeroFighPowerReq","game","game",1057)
+	addRule("CSHeroResetSkillPointReq","game","game",1059)
+	addRule("CSHeroActiveReq","game","game",1061)
+	addRule("CSEquipForgeReq","game","game",1063)
+	addRule("CSEquipUpReq","game","game",1066)
+	addRule("CSEquipDownReq","game","game",1069)
+	addRule("CSEquipLevelUpAllReq","game","game",1070)
+	addRule("CSEquipSlotLevelUpReq","game","game",1072)
+	addRule("CSCardMountReq","game","game",1074)
+	addRule("CSCardDownReq","game","game",1076)
+	addRule("CSCardComposeReq","game","game",1078)
+	addRule("CSCardDecomposeReq","game","game",1080)
+	addRule("CSUseItemReq","game","game",1085)
+	addRule("CSDelItemReq","game","game",1087)
+	addRule("CSChipComposeReq","game","game",1089)
+	addRule("CSCardUpGradeReq","game","game",1092)
+	addRule("CSCardEquipAllReq","game","game",1094)
+	addRule("CSCardEquipDownReq","game","game",1096)
+	addRule("CSCardUpGradeAllReq","game","game",1098)
+	addRule("CSCardCollectInfoReq","game","game",1100)
+	addRule("CSCardCollectRewardReq","game","game",1102)
+	addRule("CSCardCollectionRankReq","game,rank","game",1105)
+	addRule("CSSkillSlotLevelUpReq","game","game",1109)
+	addRule("CSReplaceSkillReq","game","game",1111)
+	addRule("CSActiveSkillReq","game","game",1113)
+	addRule("CSSwapSkillReq","game","game",1115)
+	addRule("CSSetSkillListReq","game","game",1117)
+	addRule("CSSkillLevelUpReq","game","game",1119)
+	addRule("CSResetSkillLevelReq","game","game",1121)
+	addRule("CSFashionUpReq","game","game",1125)
+	addRule("CSFashionDownReq","game","game",1127)
+	addRule("CSFashionComposeReq","game","game",1129)
+	addRule("CSFashionPaperDecomposeReq","game","game",1131)
+	addRule("CSGetOtherPlayerDetailInfoReq","game,social","game",1143)
+	addRule("CSGetOtherPlayerBriefInfoReq","game","game",1145)
+	addRule("CSPlayerChallengeSummonReq","game,battleboss","game",1150)
+	addRule("CSPlayerChallengeHpReq","game,battleboss","game",1153)
+	addRule("CSPlayerLeaveChallengeReq","game,battleboss","game",1155)
+	addRule("CSPlayerWorldBossListReq","game,battleboss","game",1158)
+	addRule("CSChatMessageReq","game,social,guild","game",1162)
+	addRule("CSChatPlayerStateReq","game,social","game",1165)
+	addRule("CSChatOfflineMsgReq","game,db","game",1167)
+	addRule("CSPlayerIncomeReq","game","game",1171)
+	addRule("CSPlayerBossRewardReq","game","game",1173)
+	addRule("CSPlayerBattleRecordDetailSaveReq","battlerecord","battlerecord",1176)
+	addRule("CSPlayerBattleRecordDetailReq","battlerecord","battlerecord",1178)
+	addRule("CSPlayerBattleRecordReq","game,rank","game",1180)
+	addRule("CSGetMapRankReq","game","game",1183)
+	addRule("CSQuickBattleIncomeReq","game","game",1187)
+	addRule("CSBattleBossFightReq","game","game",1189)
+	addRule("CSEvilRefreshReq","game","game",1191)
+	addRule("CSEvilChallengeReq","game","game",1194)
+	addRule("CSGetTaskRewardReq","game","game",1196)
+	addRule("CSGetTaskScoreRewardReq","game","game",1199)
+	addRule("CSArenaReq","game","game",1203)
+	addRule("CSArenaMatchReq","game","game",1204)
+	addRule("CSArenaResultReq","game","game",1206)
+	addRule("CSArenaBuyCountReq","game","game",1208)
+	addRule("CSArenaRankListReq","game","game",1210)
+	addRule("CSArenaActivityReq","game","game",1212)
+	addRule("CSMailListReq","game","game",1216)
+	addRule("CSMailReadReq","game","game",1218)
+	addRule("CSMailRewardReq","game","game",1220)
+	addRule("CSMailDelReadReq","game","game",1222)
+	addRule("CSCompetitionReq","game","game",1225)
+	addRule("CSCompetitionScoreReq","game","game",1228)
+	addRule("CSShopBuyItemReq","game","game",1230)
+	addRule("CSShopInfoReq","game","game",1232)
+	addRule("CSShopRefreshReq","game","game",1234)
+	addRule("CSFriendReq","game","game",1236)
+	addRule("CSFriendAddReq","game","game",1238)
+	addRule("CSFriendDelReq","game","game",1241)
+	addRule("CSFriendBlackReq","game","game",1244)
+	addRule("CSFriendRecommendReq","game","game",1246)
+	addRule("CSFriendSearchReq","game","game",1249)
+	addRule("CSRoleGuideNtf","game","game",1252)
+	addRule("CSRoleStoryReq","game","game",1254)
+	addRule("CSNewMapCartoonReq","game","game",1256)
+	addRule("CSCompulsoryGuidanceReq","game","game",1258)
+	addRule("CSSignUpInfoReq","game","game",1260)
+	addRule("CSSignUpReq","game","game",1262)
+	addRule("CSClimbingTowerInfoReq","game","game",1264)
+	addRule("CSFriendPassTowerInfoReq","game","game",1266)
+	addRule("CSClimbingTowerBeginReq","game","game",1269)
+	addRule("CSClimbingTowerEndReq","game","game",1271)
+	addRule("CSClimbingTowerRankReq","game","game",1273)
+	addRule("CSOnlineRushInfoReq","game","game",1275)
+	addRule("CSTowerActivityReq","game","game",1277)
+	addRule("CSBuildGuildReq","game,guild","game",1281)
+	addRule("CSDisbandGuildReq","game,guild","game",1283)
+	addRule("CSApplyGuildReq","game,guild","game",1285)
+	addRule("CSQuitGuildReq","game,guild","game",1287)
+	addRule("CSKickGuildMemberReq","game,guild","game",1289)
+	addRule("CSChangeMemberTitleReq","game,guild","game",1292)
+	addRule("CSGuildRenameReq","game,guild","game",1295)
+	addRule("CSGuildReNoticeReq","game,guild","game",1297)
+	addRule("CSSetGuildInfoReq","game,guild","game",1299)
+	addRule("CSGuildLogInfoReq","game,guild","game",1301)
+	addRule("CSGuildApplyDataReq","game,guild","game",1303)
+	addRule("CSApplyInfoHandleReq","game,guild","game",1305)
+	addRule("CSGuildInfoReq","game,guild","game",1308)
+	addRule("CSGetSelfGuildInfoReq","game,guild","game",1310)
+	addRule("CSGuildMemberInfoReq","game,guild","game",1312)
+	addRule("CSRecommendGuildInfoReq","game,guild","game",1314)
+	addRule("CSOnlinePlayerGuildReq","game,guild","game",1316)
+	addRule("CSSearchGuildReq","game,guild","game",1318)
+	addRule("CSGuildBossInfoReq","game,guild","game",1321)
+	addRule("CSGuildBossLogReq","game,guild","game",1323)
+	addRule("CSGuildBossChallengeReq","game,guild","game",1325)
+	addRule("CSGuildBossSummonReq","game,guild","game",1327)
+	addRule("CSGuildBossExtraRewardReq","game,guild","game",1329)
+	addRule("CSPetLevelUpReq","game","game",1334)
+	addRule("CSPetAdvanceReq","game","game",1336)
+	addRule("CSPetSkillLevelUpReq","game","game",1338)
+	addRule("CSPetDecomposeReq","game","game",1340)
+	addRule("CSPetBondListReq","game","game",1342)
+	addRule("CSPetBondAssistListReq","game","game",1345)
+	addRule("CSPetBondActiveReq","game","game",1347)
+	addRule("CSPetAssistReq","game","game",1349)
+	addRule("CSPetBattleReq","game","game",1351)
+	addRule("CSPetManualRewardReq","game","game",1353)
+	addRule("CSPetAdvAchievementReq","game","game",1355)
+	addRule("CSExpeditionChallengePreReq","game","game",1358)
+	addRule("CSExpeditionChallengeReq","game","game",1360)
+	addRule("CSExpeditionSelectBuffReq","game","game",1362)
+	addRule("CSExpeditionRewardReq","game","game",1364)
+	addRule("CSExpeditionBattleHeroReq","game","game",1366)
+	addRule("CSExpeditionCallForHelpReq","game","game",1368)
+	addRule("CSExpeditionHelpReq","game","game",1371)
+	addRule("CSActivitiesRewardReq","game","game",1376)
+	addRule("CSActivitiesScoreRewardReq","game","game",1378)
+	addRule("CSActivitiesFirstChargeRewardReq","game","game",1381)
+	addRule("CSInvitationNumberReq","game","game",1386)
+	addRule("CSInvitationNumberUserInfoReq","game","game",1388)
+	addRule("CSInvitationBeToMemberReq","game","game",1390)
+	addRule("CSInvitationClickReq","game","game",1392)
+	addRule("CSInvitationClickReplayReq","game","game",1394)
+	addRule("CSInvitationDelMemberReq","game","game",1396)
+	addRule("CSInvitationTaskRewardReq","game","game",1398)
+	addRule("CSPayInfoGetReq","game","game",1400)
+	addRule("CSPayInfoOrderOKListGetReq","game","game",1403)
+	addRule("CSDaoChang100PlayerInfoReq","game,rank","game",1406)
+	addRule("CSDaoChang100Req","game","game",1408)
+	addRule("CSDaoChang100LogReq","game","game",1410)
+	addRule("CSDaoChang100ChallengeReq","game","game",1412)
+	addRule("CSDaoChang100ChallengeResultReq","game","game",1414)
+	addRule("CSDaoChang100TimeRewardReq","game","game",1415)
+	addRule("CSDaoChang100BuyChallengeCountReq","game","game",1417)
+	addRule("CSGiftRewardReq","game,social,gmweb","game",1419)
+	addRule("CSGMCommandReq","game","game",1421)
+	addRule("CSDrawCardReq","game","game",1424)
+	addRule("CSRuneShopInfoReq","game","game",1426)
+	addRule("CSAntiCheatReq","game","game",1433)
+	addRule("CSQuestionRewardReq","game","game",1435)
+	addRule("CSClientParamNtf","game","game",1437)
+	addRule("CSMapActivityReq","game","game",1438)
+	addRule("CSHeroReplaceJobReq","game","game",1442)
+	addRule("CSDaoChang100SetTipsReq","game","game",1444)
+	addRule("CSOnlineGetKeepSakeReq","game","game",1446)
+	addRule("CSKeepSakeRankReq","game,rank","game",1448)
+	addRule("CSKeepSakeLevelUpReq","game","game",1450)
+	addRule("CSTowerLevelMinFightPowerReq","game","game",1453)
+	addRule("CSActivitiesCollectionServerDataReq","game","game",1455)
+	addRule("CSGuildBattleInfoReq","game,guild","game",1457)
+	addRule("CSGuildBattleSettingReq","game,guild","game",1460)
+	addRule("CSGuildBattleBuyChallengeReq","game,guild","game",1462)
+	addRule("CSGuildBattleRebornReq","game,guild","game",1464)
+	addRule("CSGuildBattleRankListReq","game,guild","game",1466)
+	addRule("CSGuildBattlePosIdxListReq","game,guild","game",1468)
+	addRule("CSGuildBattleLogReq","game,guild","game",1470)
+	addRule("CSGuildBattleChallengeReq","game","game",1472)
+	addRule("CSGuildBattleChallengeResultReq","game,guild","game",1474)
+	addRule("CSGuildBattleChallengePingReq","game,guild","game",1475)
+	addRule("CSGuildBattlePKDataReq","game,guild","game",1477)
+	addRule("CSGuildBattleBuyBuffReq","game,guild","game",1483)
+	addRule("CSGuildBattleCPRankReq","game","game",1487)
+	addRule("CSGuildBattleCountPartReq","game","game",1489)
+	addRule("CSGuildBattleMvpInfoReq","game","game",1491)
+	addRule("CSGuildBattleMvpDetailReq","game","game",1492)
+	addRule("CSExpeditionScoreRankListReq","game","game",1495)
+	addRule("CSDaoChang100WheelReq","game","game",1497)
+	addRule("CSDaoChang100WheelRefreshReq","game","game",1499)
+	addRule("CSDaoChang100WheelOpenRewardReq","game","game",1501)
+	addRule("CSDaoChang100WheelRewardReq","game","game",1503)
+	addRule("CSDaoChang100WheelCloseRewardReq","game","game",1505)
+	addRule("CSFashionUpLvlReq","game","game",1507)
+	addRule("CSFashionResetAttrReq","game","game",1510)
+	addRule("CSExploreInfoReq","game","game",1513)
+	addRule("CSExploreExtraRewardReq","game","game",1515)
+	addRule("CSExploreRewardReq","game","game",1517)
+	addRule("CSDaoChang100WheelLogReq","game,db","game",1519)
+	addRule("CSAccOnlineRewardReq","game,db","game",1523)
+	addRule("CSOnlineTimeRewardReq","game","game",1525)
+	addRule("CSRedBagExchangeReq","game","game",1528)
+	addRule("CSPetActivityReq","game","game",1530)
+	addRule("CSPetActivityRankReq","game,rank","game",1532)
+	addRule("CSAddQualityPointReq","game","game",1536)
+	addRule("CSExpeditionPassRewardReq","game","game",1538)
+	addRule("CSActivitiesLikabilityRewardReq","game","game",1540)
+	addRule("CSActorAttrGetReq","game","game",1542)
+	addRule("CSPetEquipLevelUpReq","game","game",1546)
+	addRule("CSPetEquipUpReq","game","game",1548)
+	addRule("CSPetEquipDownReq","game","game",1550)
+	addRule("CSCompetitionStarInfoReq","game","game",1552)
+	addRule("CSCompetitionStarCloseRewardReq","game","game",1556)
+	addRule("CSCompetitionStarDivineReq","game","game",1559)
+	addRule("CSConverSkillExpReq","game","game",1561)
+	addRule("CSCrossYuanHangTrialRefreshTrialTypeReq","game","game",1564)
+	addRule("CSCrossYuanHangTrialReq","game","game",1566)
+	addRule("CSCrossYuanHangTrialRewardReq","game","game",1568)
+	addRule("CSCrossYuanHangTrialChallengeReq","game","game",1570)
+	addRule("CSCrossYuanHangTrialChallengeResultReq","game","game",1572)
+	addRule("CSCrossYuanHangTrialRankListReq","game","game",1574)
+	addRule("CSCrossYuanHangTrialViewListReq","game","game",1576)
+	addRule("CSCrossYuanHangTrialViewListOutReq","game","game",1578)
+	addRule("CSActivitiesExchangeReq","game","game",1580)
+	addRule("SCActivitiesExchangeAck","game","game",1581)
+	addRule("CSCrossYuanHangTrialInfoReq","game","game",1589)
+	addRule("CSCrossYuanHangTrialLogReq","game","game",1591)
+	addRule("CSRushActivityReq","game","game",1593)
+	addRule("CSRushActivityRewardReq","game","game",1595)
+	addRule("CSRushSkillActivityRankReq","game,rank","game",1597)
+	addRule("CSActivityWheelRefreshReq","game","game",1599)
+	addRule("CSActivityWheelOpenRewardReq","game","game",1601)
+	addRule("CSActivityWheelRewardReq","game","game",1603)
+	addRule("CSActivityWheelCloseRewardReq","game","game",1605)
+	addRule("CSSkillEquipUpReq","game","game",1608)
+	addRule("CSSkillEquipDownReq","game","game",1611)
+	addRule("CSSkillEquipLevelUpReq","game","game",1613)
+	addRule("CSSkillEquipSlotLevelUpReq","game","game",1615)
+	addRule("CSSkillEquipDecomposeReq","game","game",1617)
+	addRule("CSCrossTopTowerFightListReq","game","game",1620)
+	addRule("CSCrossTopTowerChallengeResultReq","game","game",1622)
+	addRule("CSCrossTopTowerForceWinReq","game","game",1624)
+	addRule("CSCrossTopTowerForceWinRankListReq","game","game",1626)
+	addRule("CSCrossTopTowerChallengeReq","game","game",1628)
+	addRule("CSHeadOperateReq","game","game",1631)
+	addRule("CSHeadDataReq","game","game",1633)
+	addRule("CSGCrossGetServerStateReq","game","game",1635)
+	addRule("CSGCrossPlayerEnterMapReq","game","game",1637)
+	addRule("CSGCrossPlayerLeaveMapReq","game","game",1639)
+	addRule("CSGCrossPlayerMapSyncPosReq","game","game",1640)
+	addRule("CSGCrossPlayerShowInfoReq","game","game",1648)
+	addRule("CSSkillEquipRemadeReq","game","game",1650)
+	addRule("CSSkillEquipPoolReq","game","game",1652)
+	addRule("CSGuildDemonInfoReq","game,guild","game",1654)
+	addRule("CSGuildDemonFightReq","game,guild","game",1656)
+	addRule("CSGuildDemonGuildRankReq","game,guild","game",1658)
+	addRule("CSGuildDemonMVPRankReq","game,guild","game",1660)
+	addRule("CSGuildDemonBuyFightCountReq","game","game",1662)
+	addRule("CSActivitySummonReq","game","game",1664)
+	addRule("CSActivitySignInReq","game","game",1666)
+	addRule("CSSkillEquipShiftReq","game","game",1668)
+	addRule("CSCrossTopTowerChallengeViewInfoReq","game","game",1670)
+	addRule("CSGCrossPlayerMapSyncParamReq","game","game",1672)
+	addRule("CSCompetitionOnVoteReq","game","game",1674)
+	addRule("CSCompetitionSelfFansInfoReq","game","game",1676)
+	addRule("CSCompetitionVoteRankReq","game","game",1678)
+	addRule("CSCompetitionFansRewardRankReq","game","game",1680)
+	addRule("CSCompetitionFansGetRewardReq","game","game",1682)
+	addRule("CSCompetitionFansDayRewardReq","game","game",1684)
+	addRule("CSCompetitionGetPlayerVoteRankReq","game","game",1686)
+	addRule("CSPetDetailInfoReq","game","game",1688)
+	addRule("CSWishBoxUseReq","game","game",1690)
+	addRule("CSWishUnlockSlotReq","game","game",1692)
+	addRule("CSWishSlotReq","game","game",1696)
+	addRule("CSActivitiesWordNoticeSetReq","game","game",1698)
+	addRule("CSPetQiyueSlotUnlockReq","game","game",1701)
+	addRule("CSPetQiyueSlotInReq","game","game",1703)
+	addRule("CSPetQiyueSlotOutReq","game","game",1705)
+	addRule("CSPetQiyueBattlePetAttrReq","game","game",1707)
+	addRule("CSCardLevelExchangeReq","game","game",1709)
+	addRule("CSCombineServerInfoReq","game","game",1712)
+	addRule("SSCrossYuanHangTrialViewListReq","crossserver","crossserver",6002)
+	addRule("SSCrossYuanHangTrialReq","crossserver","crossserver",6004)
+	addRule("SSCrossYuanHangTrialChallengeReq","crossserver","crossserver",6006)
+	addRule("SSCrossYuanHangTrialChallengeResultReq","crossserver","crossserver",6008)
+	addRule("SSCrossYuanHangTrialUpdateRankScoreNtf","crossserver","crossserver",6011)
+	addRule("SSCrossYuanHangTrialRankListReq","crossserver","crossserver",6012)
+	addRule("SSCrossYuanHangTrialInfoReq","crossserver","crossserver",6016)
+	addRule("SSCrossYuanHangTrialSelfReq","crossserver","crossserver",6026)
+	addRule("SSCrossRankUpdateNtf","crossrank","crossrank",6028)
+	addRule("SSCrossRankFightInfoUpdateNtf","crossrank","crossrank",6029)
+	addRule("SSCrossTopTowerMatchFightReq","crossrank","crossrank",6030)
+	addRule("SSCrossTopTowerForceWinRankUpdateNtf","crossrank","crossrank",6032)
+	addRule("SSCrossTopTowerForceWinRankListReq","crossrank","crossrank",6033)
+	addRule("SSGCrossMapEnterReq","gcrossmap","gcrossmap",6035)
+	addRule("SSGCrossMapLeaveReq","gcrossmap","gcrossmap",6037)
+	addRule("SSGCrossMapSyncPosReq","gcrossmap","gcrossmap",6040)
+	addRule("SSGCrossMapOtherUnitShowInfoReq","gcrossmap","gcrossmap",6045)
+	addRule("SSGCrossMapUnitShowUpdateNtf","gcrossmap","gcrossmap",6047)
+	addRule("SSGCrossChatMessageReq","gcrossmap","gcrossmap",6048)
+	addRule("SSGCrossMapSyncParamReq","gcrossmap","gcrossmap",6051)
+
+ 	//req和ack消息映射处理
+	ReqAckKVList[1000] = ReqAckKVInfo{1000, 1001, "CSPingReq|SCPingAck"}
+	ReqAckKVList[1002] = ReqAckKVInfo{1002, 1003, "CSLoginReq|SCLoginAck"}
+	ReqAckKVList[1004] = ReqAckKVInfo{1004, 1005, "CSReconnectReq|SCReconnectAck"}
+	ReqAckKVList[1007] = ReqAckKVInfo{1007, 1008, "CSCreateRoleReq|SCCreateRoleAck"}
+	ReqAckKVList[1009] = ReqAckKVInfo{1009, 1010, "CSNameReq|SCNameAck"}
+	ReqAckKVList[1016] = ReqAckKVInfo{1016, 1017, "CSGetServerTimeReq|SCGetServerTimeAck"}
+	ReqAckKVList[1020] = ReqAckKVInfo{1020, 1021, "CSAddAttrPointReq|SCAddAttrPointAck"}
+	ReqAckKVList[1022] = ReqAckKVInfo{1022, 1023, "CSResetAttrPointReq|SCResetAttrPointAck"}
+	ReqAckKVList[1025] = ReqAckKVInfo{1025, 1026, "CSActiveHeadReq|SCActiveHeadAck"}
+	ReqAckKVList[1027] = ReqAckKVInfo{1027, 1028, "CSHeadInfoReq|SCHeadInfoAck"}
+	ReqAckKVList[1029] = ReqAckKVInfo{1029, 1030, "CSSetHeadIdReq|SCSetHeadIdAck"}
+	ReqAckKVList[1031] = ReqAckKVInfo{1031, 1032, "CSRenameReq|SCRenameAck"}
+	ReqAckKVList[1033] = ReqAckKVInfo{1033, 1034, "CSChangeHeadFrameReq|SCChangeHeadFrameAck"}
+	ReqAckKVList[1035] = ReqAckKVInfo{1035, 1036, "CSHeadFrameInfoReq|SCHeadFrameInfoAck"}
+	ReqAckKVList[1038] = ReqAckKVInfo{1038, 1039, "CSUseHeadFrameItemReq|SCUseHeadFrameItemAck"}
+	ReqAckKVList[1040] = ReqAckKVInfo{1040, 1041, "CSHeroLevelUpReq|SCHeroLevelUpAck"}
+	ReqAckKVList[1042] = ReqAckKVInfo{1042, 1043, "CSHeroAdvanceReq|SCHeroAdvanceAck"}
+	ReqAckKVList[1044] = ReqAckKVInfo{1044, 1045, "CSHeroBattleReq|SCHeroBattleAck"}
+	ReqAckKVList[1050] = ReqAckKVInfo{1050, 1051, "CSHeroChipDecomposeReq|SCHeroChipDecomposeAck"}
+	ReqAckKVList[1052] = ReqAckKVInfo{1052, 1053, "CSHeroStrengthReq|SCHeroStrengthAck"}
+	ReqAckKVList[1054] = ReqAckKVInfo{1054, 1055, "CSHeroChangeJobReq|SCHeroChangeJobAck"}
+	ReqAckKVList[1057] = ReqAckKVInfo{1057, 1058, "CSHeroFighPowerReq|SCHeroFighPowerAck"}
+	ReqAckKVList[1059] = ReqAckKVInfo{1059, 1060, "CSHeroResetSkillPointReq|SCHeroResetSkillPointAck"}
+	ReqAckKVList[1061] = ReqAckKVInfo{1061, 1062, "CSHeroActiveReq|SCHeroActiveAck"}
+	ReqAckKVList[1063] = ReqAckKVInfo{1063, 1064, "CSEquipForgeReq|SCEquipForgeAck"}
+	ReqAckKVList[1066] = ReqAckKVInfo{1066, 1067, "CSEquipUpReq|SCEquipUpAck"}
+	ReqAckKVList[1070] = ReqAckKVInfo{1070, 1071, "CSEquipLevelUpAllReq|SCEquipLevelUpAllAck"}
+	ReqAckKVList[1072] = ReqAckKVInfo{1072, 1073, "CSEquipSlotLevelUpReq|SCEquipSlotLevelUpAck"}
+	ReqAckKVList[1074] = ReqAckKVInfo{1074, 1075, "CSCardMountReq|SCCardMountAck"}
+	ReqAckKVList[1076] = ReqAckKVInfo{1076, 1077, "CSCardDownReq|SCCardDownAck"}
+	ReqAckKVList[1078] = ReqAckKVInfo{1078, 1079, "CSCardComposeReq|SCCardComposeAck"}
+	ReqAckKVList[1080] = ReqAckKVInfo{1080, 1081, "CSCardDecomposeReq|SCCardDecomposeAck"}
+	ReqAckKVList[1085] = ReqAckKVInfo{1085, 1086, "CSUseItemReq|SCUseItemAck"}
+	ReqAckKVList[1087] = ReqAckKVInfo{1087, 1088, "CSDelItemReq|SCDelItemAck"}
+	ReqAckKVList[1089] = ReqAckKVInfo{1089, 1090, "CSChipComposeReq|SCChipComposeAck"}
+	ReqAckKVList[1092] = ReqAckKVInfo{1092, 1093, "CSCardUpGradeReq|SCCardUpGradeAck"}
+	ReqAckKVList[1094] = ReqAckKVInfo{1094, 1095, "CSCardEquipAllReq|SCCardEquipAllAck"}
+	ReqAckKVList[1096] = ReqAckKVInfo{1096, 1097, "CSCardEquipDownReq|SCCardEquipDownAck"}
+	ReqAckKVList[1098] = ReqAckKVInfo{1098, 1099, "CSCardUpGradeAllReq|SCCardUpGradeAllAck"}
+	ReqAckKVList[1100] = ReqAckKVInfo{1100, 1101, "CSCardCollectInfoReq|SCCardCollectInfoAck"}
+	ReqAckKVList[1102] = ReqAckKVInfo{1102, 1103, "CSCardCollectRewardReq|SCCardCollectRewardAck"}
+	ReqAckKVList[1105] = ReqAckKVInfo{1105, 1106, "CSCardCollectionRankReq|SCCardCollectionRankAck"}
+	ReqAckKVList[1109] = ReqAckKVInfo{1109, 1110, "CSSkillSlotLevelUpReq|SCSkillSlotLevelUpAck"}
+	ReqAckKVList[1111] = ReqAckKVInfo{1111, 1112, "CSReplaceSkillReq|SCReplaceSkillAck"}
+	ReqAckKVList[1113] = ReqAckKVInfo{1113, 1114, "CSActiveSkillReq|SCActiveSkillAck"}
+	ReqAckKVList[1115] = ReqAckKVInfo{1115, 1116, "CSSwapSkillReq|SCSwapSkillAck"}
+	ReqAckKVList[1117] = ReqAckKVInfo{1117, 1118, "CSSetSkillListReq|SCSetSkillListAck"}
+	ReqAckKVList[1119] = ReqAckKVInfo{1119, 1120, "CSSkillLevelUpReq|SCSkillLevelUpAck"}
+	ReqAckKVList[1121] = ReqAckKVInfo{1121, 1122, "CSResetSkillLevelReq|SCResetSkillLevelAck"}
+	ReqAckKVList[1125] = ReqAckKVInfo{1125, 1126, "CSFashionUpReq|SCFashionUpAck"}
+	ReqAckKVList[1127] = ReqAckKVInfo{1127, 1128, "CSFashionDownReq|SCFashionDownAck"}
+	ReqAckKVList[1129] = ReqAckKVInfo{1129, 1130, "CSFashionComposeReq|SCFashionComposeAck"}
+	ReqAckKVList[1143] = ReqAckKVInfo{1143, 1144, "CSGetOtherPlayerDetailInfoReq|SCGetOtherPlayerDetailInfoAck"}
+	ReqAckKVList[1145] = ReqAckKVInfo{1145, 1146, "CSGetOtherPlayerBriefInfoReq|SCGetOtherPlayerBriefInfoAck"}
+	ReqAckKVList[1150] = ReqAckKVInfo{1150, 1151, "CSPlayerChallengeSummonReq|SCPlayerChallengeSummonAck"}
+	ReqAckKVList[1158] = ReqAckKVInfo{1158, 1159, "CSPlayerWorldBossListReq|SCPlayerWorldBossListAck"}
+	ReqAckKVList[1162] = ReqAckKVInfo{1162, 1163, "CSChatMessageReq|SCChatMessageAck"}
+	ReqAckKVList[1165] = ReqAckKVInfo{1165, 1166, "CSChatPlayerStateReq|SCChatPlayerStateAck"}
+	ReqAckKVList[1167] = ReqAckKVInfo{1167, 1168, "CSChatOfflineMsgReq|SCChatOfflineMsgAck"}
+	ReqAckKVList[1171] = ReqAckKVInfo{1171, 1172, "CSPlayerIncomeReq|SCPlayerIncomeAck"}
+	ReqAckKVList[1173] = ReqAckKVInfo{1173, 1174, "CSPlayerBossRewardReq|SCPlayerBossRewardAck"}
+	ReqAckKVList[1176] = ReqAckKVInfo{1176, 1177, "CSPlayerBattleRecordDetailSaveReq|SCPlayerBattleRecordDetailSaveAck"}
+	ReqAckKVList[1178] = ReqAckKVInfo{1178, 1179, "CSPlayerBattleRecordDetailReq|SCPlayerBattleRecordDetailAck"}
+	ReqAckKVList[1180] = ReqAckKVInfo{1180, 1181, "CSPlayerBattleRecordReq|SCPlayerBattleRecordAck"}
+	ReqAckKVList[1183] = ReqAckKVInfo{1183, 1184, "CSGetMapRankReq|SCGetMapRankAck"}
+	ReqAckKVList[1185] = ReqAckKVInfo{1185, 1186, "CSBattleResultReq|SCBattleResultAck"}
+	ReqAckKVList[1187] = ReqAckKVInfo{1187, 1188, "CSQuickBattleIncomeReq|SCQuickBattleIncomeAck"}
+	ReqAckKVList[1189] = ReqAckKVInfo{1189, 1190, "CSBattleBossFightReq|SCBattleBossFightAck"}
+	ReqAckKVList[1191] = ReqAckKVInfo{1191, 1192, "CSEvilRefreshReq|SCEvilRefreshAck"}
+	ReqAckKVList[1194] = ReqAckKVInfo{1194, 1195, "CSEvilChallengeReq|SCEvilChallengeAck"}
+	ReqAckKVList[1196] = ReqAckKVInfo{1196, 1197, "CSGetTaskRewardReq|SCGetTaskRewardAck"}
+	ReqAckKVList[1199] = ReqAckKVInfo{1199, 1200, "CSGetTaskScoreRewardReq|SCGetTaskScoreRewardAck"}
+	ReqAckKVList[1204] = ReqAckKVInfo{1204, 1205, "CSArenaMatchReq|SCArenaMatchAck"}
+	ReqAckKVList[1206] = ReqAckKVInfo{1206, 1207, "CSArenaResultReq|SCArenaResultAck"}
+	ReqAckKVList[1208] = ReqAckKVInfo{1208, 1209, "CSArenaBuyCountReq|SCArenaBuyCountAck"}
+	ReqAckKVList[1210] = ReqAckKVInfo{1210, 1211, "CSArenaRankListReq|SCArenaRankListAck"}
+	ReqAckKVList[1212] = ReqAckKVInfo{1212, 1213, "CSArenaActivityReq|SCArenaActivityAck"}
+	ReqAckKVList[1216] = ReqAckKVInfo{1216, 1217, "CSMailListReq|SCMailListAck"}
+	ReqAckKVList[1218] = ReqAckKVInfo{1218, 1219, "CSMailReadReq|SCMailReadAck"}
+	ReqAckKVList[1220] = ReqAckKVInfo{1220, 1221, "CSMailRewardReq|SCMailRewardAck"}
+	ReqAckKVList[1222] = ReqAckKVInfo{1222, 1223, "CSMailDelReadReq|SCMailDelReadAck"}
+	ReqAckKVList[1228] = ReqAckKVInfo{1228, 1229, "CSCompetitionScoreReq|SCCompetitionScoreAck"}
+	ReqAckKVList[1230] = ReqAckKVInfo{1230, 1231, "CSShopBuyItemReq|SCShopBuyItemAck"}
+	ReqAckKVList[1232] = ReqAckKVInfo{1232, 1233, "CSShopInfoReq|SCShopInfoAck"}
+	ReqAckKVList[1234] = ReqAckKVInfo{1234, 1235, "CSShopRefreshReq|SCShopRefreshAck"}
+	ReqAckKVList[1236] = ReqAckKVInfo{1236, 1237, "CSFriendReq|SCFriendAck"}
+	ReqAckKVList[1238] = ReqAckKVInfo{1238, 1239, "CSFriendAddReq|SCFriendAddAck"}
+	ReqAckKVList[1241] = ReqAckKVInfo{1241, 1242, "CSFriendDelReq|SCFriendDelAck"}
+	ReqAckKVList[1244] = ReqAckKVInfo{1244, 1245, "CSFriendBlackReq|SCFriendBlackAck"}
+	ReqAckKVList[1246] = ReqAckKVInfo{1246, 1247, "CSFriendRecommendReq|SCFriendRecommendAck"}
+	ReqAckKVList[1249] = ReqAckKVInfo{1249, 1250, "CSFriendSearchReq|SCFriendSearchAck"}
+	ReqAckKVList[1254] = ReqAckKVInfo{1254, 1255, "CSRoleStoryReq|SCRoleStoryAck"}
+	ReqAckKVList[1256] = ReqAckKVInfo{1256, 1257, "CSNewMapCartoonReq|SCNewMapCartoonAck"}
+	ReqAckKVList[1258] = ReqAckKVInfo{1258, 1259, "CSCompulsoryGuidanceReq|SCCompulsoryGuidanceAck"}
+	ReqAckKVList[1260] = ReqAckKVInfo{1260, 1261, "CSSignUpInfoReq|SCSignUpInfoAck"}
+	ReqAckKVList[1262] = ReqAckKVInfo{1262, 1263, "CSSignUpReq|SCSignUpAck"}
+	ReqAckKVList[1264] = ReqAckKVInfo{1264, 1265, "CSClimbingTowerInfoReq|SCClimbingTowerInfoAck"}
+	ReqAckKVList[1266] = ReqAckKVInfo{1266, 1267, "CSFriendPassTowerInfoReq|SCFriendPassTowerInfoAck"}
+	ReqAckKVList[1269] = ReqAckKVInfo{1269, 1270, "CSClimbingTowerBeginReq|SCClimbingTowerBeginAck"}
+	ReqAckKVList[1271] = ReqAckKVInfo{1271, 1272, "CSClimbingTowerEndReq|SCClimbingTowerEndAck"}
+	ReqAckKVList[1273] = ReqAckKVInfo{1273, 1274, "CSClimbingTowerRankReq|SCClimbingTowerRankAck"}
+	ReqAckKVList[1275] = ReqAckKVInfo{1275, 1276, "CSOnlineRushInfoReq|SCOnlineRushInfoAck"}
+	ReqAckKVList[1277] = ReqAckKVInfo{1277, 1278, "CSTowerActivityReq|SCTowerActivityAck"}
+	ReqAckKVList[1281] = ReqAckKVInfo{1281, 1282, "CSBuildGuildReq|SCBuildGuildAck"}
+	ReqAckKVList[1283] = ReqAckKVInfo{1283, 1284, "CSDisbandGuildReq|SCDisbandGuildAck"}
+	ReqAckKVList[1285] = ReqAckKVInfo{1285, 1286, "CSApplyGuildReq|SCApplyGuildAck"}
+	ReqAckKVList[1287] = ReqAckKVInfo{1287, 1288, "CSQuitGuildReq|SCQuitGuildAck"}
+	ReqAckKVList[1289] = ReqAckKVInfo{1289, 1290, "CSKickGuildMemberReq|SCKickGuildMemberAck"}
+	ReqAckKVList[1292] = ReqAckKVInfo{1292, 1293, "CSChangeMemberTitleReq|SCChangeMemberTitleAck"}
+	ReqAckKVList[1295] = ReqAckKVInfo{1295, 1296, "CSGuildRenameReq|SCGuildRenameAck"}
+	ReqAckKVList[1297] = ReqAckKVInfo{1297, 1298, "CSGuildReNoticeReq|SCGuildReNoticeAck"}
+	ReqAckKVList[1299] = ReqAckKVInfo{1299, 1300, "CSSetGuildInfoReq|SCSetGuildInfoAck"}
+	ReqAckKVList[1301] = ReqAckKVInfo{1301, 1302, "CSGuildLogInfoReq|SCGuildLogInfoAck"}
+	ReqAckKVList[1303] = ReqAckKVInfo{1303, 1304, "CSGuildApplyDataReq|SCGuildApplyDataAck"}
+	ReqAckKVList[1305] = ReqAckKVInfo{1305, 1306, "CSApplyInfoHandleReq|SCApplyInfoHandleAck"}
+	ReqAckKVList[1308] = ReqAckKVInfo{1308, 1309, "CSGuildInfoReq|SCGuildInfoAck"}
+	ReqAckKVList[1310] = ReqAckKVInfo{1310, 1311, "CSGetSelfGuildInfoReq|SCGetSelfGuildInfoAck"}
+	ReqAckKVList[1312] = ReqAckKVInfo{1312, 1313, "CSGuildMemberInfoReq|SCGuildMemberInfoAck"}
+	ReqAckKVList[1314] = ReqAckKVInfo{1314, 1315, "CSRecommendGuildInfoReq|SCRecommendGuildInfoAck"}
+	ReqAckKVList[1316] = ReqAckKVInfo{1316, 1317, "CSOnlinePlayerGuildReq|SCOnlinePlayerGuildAck"}
+	ReqAckKVList[1318] = ReqAckKVInfo{1318, 1319, "CSSearchGuildReq|SCSearchGuildAck"}
+	ReqAckKVList[1321] = ReqAckKVInfo{1321, 1322, "CSGuildBossInfoReq|SCGuildBossInfoAck"}
+	ReqAckKVList[1323] = ReqAckKVInfo{1323, 1324, "CSGuildBossLogReq|SCGuildBossLogAck"}
+	ReqAckKVList[1325] = ReqAckKVInfo{1325, 1326, "CSGuildBossChallengeReq|SCGuildBossChallengeAck"}
+	ReqAckKVList[1327] = ReqAckKVInfo{1327, 1328, "CSGuildBossSummonReq|SCGuildBossSummonAck"}
+	ReqAckKVList[1329] = ReqAckKVInfo{1329, 1330, "CSGuildBossExtraRewardReq|SCGuildBossExtraRewardAck"}
+	ReqAckKVList[1334] = ReqAckKVInfo{1334, 1335, "CSPetLevelUpReq|SCPetLevelUpAck"}
+	ReqAckKVList[1336] = ReqAckKVInfo{1336, 1337, "CSPetAdvanceReq|SCPetAdvanceAck"}
+	ReqAckKVList[1338] = ReqAckKVInfo{1338, 1339, "CSPetSkillLevelUpReq|SCPetSkillLevelUpAck"}
+	ReqAckKVList[1340] = ReqAckKVInfo{1340, 1341, "CSPetDecomposeReq|SCPetDecomposeAck"}
+	ReqAckKVList[1342] = ReqAckKVInfo{1342, 1343, "CSPetBondListReq|SCPetBondListAck"}
+	ReqAckKVList[1345] = ReqAckKVInfo{1345, 1346, "CSPetBondAssistListReq|SCPetBondAssistListAck"}
+	ReqAckKVList[1347] = ReqAckKVInfo{1347, 1348, "CSPetBondActiveReq|SCPetBondActiveAck"}
+	ReqAckKVList[1349] = ReqAckKVInfo{1349, 1350, "CSPetAssistReq|SCPetAssistAck"}
+	ReqAckKVList[1351] = ReqAckKVInfo{1351, 1352, "CSPetBattleReq|SCPetBattleAck"}
+	ReqAckKVList[1353] = ReqAckKVInfo{1353, 1354, "CSPetManualRewardReq|SCPetManualRewardAck"}
+	ReqAckKVList[1355] = ReqAckKVInfo{1355, 1356, "CSPetAdvAchievementReq|SCPetAdvAchievementAck"}
+	ReqAckKVList[1358] = ReqAckKVInfo{1358, 1359, "CSExpeditionChallengePreReq|SCExpeditionChallengePreAck"}
+	ReqAckKVList[1360] = ReqAckKVInfo{1360, 1361, "CSExpeditionChallengeReq|SCExpeditionChallengeAck"}
+	ReqAckKVList[1362] = ReqAckKVInfo{1362, 1363, "CSExpeditionSelectBuffReq|SCExpeditionSelectBuffAck"}
+	ReqAckKVList[1364] = ReqAckKVInfo{1364, 1365, "CSExpeditionRewardReq|SCExpeditionRewardAck"}
+	ReqAckKVList[1366] = ReqAckKVInfo{1366, 1367, "CSExpeditionBattleHeroReq|SCExpeditionBattleHeroAck"}
+	ReqAckKVList[1368] = ReqAckKVInfo{1368, 1369, "CSExpeditionCallForHelpReq|SCExpeditionCallForHelpAck"}
+	ReqAckKVList[1371] = ReqAckKVInfo{1371, 1372, "CSExpeditionHelpReq|SCExpeditionHelpAck"}
+	ReqAckKVList[1376] = ReqAckKVInfo{1376, 1377, "CSActivitiesRewardReq|SCActivitiesRewardAck"}
+	ReqAckKVList[1378] = ReqAckKVInfo{1378, 1379, "CSActivitiesScoreRewardReq|SCActivitiesScoreRewardAck"}
+	ReqAckKVList[1381] = ReqAckKVInfo{1381, 1382, "CSActivitiesFirstChargeRewardReq|SCActivitiesFirstChargeRewardAck"}
+	ReqAckKVList[1386] = ReqAckKVInfo{1386, 1387, "CSInvitationNumberReq|SCInvitationNumberAck"}
+	ReqAckKVList[1388] = ReqAckKVInfo{1388, 1389, "CSInvitationNumberUserInfoReq|SCInvitationNumberUserInfoAck"}
+	ReqAckKVList[1390] = ReqAckKVInfo{1390, 1391, "CSInvitationBeToMemberReq|SCInvitationBeToMemberAck"}
+	ReqAckKVList[1392] = ReqAckKVInfo{1392, 1393, "CSInvitationClickReq|SCInvitationClickAck"}
+	ReqAckKVList[1394] = ReqAckKVInfo{1394, 1395, "CSInvitationClickReplayReq|SCInvitationClickReplayAck"}
+	ReqAckKVList[1396] = ReqAckKVInfo{1396, 1397, "CSInvitationDelMemberReq|SCInvitationDelMemberAck"}
+	ReqAckKVList[1398] = ReqAckKVInfo{1398, 1399, "CSInvitationTaskRewardReq|SCInvitationTaskRewardAck"}
+	ReqAckKVList[1400] = ReqAckKVInfo{1400, 1401, "CSPayInfoGetReq|SCPayInfoGetAck"}
+	ReqAckKVList[1403] = ReqAckKVInfo{1403, 1404, "CSPayInfoOrderOKListGetReq|SCPayInfoOrderOKListGetAck"}
+	ReqAckKVList[1406] = ReqAckKVInfo{1406, 1407, "CSDaoChang100PlayerInfoReq|SCDaoChang100PlayerInfoAck"}
+	ReqAckKVList[1408] = ReqAckKVInfo{1408, 1409, "CSDaoChang100Req|SCDaoChang100Ack"}
+	ReqAckKVList[1410] = ReqAckKVInfo{1410, 1411, "CSDaoChang100LogReq|SCDaoChang100LogAck"}
+	ReqAckKVList[1412] = ReqAckKVInfo{1412, 1413, "CSDaoChang100ChallengeReq|SCDaoChang100ChallengeAck"}
+	ReqAckKVList[1415] = ReqAckKVInfo{1415, 1416, "CSDaoChang100TimeRewardReq|SCDaoChang100TimeRewardAck"}
+	ReqAckKVList[1417] = ReqAckKVInfo{1417, 1418, "CSDaoChang100BuyChallengeCountReq|SCDaoChang100BuyChallengeCountAck"}
+	ReqAckKVList[1419] = ReqAckKVInfo{1419, 1420, "CSGiftRewardReq|SCGiftRewardAck"}
+	ReqAckKVList[1421] = ReqAckKVInfo{1421, 1422, "CSGMCommandReq|SCGMCommandAck"}
+	ReqAckKVList[1424] = ReqAckKVInfo{1424, 1425, "CSDrawCardReq|SCDrawCardAck"}
+	ReqAckKVList[1426] = ReqAckKVInfo{1426, 1427, "CSRuneShopInfoReq|SCRuneShopInfoAck"}
+	ReqAckKVList[1433] = ReqAckKVInfo{1433, 1434, "CSAntiCheatReq|SCAntiCheatAck"}
+	ReqAckKVList[1435] = ReqAckKVInfo{1435, 1436, "CSQuestionRewardReq|SCQuestionRewardAck"}
+	ReqAckKVList[1438] = ReqAckKVInfo{1438, 1439, "CSMapActivityReq|SCMapActivityAck"}
+	ReqAckKVList[1442] = ReqAckKVInfo{1442, 1443, "CSHeroReplaceJobReq|SCHeroReplaceJobAck"}
+	ReqAckKVList[1444] = ReqAckKVInfo{1444, 1445, "CSDaoChang100SetTipsReq|SCDaoChang100SetTipsAck"}
+	ReqAckKVList[1446] = ReqAckKVInfo{1446, 1447, "CSOnlineGetKeepSakeReq|SCOnlineGetKeepSakeAck"}
+	ReqAckKVList[1448] = ReqAckKVInfo{1448, 1449, "CSKeepSakeRankReq|SCKeepSakeRankAck"}
+	ReqAckKVList[1450] = ReqAckKVInfo{1450, 1451, "CSKeepSakeLevelUpReq|SCKeepSakeLevelUpAck"}
+	ReqAckKVList[1453] = ReqAckKVInfo{1453, 1454, "CSTowerLevelMinFightPowerReq|SCTowerLevelMinFightPowerAck"}
+	ReqAckKVList[1455] = ReqAckKVInfo{1455, 1456, "CSActivitiesCollectionServerDataReq|SCActivitiesCollectionServerDataAck"}
+	ReqAckKVList[1457] = ReqAckKVInfo{1457, 1458, "CSGuildBattleInfoReq|SCGuildBattleInfoAck"}
+	ReqAckKVList[1460] = ReqAckKVInfo{1460, 1461, "CSGuildBattleSettingReq|SCGuildBattleSettingAck"}
+	ReqAckKVList[1466] = ReqAckKVInfo{1466, 1467, "CSGuildBattleRankListReq|SCGuildBattleRankListAck"}
+	ReqAckKVList[1468] = ReqAckKVInfo{1468, 1469, "CSGuildBattlePosIdxListReq|SCGuildBattlePosIdxListAck"}
+	ReqAckKVList[1470] = ReqAckKVInfo{1470, 1471, "CSGuildBattleLogReq|SCGuildBattleLogAck"}
+	ReqAckKVList[1472] = ReqAckKVInfo{1472, 1473, "CSGuildBattleChallengeReq|SCGuildBattleChallengeAck"}
+	ReqAckKVList[1477] = ReqAckKVInfo{1477, 1478, "CSGuildBattlePKDataReq|SCGuildBattlePKDataAck"}
+	ReqAckKVList[1483] = ReqAckKVInfo{1483, 1484, "CSGuildBattleBuyBuffReq|SCGuildBattleBuyBuffAck"}
+	ReqAckKVList[1487] = ReqAckKVInfo{1487, 1488, "CSGuildBattleCPRankReq|SCGuildBattleCPRankAck"}
+	ReqAckKVList[1489] = ReqAckKVInfo{1489, 1490, "CSGuildBattleCountPartReq|SCGuildBattleCountPartAck"}
+	ReqAckKVList[1492] = ReqAckKVInfo{1492, 1493, "CSGuildBattleMvpDetailReq|SCGuildBattleMvpDetailAck"}
+	ReqAckKVList[1495] = ReqAckKVInfo{1495, 1496, "CSExpeditionScoreRankListReq|SCExpeditionScoreRankListAck"}
+	ReqAckKVList[1497] = ReqAckKVInfo{1497, 1498, "CSDaoChang100WheelReq|SCDaoChang100WheelAck"}
+	ReqAckKVList[1499] = ReqAckKVInfo{1499, 1500, "CSDaoChang100WheelRefreshReq|SCDaoChang100WheelRefreshAck"}
+	ReqAckKVList[1501] = ReqAckKVInfo{1501, 1502, "CSDaoChang100WheelOpenRewardReq|SCDaoChang100WheelOpenRewardAck"}
+	ReqAckKVList[1503] = ReqAckKVInfo{1503, 1504, "CSDaoChang100WheelRewardReq|SCDaoChang100WheelRewardAck"}
+	ReqAckKVList[1505] = ReqAckKVInfo{1505, 1506, "CSDaoChang100WheelCloseRewardReq|SCDaoChang100WheelCloseRewardAck"}
+	ReqAckKVList[1507] = ReqAckKVInfo{1507, 1508, "CSFashionUpLvlReq|SCFashionUpLvlAck"}
+	ReqAckKVList[1510] = ReqAckKVInfo{1510, 1511, "CSFashionResetAttrReq|SCFashionResetAttrAck"}
+	ReqAckKVList[1513] = ReqAckKVInfo{1513, 1514, "CSExploreInfoReq|SCExploreInfoAck"}
+	ReqAckKVList[1515] = ReqAckKVInfo{1515, 1516, "CSExploreExtraRewardReq|SCExploreExtraRewardAck"}
+	ReqAckKVList[1517] = ReqAckKVInfo{1517, 1518, "CSExploreRewardReq|SCExploreRewardAck"}
+	ReqAckKVList[1519] = ReqAckKVInfo{1519, 1520, "CSDaoChang100WheelLogReq|SCDaoChang100WheelLogAck"}
+	ReqAckKVList[1523] = ReqAckKVInfo{1523, 1524, "CSAccOnlineRewardReq|SCAccOnlineRewardAck"}
+	ReqAckKVList[1525] = ReqAckKVInfo{1525, 1526, "CSOnlineTimeRewardReq|SCOnlineTimeRewardAck"}
+	ReqAckKVList[1528] = ReqAckKVInfo{1528, 1529, "CSRedBagExchangeReq|SCRedBagExchangeAck"}
+	ReqAckKVList[1530] = ReqAckKVInfo{1530, 1531, "CSPetActivityReq|SCPetActivityAck"}
+	ReqAckKVList[1532] = ReqAckKVInfo{1532, 1533, "CSPetActivityRankReq|SCPetActivityRankAck"}
+	ReqAckKVList[1536] = ReqAckKVInfo{1536, 1537, "CSAddQualityPointReq|SCAddQualityPointAck"}
+	ReqAckKVList[1538] = ReqAckKVInfo{1538, 1539, "CSExpeditionPassRewardReq|SCExpeditionPassRewardAck"}
+	ReqAckKVList[1540] = ReqAckKVInfo{1540, 1541, "CSActivitiesLikabilityRewardReq|SCActivitiesLikabilityRewardAck"}
+	ReqAckKVList[1542] = ReqAckKVInfo{1542, 1543, "CSActorAttrGetReq|SCActorAttrGetAck"}
+	ReqAckKVList[1546] = ReqAckKVInfo{1546, 1547, "CSPetEquipLevelUpReq|SCPetEquipLevelUpAck"}
+	ReqAckKVList[1550] = ReqAckKVInfo{1550, 1551, "CSPetEquipDownReq|SCPetEquipDownAck"}
+	ReqAckKVList[1552] = ReqAckKVInfo{1552, 1553, "CSCompetitionStarInfoReq|SCCompetitionStarInfoAck"}
+	ReqAckKVList[1556] = ReqAckKVInfo{1556, 1557, "CSCompetitionStarCloseRewardReq|SCCompetitionStarCloseRewardAck"}
+	ReqAckKVList[1559] = ReqAckKVInfo{1559, 1560, "CSCompetitionStarDivineReq|SCCompetitionStarDivineAck"}
+	ReqAckKVList[1561] = ReqAckKVInfo{1561, 1562, "CSConverSkillExpReq|SCConverSkillExpAck"}
+	ReqAckKVList[1564] = ReqAckKVInfo{1564, 1565, "CSCrossYuanHangTrialRefreshTrialTypeReq|SCCrossYuanHangTrialRefreshTrialTypeAck"}
+	ReqAckKVList[1566] = ReqAckKVInfo{1566, 1567, "CSCrossYuanHangTrialReq|SCCrossYuanHangTrialAck"}
+	ReqAckKVList[1568] = ReqAckKVInfo{1568, 1569, "CSCrossYuanHangTrialRewardReq|SCCrossYuanHangTrialRewardAck"}
+	ReqAckKVList[1570] = ReqAckKVInfo{1570, 1571, "CSCrossYuanHangTrialChallengeReq|SCCrossYuanHangTrialChallengeAck"}
+	ReqAckKVList[1572] = ReqAckKVInfo{1572, 1573, "CSCrossYuanHangTrialChallengeResultReq|SCCrossYuanHangTrialChallengeResultAck"}
+	ReqAckKVList[1574] = ReqAckKVInfo{1574, 1575, "CSCrossYuanHangTrialRankListReq|SCCrossYuanHangTrialRankListAck"}
+	ReqAckKVList[1576] = ReqAckKVInfo{1576, 1577, "CSCrossYuanHangTrialViewListReq|SCCrossYuanHangTrialViewListAck"}
+	ReqAckKVList[1580] = ReqAckKVInfo{1580, 1581, "CSActivitiesExchangeReq|SCActivitiesExchangeAck"}
+	ReqAckKVList[1589] = ReqAckKVInfo{1589, 1590, "CSCrossYuanHangTrialInfoReq|SCCrossYuanHangTrialInfoAck"}
+	ReqAckKVList[1591] = ReqAckKVInfo{1591, 1592, "CSCrossYuanHangTrialLogReq|SCCrossYuanHangTrialLogAck"}
+	ReqAckKVList[1593] = ReqAckKVInfo{1593, 1594, "CSRushActivityReq|SCRushActivityAck"}
+	ReqAckKVList[1595] = ReqAckKVInfo{1595, 1596, "CSRushActivityRewardReq|SCRushActivityRewardAck"}
+	ReqAckKVList[1597] = ReqAckKVInfo{1597, 1598, "CSRushSkillActivityRankReq|SCRushSkillActivityRankAck"}
+	ReqAckKVList[1599] = ReqAckKVInfo{1599, 1600, "CSActivityWheelRefreshReq|SCActivityWheelRefreshAck"}
+	ReqAckKVList[1601] = ReqAckKVInfo{1601, 1602, "CSActivityWheelOpenRewardReq|SCActivityWheelOpenRewardAck"}
+	ReqAckKVList[1603] = ReqAckKVInfo{1603, 1604, "CSActivityWheelRewardReq|SCActivityWheelRewardAck"}
+	ReqAckKVList[1605] = ReqAckKVInfo{1605, 1606, "CSActivityWheelCloseRewardReq|SCActivityWheelCloseRewardAck"}
+	ReqAckKVList[1608] = ReqAckKVInfo{1608, 1609, "CSSkillEquipUpReq|SCSkillEquipUpAck"}
+	ReqAckKVList[1611] = ReqAckKVInfo{1611, 1612, "CSSkillEquipDownReq|SCSkillEquipDownAck"}
+	ReqAckKVList[1613] = ReqAckKVInfo{1613, 1614, "CSSkillEquipLevelUpReq|SCSkillEquipLevelUpAck"}
+	ReqAckKVList[1615] = ReqAckKVInfo{1615, 1616, "CSSkillEquipSlotLevelUpReq|SCSkillEquipSlotLevelUpAck"}
+	ReqAckKVList[1617] = ReqAckKVInfo{1617, 1618, "CSSkillEquipDecomposeReq|SCSkillEquipDecomposeAck"}
+	ReqAckKVList[1620] = ReqAckKVInfo{1620, 1621, "CSCrossTopTowerFightListReq|SCCrossTopTowerFightListAck"}
+	ReqAckKVList[1622] = ReqAckKVInfo{1622, 1623, "CSCrossTopTowerChallengeResultReq|SCCrossTopTowerChallengeResultAck"}
+	ReqAckKVList[1624] = ReqAckKVInfo{1624, 1625, "CSCrossTopTowerForceWinReq|SCCrossTopTowerForceWinAck"}
+	ReqAckKVList[1626] = ReqAckKVInfo{1626, 1627, "CSCrossTopTowerForceWinRankListReq|SCCrossTopTowerForceWinRankListAck"}
+	ReqAckKVList[1628] = ReqAckKVInfo{1628, 1629, "CSCrossTopTowerChallengeReq|SCCrossTopTowerChallengeAck"}
+	ReqAckKVList[1631] = ReqAckKVInfo{1631, 1632, "CSHeadOperateReq|SCHeadOperateAck"}
+	ReqAckKVList[1633] = ReqAckKVInfo{1633, 1634, "CSHeadDataReq|SCHeadDataAck"}
+	ReqAckKVList[1635] = ReqAckKVInfo{1635, 1636, "CSGCrossGetServerStateReq|SCGCrossGetServerStateAck"}
+	ReqAckKVList[1637] = ReqAckKVInfo{1637, 1638, "CSGCrossPlayerEnterMapReq|SCGCrossPlayerEnterMapAck"}
+	ReqAckKVList[1650] = ReqAckKVInfo{1650, 1651, "CSSkillEquipRemadeReq|SCSkillEquipRemadeAck"}
+	ReqAckKVList[1652] = ReqAckKVInfo{1652, 1653, "CSSkillEquipPoolReq|SCSkillEquipPoolAck"}
+	ReqAckKVList[1654] = ReqAckKVInfo{1654, 1655, "CSGuildDemonInfoReq|SCGuildDemonInfoAck"}
+	ReqAckKVList[1656] = ReqAckKVInfo{1656, 1657, "CSGuildDemonFightReq|SCGuildDemonFightAck"}
+	ReqAckKVList[1658] = ReqAckKVInfo{1658, 1659, "CSGuildDemonGuildRankReq|SCGuildDemonGuildRankAck"}
+	ReqAckKVList[1660] = ReqAckKVInfo{1660, 1661, "CSGuildDemonMVPRankReq|SCGuildDemonMVPRankAck"}
+	ReqAckKVList[1662] = ReqAckKVInfo{1662, 1663, "CSGuildDemonBuyFightCountReq|SCGuildDemonBuyFightCountAck"}
+	ReqAckKVList[1664] = ReqAckKVInfo{1664, 1665, "CSActivitySummonReq|SCActivitySummonAck"}
+	ReqAckKVList[1666] = ReqAckKVInfo{1666, 1667, "CSActivitySignInReq|SCActivitySignInAck"}
+	ReqAckKVList[1668] = ReqAckKVInfo{1668, 1669, "CSSkillEquipShiftReq|SCSkillEquipShiftAck"}
+	ReqAckKVList[1670] = ReqAckKVInfo{1670, 1671, "CSCrossTopTowerChallengeViewInfoReq|SCCrossTopTowerChallengeViewInfoAck"}
+	ReqAckKVList[1674] = ReqAckKVInfo{1674, 1675, "CSCompetitionOnVoteReq|SCCompetitionOnVoteAck"}
+	ReqAckKVList[1676] = ReqAckKVInfo{1676, 1677, "CSCompetitionSelfFansInfoReq|SCCompetitionSelfFansInfoAck"}
+	ReqAckKVList[1678] = ReqAckKVInfo{1678, 1679, "CSCompetitionVoteRankReq|SCCompetitionVoteRankAck"}
+	ReqAckKVList[1680] = ReqAckKVInfo{1680, 1681, "CSCompetitionFansRewardRankReq|SCCompetitionFansRewardRankAck"}
+	ReqAckKVList[1682] = ReqAckKVInfo{1682, 1683, "CSCompetitionFansGetRewardReq|SCCompetitionFansGetRewardAck"}
+	ReqAckKVList[1684] = ReqAckKVInfo{1684, 1685, "CSCompetitionFansDayRewardReq|SCCompetitionFansDayRewardAck"}
+	ReqAckKVList[1686] = ReqAckKVInfo{1686, 1687, "CSCompetitionGetPlayerVoteRankReq|SCCompetitionGetPlayerVoteRankAck"}
+	ReqAckKVList[1688] = ReqAckKVInfo{1688, 1689, "CSPetDetailInfoReq|SCPetDetailInfoAck"}
+	ReqAckKVList[1690] = ReqAckKVInfo{1690, 1691, "CSWishBoxUseReq|SCWishBoxUseAck"}
+	ReqAckKVList[1698] = ReqAckKVInfo{1698, 1699, "CSActivitiesWordNoticeSetReq|SCActivitiesWordNoticeSetAck"}
+	ReqAckKVList[1701] = ReqAckKVInfo{1701, 1702, "CSPetQiyueSlotUnlockReq|SCPetQiyueSlotUnlockAck"}
+	ReqAckKVList[1703] = ReqAckKVInfo{1703, 1704, "CSPetQiyueSlotInReq|SCPetQiyueSlotInAck"}
+	ReqAckKVList[1705] = ReqAckKVInfo{1705, 1706, "CSPetQiyueSlotOutReq|SCPetQiyueSlotOutAck"}
+	ReqAckKVList[1707] = ReqAckKVInfo{1707, 1708, "CSPetQiyueBattlePetAttrReq|SCPetQiyueBattlePetAttrAck"}
+	ReqAckKVList[1709] = ReqAckKVInfo{1709, 1710, "CSCardLevelExchangeReq|SCCardLevelExchangeAck"}
+	ReqAckKVList[1712] = ReqAckKVInfo{1712, 1713, "CSCombineServerInfoReq|SCCombineServerInfoAck"}
+}

+ 152 - 0
RO_Server_Trunk-branch_0.1.39/roserver/baseserver/set/set.go

@@ -0,0 +1,152 @@
+// Package set provides both threadsafe and non-threadsafe implementations of
+// a generic set data structure. In the threadsafe set, safety encompasses all
+// operations on one set. Operations on multiple sets are consistent in that
+// the elements of each set used was valid at exactly one point in time
+// between the start and the end of the operation.
+package set
+
+// SetType denotes which type of set is created. ThreadSafe or NonThreadSafe
+type SetType int
+
+const (
+	ThreadSafe = iota
+	NonThreadSafe
+)
+
+func (s SetType) String() string {
+	switch s {
+	case ThreadSafe:
+		return "ThreadSafe"
+	case NonThreadSafe:
+		return "NonThreadSafe"
+	}
+	return ""
+}
+
+// Interface is describing a Set. Sets are an unordered, unique list of values.
+type Interface interface {
+	Add(items ...interface{})
+	Remove(items ...interface{})
+	Pop() interface{}
+	Has(items ...interface{}) bool
+	Size() int
+	Clear()
+	IsEmpty() bool
+	IsEqual(s Interface) bool
+	IsSubset(s Interface) bool
+	IsSuperset(s Interface) bool
+	Each(func(interface{}) bool)
+	String() string
+	List() []interface{}
+	Copy() Interface
+	CopyWithOut(set2 Interface, sets ...Interface) Interface
+	Merge(s Interface)
+	Separate(s Interface)
+}
+
+// helpful to not write everywhere struct{}{}
+var keyExists = struct{}{}
+
+// New creates and initalizes a new Set interface. Its single parameter
+// denotes the type of set to create. Either ThreadSafe or
+// NonThreadSafe. The default is ThreadSafe.
+func New(settype SetType) Interface {
+	if settype == NonThreadSafe {
+		return newNonTS()
+	}
+	return newTS()
+}
+
+// Union is the merger of multiple sets. It returns a new set with all the
+// elements present in all the sets that are passed.
+//
+// The dynamic type of the returned set is determined by the first passed set's
+// implementation of the New() method.
+func Union(set1, set2 Interface, sets ...Interface) Interface {
+	u := set1.Copy()
+	set2.Each(func(item interface{}) bool {
+		u.Add(item)
+		return true
+	})
+	for _, set := range sets {
+		set.Each(func(item interface{}) bool {
+			u.Add(item)
+			return true
+		})
+	}
+
+	return u
+}
+
+// Difference returns a new set which contains items which are in in the first
+// set but not in the others. Unlike the Difference() method you can use this
+// function separately with multiple sets.
+func Difference(set1, set2 Interface, sets ...Interface) Interface {
+	//return set1.CopyWithOut(set2, sets...)
+
+	s := set1.Copy()
+	s.Separate(set2)
+	for _, set := range sets {
+		s.Separate(set) // seperate is thread safe
+	}
+	return s
+
+}
+
+// Intersection returns a new set which contains items that only exist in all given sets.
+func Intersection(set1, set2 Interface, sets ...Interface) Interface {
+	all := Union(set1, set2, sets...)
+	result := Union(set1, set2, sets...)
+
+	all.Each(func(item interface{}) bool {
+		if !set1.Has(item) || !set2.Has(item) {
+			result.Remove(item)
+		}
+
+		for _, set := range sets {
+			if !set.Has(item) {
+				result.Remove(item)
+			}
+		}
+		return true
+	})
+	return result
+}
+
+// SymmetricDifference returns a new set which s is the difference of items which are in
+// one of either, but not in both.
+func SymmetricDifference(s Interface, t Interface) Interface {
+	u := Difference(s, t)
+	v := Difference(t, s)
+	return Union(u, v)
+}
+
+// StringSlice is a helper function that returns a slice of strings of s. If
+// the set contains mixed types of items only items of type string are returned.
+func StringSlice(s Interface) []string {
+	slice := make([]string, 0)
+	for _, item := range s.List() {
+		v, ok := item.(string)
+		if !ok {
+			continue
+		}
+
+		slice = append(slice, v)
+	}
+	return slice
+}
+
+// IntSlice is a helper function that returns a slice of ints of s. If
+// the set contains mixed types of items only items of type int are returned.
+func IntSlice(s Interface) []int {
+	slice := make([]int, 0)
+	for _, item := range s.List() {
+		v, ok := item.(int)
+		if !ok {
+			continue
+		}
+
+		slice = append(slice, v)
+	}
+	return slice
+}

+ 225 - 0
RO_Server_Trunk-branch_0.1.39/roserver/baseserver/set/set_nots.go

@@ -0,0 +1,225 @@
+package set
+
+import (
+	"fmt"
+	"strings"
+)
+
+// Provides a common set baseline for both threadsafe and non-ts Sets.
+type set struct {
+	m         map[interface{}]struct{} // struct{} doesn't take up space
+	lenChange bool                     //List 做缓存
+	list      []interface{}
+}
+
+// SetNonTS defines a non-thread safe set data structure.
+type SetNonTS struct {
+	set
+}
+
+// NewNonTS creates and initializes a new non-threadsafe Set.
+func newNonTS() *SetNonTS {
+	s := &SetNonTS{}
+	s.m = make(map[interface{}]struct{}, 16)
+	s.lenChange = false
+	s.list = make([]interface{}, 0, 32)
+
+	// Ensure interface compliance
+	var _ Interface = s
+
+	return s
+}
+
+// Add includes the specified items (one or more) to the set. The underlying
+// Set s is modified. If passed nothing it silently returns.
+func (s *set) Add(items ...interface{}) {
+	if len(items) == 0 {
+		return
+	}
+
+	for _, item := range items {
+		if _, ok := s.m[item]; !ok {
+			s.list = append(s.list, item)
+		}
+		s.m[item] = keyExists
+	}
+}
+
+// Remove deletes the specified items from the set.  The underlying Set s is
+// modified. If passed nothing it silently returns.
+func (s *set) Remove(items ...interface{}) {
+	if len(items) == 0 {
+		return
+	}
+
+	for _, item := range items {
+		delete(s.m, item)
+	}
+	s.lenChange = true
+}
+
+// Pop  deletes and return an item from the set. The underlying Set s is
+// modified. If set is empty, nil is returned.
+func (s *set) Pop() interface{} {
+	for item := range s.m {
+		delete(s.m, item)
+		s.lenChange = true
+		return item
+	}
+	return nil
+}
+
+// Has looks for the existence of items passed. It returns false if nothing is
+// passed. For multiple items it returns true only if all of  the items exist.
+func (s *set) Has(items ...interface{}) bool {
+	// assume checked for empty item, which not exist
+	if len(items) == 0 {
+		return false
+	}
+
+	has := true
+	for _, item := range items {
+		if _, has = s.m[item]; !has {
+			break
+		}
+	}
+	return has
+}
+
+// Size returns the number of items in a set.
+func (s *set) Size() int {
+	return len(s.m)
+}
+
+// Clear removes all items from the set.
+func (s *set) Clear() {
+	s.m = make(map[interface{}]struct{}, 16)
+	s.lenChange = false
+	if len(s.list) > 0 {
+		s.list = s.list[:0]
+	}
+}
+
+// IsEmpty reports whether the Set is empty.
+func (s *set) IsEmpty() bool {
+	return s.Size() == 0
+}
+
+// IsEqual test whether s and t are the same in size and have the same items.
+func (s *set) IsEqual(t Interface) bool {
+	// Force locking only if given set is threadsafe.
+	if conv, ok := t.(*Set); ok {
+		conv.l.RLock()
+		defer conv.l.RUnlock()
+	}
+
+	// return false if they are no the same size
+	if sameSize := len(s.m) == t.Size(); !sameSize {
+		return false
+	}
+
+	equal := true
+	t.Each(func(item interface{}) bool {
+		_, equal = s.m[item]
+		return equal // if false, Each() will end
+	})
+
+	return equal
+}
+
+// IsSubset tests whether t is a subset of s.
+func (s *set) IsSubset(t Interface) (subset bool) {
+	subset = true
+
+	t.Each(func(item interface{}) bool {
+		_, subset = s.m[item]
+		return subset
+	})
+
+	return
+}
+
+// IsSuperset tests whether t is a superset of s.
+func (s *set) IsSuperset(t Interface) bool {
+	return t.IsSubset(s)
+}
+
+// Each traverses the items in the Set, calling the provided function for each
+// set member. Traversal will continue until all items in the Set have been
+// visited, or if the closure returns false.
+func (s *set) Each(f func(item interface{}) bool) {
+	for item := range s.m {
+		if !f(item) {
+			break
+		}
+	}
+}
+
+// Copy returns a new Set with a copy of s.
+func (s *set) Copy() Interface {
+	u := newNonTS()
+	for item := range s.m {
+		u.Add(item)
+	}
+	return u
+}
+
+func (s *set) CopyWithOut(set2 Interface, sets ...Interface) Interface {
+	u := newNonTS()
+	for item := range s.m {
+		if set2.Has(item) {
+			continue
+		}
+		bOk := false
+		for _, set := range sets {
+			if set.Has(item) {
+				bOk = true
+				break
+			}
+		}
+		if !bOk {
+			u.Add(item)
+		}
+	}
+	return u
+}
+
+// String returns a string representation of s
+func (s *set) String() string {
+	t := make([]string, 0, len(s.List()))
+	for _, item := range s.List() {
+		t = append(t, fmt.Sprintf("%v", item))
+	}
+
+	return fmt.Sprintf("[%s]", strings.Join(t, ", "))
+}
+
+// List returns a slice of all items. There is also StringSlice() and
+// IntSlice() methods for returning slices of type string or int.
+func (s *set) List() []interface{} {
+	if s.lenChange {
+		s.list = s.list[:0]
+		for item := range s.m {
+			s.list = append(s.list, item)
+		}
+		s.lenChange = false
+	}
+	return s.list
+}
+
+// Merge is like Union, however it modifies the current set it's applied on
+// with the given t set.
+func (s *set) Merge(t Interface) {
+	t.Each(func(item interface{}) bool {
+		s.m[item] = keyExists
+		s.lenChange = true
+		return true
+	})
+}
+
+// it's not the opposite of Merge.
+// Separate removes the set items containing in t from set s. Please aware that
+func (s *set) Separate(t Interface) {
+	s.Remove(t.List()...)
+	s.lenChange = true
+}

+ 300 - 0
RO_Server_Trunk-branch_0.1.39/roserver/baseserver/set/set_nots_test.go

@@ -0,0 +1,300 @@
+package set
+
+import (
+	"reflect"
+	"strings"
+	"testing"
+)
+
+func Test_New(t *testing.T) {
+	s := New(ThreadSafe)
+	s.Add(1, 2, 3, "testing")
+	if s.Size() != 4 {
+		t.Error("New: The set created was expected have 4 items")
+	}
+}
+
+func TestSetNonTS_Add(t *testing.T) {
+	s := New(NonThreadSafe)
+	s.Add(1)
+	s.Add(2)
+	s.Add(2) // duplicate
+	s.Add("fatih")
+	s.Add("zeynep")
+	s.Add("zeynep") // another duplicate
+
+	if s.Size() != 4 {
+		t.Error("Add: items are not unique. The set size should be four")
+	}
+
+	if !s.Has(1, 2, "fatih", "zeynep") {
+		t.Error("Add: added items are not availabile in the set.")
+	}
+}
+
+func TestSetNonTS_Add_multiple(t *testing.T) {
+	s := newNonTS()
+	s.Add("ankara", "san francisco", 3.14)
+
+	if s.Size() != 3 {
+		t.Error("Add: items are not unique. The set size should be three")
+	}
+
+	if !s.Has("ankara", "san francisco", 3.14) {
+		t.Error("Add: added items are not availabile in the set.")
+	}
+}
+
+func TestSetNonTS_Remove(t *testing.T) {
+	s := newNonTS()
+	s.Add(1)
+	s.Add(2)
+	s.Add("fatih")
+
+	s.Remove(1)
+	if s.Size() != 2 {
+		t.Error("Remove: set size should be two after removing")
+	}
+
+	s.Remove(1)
+	if s.Size() != 2 {
+		t.Error("Remove: set size should be not change after trying to remove a non-existing item")
+	}
+
+	s.Remove(2)
+	s.Remove("fatih")
+	if s.Size() != 0 {
+		t.Error("Remove: set size should be zero")
+	}
+
+	s.Remove("fatih") // try to remove something from a zero length set
+}
+
+func TestSetNonTS_Remove_multiple(t *testing.T) {
+	s := newNonTS()
+	s.Add("ankara", "san francisco", 3.14, "istanbul")
+	s.Remove("ankara", "san francisco", 3.14)
+
+	if s.Size() != 1 {
+		t.Error("Remove: items are not unique. The set size should be four")
+	}
+
+	if !s.Has("istanbul") {
+		t.Error("Add: added items are not availabile in the set.")
+	}
+}
+
+func TestSetNonTS_Pop(t *testing.T) {
+	s := newNonTS()
+	s.Add(1)
+	s.Add(2)
+	s.Add("fatih")
+
+	a := s.Pop()
+	if s.Size() != 2 {
+		t.Error("Pop: set size should be two after popping out")
+	}
+
+	if s.Has(a) {
+		t.Error("Pop: returned item should not exist")
+	}
+
+	s.Pop()
+	s.Pop()
+	b := s.Pop()
+	if b != nil {
+		t.Error("Pop: should return nil because set is empty")
+	}
+
+	s.Pop() // try to remove something from a zero length set
+}
+
+func TestSetNonTS_Has(t *testing.T) {
+	s := newNonTS()
+	s.Add("1", "2", "3", "4")
+
+	if !s.Has("1") {
+		t.Error("Has: the item 1 exist, but 'Has' is returning false")
+	}
+
+	if !s.Has("1", "2", "3", "4") {
+		t.Error("Has: the items all exist, but 'Has' is returning false")
+	}
+}
+
+func TestSetNonTS_Clear(t *testing.T) {
+	s := newNonTS()
+	s.Add(1)
+	s.Add("istanbul")
+	s.Add("san francisco")
+
+	s.Clear()
+	if s.Size() != 0 {
+		t.Error("Clear: set size should be zero")
+	}
+}
+
+func TestSetNonTS_IsEmpty(t *testing.T) {
+	s := newNonTS()
+
+	empty := s.IsEmpty()
+	if !empty {
+		t.Error("IsEmpty: set is empty, it should be true")
+	}
+
+	s.Add(2)
+	s.Add(3)
+	notEmpty := s.IsEmpty()
+
+	if notEmpty {
+		t.Error("IsEmpty: set is filled, it should be false")
+	}
+}
+
+func TestSetNonTS_IsEqual(t *testing.T) {
+	s := newNonTS()
+	s.Add("1", "2", "3")
+	u := newNonTS()
+	u.Add("1", "2", "3")
+
+	ok := s.IsEqual(u)
+	if !ok {
+		t.Error("IsEqual: set s and t are equal. However it returns false")
+	}
+
+	// same size, different content
+	a := newNonTS()
+	a.Add("1", "2", "3")
+	b := newNonTS()
+	b.Add("4", "5", "6")
+
+	ok = a.IsEqual(b)
+	if ok {
+		t.Error("IsEqual: set a and b are now equal (1). However it returns true")
+	}
+
+	// different size, similar content
+	a = newNonTS()
+	a.Add("1", "2", "3")
+	b = newNonTS()
+	b.Add("1", "2", "3", "4")
+
+	ok = a.IsEqual(b)
+	if ok {
+		t.Error("IsEqual: set s and t are now equal (2). However it returns true")
+	}
+}
+
+func TestSetNonTS_IsSubset(t *testing.T) {
+	s := newNonTS()
+	s.Add("1", "2", "3", "4")
+	u := newNonTS()
+	u.Add("1", "2", "3")
+
+	ok := s.IsSubset(u)
+	if !ok {
+		t.Error("IsSubset: u is a subset of s. However it returns false")
+	}
+
+	ok = u.IsSubset(s)
+	if ok {
+		t.Error("IsSubset: s is not a subset of u. However it returns true")
+	}
+
+}
+
+func TestSetNonTS_IsSuperset(t *testing.T) {
+	s := newNonTS()
+	s.Add("1", "2", "3", "4")
+	u := newNonTS()
+	u.Add("1", "2", "3")
+
+	ok := u.IsSuperset(s)
+	if !ok {
+		t.Error("IsSuperset: s is a superset of u. However it returns false")
+	}
+
+	ok = s.IsSuperset(u)
+	if ok {
+		t.Error("IsSuperset: u is not a superset of u. However it returns true")
+	}
+
+}
+
+func TestSetNonTS_String(t *testing.T) {
+	s := newNonTS()
+	if s.String() != "[]" {
+		t.Errorf("String: output is not what is excepted '%s'", s.String())
+	}
+
+	s.Add("1", "2", "3", "4")
+
+	if !strings.HasPrefix(s.String(), "[") {
+		t.Error("String: output should begin with a square bracket")
+	}
+
+	if !strings.HasSuffix(s.String(), "]") {
+		t.Error("String: output should end with a square bracket")
+	}
+}
+
+func TestSetNonTS_List(t *testing.T) {
+	s := newNonTS()
+	s.Add("1", "2", "3", "4")
+	s = newNonTS()
+	s.Add("1", "2", "3", "4")
+
+	// this returns a slice of interface{}
+	if len(s.List()) != 4 {
+		t.Error("List: slice size should be four.")
+	}
+
+	for _, item := range s.List() {
+		r := reflect.TypeOf(item)
+		if r.Kind().String() != "string" {
+			t.Error("List: slice item should be a string")
+		}
+	}
+}
+
+func TestSetNonTS_Copy(t *testing.T) {
+	s := newNonTS()
+	s.Add("1", "2", "3", "4")
+	r := s.Copy()
+
+	if !s.IsEqual(r) {
+		t.Error("Copy: set s and r are not equal")
+	}
+}
+
+func TestSetNonTS_Merge(t *testing.T) {
+	s := newNonTS()
+	s.Add("1", "2", "3")
+	r := newNonTS()
+	r.Add("3", "4", "5")
+	s.Merge(r)
+
+	if s.Size() != 5 {
+		t.Error("Merge: the set doesn't have all items in it.")
+	}
+
+	if !s.Has("1", "2", "3", "4", "5") {
+		t.Error("Merge: merged items are not availabile in the set.")
+	}
+}
+
+func TestSetNonTS_Separate(t *testing.T) {
+	s := newNonTS()
+	s.Add("1", "2", "3")
+	r := newNonTS()
+	r.Add("3", "5")
+	s.Separate(r)
+
+	if s.Size() != 2 {
+		t.Error("Separate: the set doesn't have all items in it.")
+	}
+
+	if !s.Has("1", "2") {
+		t.Error("Separate: items after separation are not availabile in the set.")
+	}
+}

+ 218 - 0
RO_Server_Trunk-branch_0.1.39/roserver/baseserver/set/set_test.go

@@ -0,0 +1,218 @@
+package set
+
+import (
+	"reflect"
+	"testing"
+)
+
+func Test_Union(t *testing.T) {
+	s := newTS()
+	s.Add("1", "2", "3")
+	r := newTS()
+	r.Add("3", "4", "5")
+	x := newNonTS()
+	x.Add("5", "6", "7")
+
+	u := Union(s, r, x)
+	if settype := reflect.TypeOf(u).String(); settype != "*set.Set" {
+		t.Error("Union should derive its set type from the first passed set, got", settype)
+	}
+	if u.Size() != 7 {
+		t.Error("Union: the merged set doesn't have all items in it.")
+	}
+
+	if !u.Has("1", "2", "3", "4", "5", "6", "7") {
+		t.Error("Union: merged items are not availabile in the set.")
+	}
+
+	z := Union(x, r)
+	if z.Size() != 5 {
+		t.Error("Union: Union of 2 sets doesn't have the proper number of items.")
+	}
+	if settype := reflect.TypeOf(z).String(); settype != "*set.SetNonTS" {
+		t.Error("Union should derive its set type from the first passed set, got", settype)
+	}
+
+}
+
+func Test_Difference(t *testing.T) {
+	s := newTS()
+	s.Add("1", "2", "3")
+	r := newTS()
+	r.Add("3", "4", "5")
+	x := newNonTS()
+	x.Add("5", "6", "7")
+
+	u := Difference(s, r, x)
+
+	if u.Size() != 2 {
+		t.Error("Difference: the set doesn't have all items in it.")
+	}
+
+	if !u.Has("1", "2") {
+		t.Error("Difference: items are not availabile in the set.")
+	}
+
+	y := Difference(r, r)
+	if y.Size() != 0 {
+		t.Error("Difference: size should be zero")
+	}
+
+}
+
+func Test_Intersection(t *testing.T) {
+	s1 := newTS()
+	s1.Add("1", "3", "4", "5")
+	s2 := newTS()
+	s2.Add("3", "5", "6")
+	s3 := newTS()
+	s3.Add("4", "5", "6", "7")
+	u := Intersection(s1, s2, s3)
+
+	if u.Size() != 1 {
+		t.Error("Intersection: the set doesn't have all items in it.")
+	}
+
+	if !u.Has("5") {
+		t.Error("Intersection: items after intersection are not availabile in the set.")
+	}
+}
+
+func Test_Intersection2(t *testing.T) {
+	s1 := newTS()
+	s1.Add("1", "3", "4", "5")
+	s2 := newTS()
+	s2.Add("5", "6")
+	i := Intersection(s1, s2)
+
+	if i.Size() != 1 {
+		t.Error("Intersection: size should be 1, it was", i.Size())
+	}
+
+	if !i.Has("5") {
+		t.Error("Intersection: items after intersection are not availabile in the set.")
+	}
+}
+
+func Test_SymmetricDifference(t *testing.T) {
+	s := newTS()
+	s.Add("1", "2", "3")
+	r := newTS()
+	r.Add("3", "4", "5")
+	u := SymmetricDifference(s, r)
+
+	if u.Size() != 4 {
+		t.Error("SymmetricDifference: the set doesn't have all items in it.")
+	}
+
+	if !u.Has("1", "2", "4", "5") {
+		t.Error("SymmetricDifference: items are not availabile in the set.")
+	}
+}
+
+func Test_StringSlice(t *testing.T) {
+	s := newTS()
+	s.Add("san francisco", "istanbul", 3.14, 1321, "ankara")
+	u := StringSlice(s)
+
+	if len(u) != 3 {
+		t.Error("StringSlice: slice should only have three items")
+	}
+
+	for _, item := range u {
+		r := reflect.TypeOf(item)
+		if r.Kind().String() != "string" {
+			t.Error("StringSlice: slice item should be a string")
+		}
+	}
+}
+
+func Test_IntSlice(t *testing.T) {
+	s := newTS()
+	s.Add("san francisco", "istanbul", 3.14, 1321, "ankara", 8876)
+	u := IntSlice(s)
+
+	if len(u) != 2 {
+		t.Error("IntSlice: slice should only have two items")
+	}
+
+	for _, item := range u {
+		r := reflect.TypeOf(item)
+		if r.Kind().String() != "int" {
+			t.Error("Intslice: slice item should be a int")
+		}
+	}
+}
+
+func BenchmarkSetEquality(b *testing.B) {
+	s := newTS()
+	u := newTS()
+
+	for i := 0; i < b.N; i++ {
+		s.Add(i)
+		u.Add(i)
+	}
+
+	b.ResetTimer()
+
+	for i := 0; i < b.N; i++ {
+		s.IsEqual(u)
+	}
+}
+
+func BenchmarkSubset(b *testing.B) {
+	s := newTS()
+	u := newTS()
+
+	for i := 0; i < b.N; i++ {
+		s.Add(i)
+		u.Add(i)
+	}
+
+	b.ResetTimer()
+
+	for i := 0; i < b.N; i++ {
+		s.IsSubset(u)
+	}
+}
+
+func benchmarkIntersection(b *testing.B, numberOfItems int) {
+	s1 := newTS()
+	s2 := newTS()
+
+	for i := 0; i < numberOfItems/2; i++ {
+		s1.Add(i)
+	}
+	for i := 0; i < numberOfItems; i++ {
+		s2.Add(i)
+	}
+
+	b.ResetTimer()
+	for i := 0; i < b.N; i++ {
+		Intersection(s1, s2)
+	}
+}
+
+func BenchmarkIntersection10(b *testing.B) {
+	benchmarkIntersection(b, 10)
+}
+
+func BenchmarkIntersection100(b *testing.B) {
+	benchmarkIntersection(b, 100)
+}
+
+func BenchmarkIntersection1000(b *testing.B) {
+	benchmarkIntersection(b, 1000)
+}
+
+func BenchmarkIntersection10000(b *testing.B) {
+	benchmarkIntersection(b, 10000)
+}
+
+func BenchmarkIntersection100000(b *testing.B) {
+	benchmarkIntersection(b, 100000)
+}
+
+func BenchmarkIntersection1000000(b *testing.B) {
+	benchmarkIntersection(b, 1000000)
+}

+ 204 - 0
RO_Server_Trunk-branch_0.1.39/roserver/baseserver/set/set_ts.go

@@ -0,0 +1,204 @@
+package set
+
+import "sync"
+
+// Set defines a thread safe set data structure.
+type Set struct {
+	set
+	l sync.RWMutex // we name it because we don't want to expose it
+}
+
+// New creates and initialize a new Set. It's accept a variable number of
+// arguments to populate the initial set. If nothing passed a Set with zero
+// size is created.
+func newTS() *Set {
+	s := &Set{}
+	s.m = make(map[interface{}]struct{})
+
+	// Ensure interface compliance
+	var _ Interface = s
+
+	return s
+}
+
+// Add includes the specified items (one or more) to the set. The underlying
+// Set s is modified. If passed nothing it silently returns.
+func (s *Set) Add(items ...interface{}) {
+	if len(items) == 0 {
+		return
+	}
+
+	s.l.Lock()
+	defer s.l.Unlock()
+
+	for _, item := range items {
+		s.m[item] = keyExists
+	}
+}
+
+// Remove deletes the specified items from the set.  The underlying Set s is
+// modified. If passed nothing it silently returns.
+func (s *Set) Remove(items ...interface{}) {
+	if len(items) == 0 {
+		return
+	}
+
+	s.l.Lock()
+	defer s.l.Unlock()
+
+	for _, item := range items {
+		delete(s.m, item)
+	}
+}
+
+// Pop  deletes and return an item from the set. The underlying Set s is
+// modified. If set is empty, nil is returned.
+func (s *Set) Pop() interface{} {
+	s.l.RLock()
+	for item := range s.m {
+		s.l.RUnlock()
+		s.l.Lock()
+		delete(s.m, item)
+		s.l.Unlock()
+		return item
+	}
+	s.l.RUnlock()
+	return nil
+}
+
+// Has looks for the existence of items passed. It returns false if nothing is
+// passed. For multiple items it returns true only if all of  the items exist.
+func (s *Set) Has(items ...interface{}) bool {
+	// assume checked for empty item, which not exist
+	if len(items) == 0 {
+		return false
+	}
+
+	s.l.RLock()
+	defer s.l.RUnlock()
+
+	has := true
+	for _, item := range items {
+		if _, has = s.m[item]; !has {
+			break
+		}
+	}
+	return has
+}
+
+// Size returns the number of items in a set.
+func (s *Set) Size() int {
+	s.l.RLock()
+	defer s.l.RUnlock()
+
+	l := len(s.m)
+	return l
+}
+
+// Clear removes all items from the set.
+func (s *Set) Clear() {
+	s.l.Lock()
+	defer s.l.Unlock()
+
+	s.m = make(map[interface{}]struct{})
+}
+
+// IsEqual test whether s and t are the same in size and have the same items.
+func (s *Set) IsEqual(t Interface) bool {
+	s.l.RLock()
+	defer s.l.RUnlock()
+
+	// Force locking only if given set is threadsafe.
+	if conv, ok := t.(*Set); ok {
+		conv.l.RLock()
+		defer conv.l.RUnlock()
+	}
+
+	// return false if they are no the same size
+	if sameSize := len(s.m) == t.Size(); !sameSize {
+		return false
+	}
+
+	equal := true
+	t.Each(func(item interface{}) bool {
+		_, equal = s.m[item]
+		return equal // if false, Each() will end
+	})
+
+	return equal
+}
+
+// IsSubset tests whether t is a subset of s.
+func (s *Set) IsSubset(t Interface) (subset bool) {
+	s.l.RLock()
+	defer s.l.RUnlock()
+
+	subset = true
+
+	t.Each(func(item interface{}) bool {
+		_, subset = s.m[item]
+		return subset
+	})
+
+	return
+}
+
+// Each traverses the items in the Set, calling the provided function for each
+// set member. Traversal will continue until all items in the Set have been
+// visited, or if the closure returns false.
+func (s *Set) Each(f func(item interface{}) bool) {
+	s.l.RLock()
+	defer s.l.RUnlock()
+
+	for item := range s.m {
+		if !f(item) {
+			break
+		}
+	}
+}
+
+// List returns a slice of all items. There is also StringSlice() and
+// IntSlice() methods for returning slices of type string or int.
+func (s *Set) List() []interface{} {
+	s.l.RLock()
+	defer s.l.RUnlock()
+
+	list := make([]interface{}, 0, len(s.m))
+
+	for item := range s.m {
+		list = append(list, item)
+	}
+
+	return list
+}
+
+// Copy returns a new Set with a copy of s.
+func (s *Set) Copy() Interface {
+	u := newTS()
+	for item := range s.m {
+		u.Add(item)
+	}
+	return u
+}
+
+func (s *Set) CopyWithOut(set2 Interface, sets ...Interface) Interface {
+	u := newTS()
+	for item := range s.m {
+		if !s.Has(set2, sets) {
+			u.Add(item)
+		}
+	}
+	return u
+}
+
+// Merge is like Union, however it modifies the current set it's applied on
+// with the given t set.
+func (s *Set) Merge(t Interface) {
+	s.l.Lock()
+	defer s.l.Unlock()
+
+	t.Each(func(item interface{}) bool {
+		s.m[item] = keyExists
+		return true
+	})
+}

+ 331 - 0
RO_Server_Trunk-branch_0.1.39/roserver/baseserver/set/set_ts_test.go

@@ -0,0 +1,331 @@
+package set
+
+import (
+	"reflect"
+	"strconv"
+	"strings"
+	"testing"
+)
+
+func TestSet_New(t *testing.T) {
+	s := newTS()
+
+	if s.Size() != 0 {
+		t.Error("New: calling without any parameters should create a set with zero size")
+	}
+}
+
+func TestSet_New_parameters(t *testing.T) {
+	s := newTS()
+	s.Add("string", "another_string", 1, 3.14)
+
+	if s.Size() != 4 {
+		t.Error("New: calling with parameters should create a set with size of four")
+	}
+}
+
+func TestSet_Add(t *testing.T) {
+	s := newTS()
+	s.Add(1)
+	s.Add(2)
+	s.Add(2) // duplicate
+	s.Add("fatih")
+	s.Add("zeynep")
+	s.Add("zeynep") // another duplicate
+
+	if s.Size() != 4 {
+		t.Error("Add: items are not unique. The set size should be four")
+	}
+
+	if !s.Has(1, 2, "fatih", "zeynep") {
+		t.Error("Add: added items are not availabile in the set.")
+	}
+}
+
+func TestSet_Add_multiple(t *testing.T) {
+	s := newTS()
+	s.Add("ankara", "san francisco", 3.14)
+
+	if s.Size() != 3 {
+		t.Error("Add: items are not unique. The set size should be three")
+	}
+
+	if !s.Has("ankara", "san francisco", 3.14) {
+		t.Error("Add: added items are not availabile in the set.")
+	}
+}
+
+func TestSet_Remove(t *testing.T) {
+	s := newTS()
+	s.Add(1)
+	s.Add(2)
+	s.Add("fatih")
+
+	s.Remove(1)
+	if s.Size() != 2 {
+		t.Error("Remove: set size should be two after removing")
+	}
+
+	s.Remove(1)
+	if s.Size() != 2 {
+		t.Error("Remove: set size should be not change after trying to remove a non-existing item")
+	}
+
+	s.Remove(2)
+	s.Remove("fatih")
+	if s.Size() != 0 {
+		t.Error("Remove: set size should be zero")
+	}
+
+	s.Remove("fatih") // try to remove something from a zero length set
+}
+
+func TestSet_Remove_multiple(t *testing.T) {
+	s := newTS()
+	s.Add("ankara", "san francisco", 3.14, "istanbul")
+	s.Remove("ankara", "san francisco", 3.14)
+
+	if s.Size() != 1 {
+		t.Error("Remove: items are not unique. The set size should be four")
+	}
+
+	if !s.Has("istanbul") {
+		t.Error("Add: added items are not availabile in the set.")
+	}
+}
+
+func TestSet_Pop(t *testing.T) {
+	s := newTS()
+	s.Add(1)
+	s.Add(2)
+	s.Add("fatih")
+
+	a := s.Pop()
+	if s.Size() != 2 {
+		t.Error("Pop: set size should be two after popping out")
+	}
+
+	if s.Has(a) {
+		t.Error("Pop: returned item should not exist")
+	}
+
+	s.Pop()
+	s.Pop()
+	b := s.Pop()
+	if b != nil {
+		t.Error("Pop: should return nil because set is empty")
+	}
+
+	s.Pop() // try to remove something from a zero length set
+}
+
+func TestSet_Has(t *testing.T) {
+	s := newTS()
+	s.Add("1", "2", "3", "4")
+
+	if !s.Has("1") {
+		t.Error("Has: the item 1 exist, but 'Has' is returning false")
+	}
+
+	if !s.Has("1", "2", "3", "4") {
+		t.Error("Has: the items all exist, but 'Has' is returning false")
+	}
+}
+
+func TestSet_Clear(t *testing.T) {
+	s := newTS()
+	s.Add(1)
+	s.Add("istanbul")
+	s.Add("san francisco")
+
+	s.Clear()
+	if s.Size() != 0 {
+		t.Error("Clear: set size should be zero")
+	}
+}
+
+func TestSet_IsEmpty(t *testing.T) {
+	s := newTS()
+
+	empty := s.IsEmpty()
+	if !empty {
+		t.Error("IsEmpty: set is empty, it should be true")
+	}
+
+	s.Add(2)
+	s.Add(3)
+	notEmpty := s.IsEmpty()
+
+	if notEmpty {
+		t.Error("IsEmpty: set is filled, it should be false")
+	}
+}
+
+func TestSet_IsEqual(t *testing.T) {
+	// same size, same content
+	s := newTS()
+	s.Add("1", "2", "3")
+	u := newTS()
+	u.Add("1", "2", "3")
+
+	ok := s.IsEqual(u)
+	if !ok {
+		t.Error("IsEqual: set s and t are equal. However it returns false")
+	}
+
+	// same size, different content
+	a := newTS()
+	a.Add("1", "2", "3")
+	b := newTS()
+	b.Add("4", "5", "6")
+
+	ok = a.IsEqual(b)
+	if ok {
+		t.Error("IsEqual: set a and b are now equal (1). However it returns true")
+	}
+
+	// different size, similar content
+	a = newTS()
+	a.Add("1", "2", "3")
+	b = newTS()
+	b.Add("1", "2", "3", "4")
+
+	ok = a.IsEqual(b)
+	if ok {
+		t.Error("IsEqual: set s and t are now equal (2). However it returns true")
+	}
+}
+
+func TestSet_IsSubset(t *testing.T) {
+	s := newTS()
+	s.Add("1", "2", "3", "4")
+	u := newTS()
+	u.Add("1", "2", "3")
+
+	ok := s.IsSubset(u)
+	if !ok {
+		t.Error("IsSubset: u is a subset of s. However it returns false")
+	}
+
+	ok = u.IsSubset(s)
+	if ok {
+		t.Error("IsSubset: s is not a subset of u. However it returns true")
+	}
+}
+
+func TestSet_IsSuperset(t *testing.T) {
+	s := newTS()
+	s.Add("1", "2", "3", "4")
+	u := newTS()
+	u.Add("1", "2", "3")
+
+	ok := u.IsSuperset(s)
+	if !ok {
+		t.Error("IsSuperset: s is a superset of u. However it returns false")
+	}
+
+	ok = s.IsSuperset(u)
+	if ok {
+		t.Error("IsSuperset: u is not a superset of u. However it returns true")
+	}
+}
+
+func TestSet_String(t *testing.T) {
+	s := newTS()
+	if s.String() != "[]" {
+		t.Errorf("String: output is not what is excepted '%s'", s.String())
+	}
+
+	if !strings.HasPrefix(s.String(), "[") {
+		t.Error("String: output should begin with a square bracket")
+	}
+
+	if !strings.HasSuffix(s.String(), "]") {
+		t.Error("String: output should end with a square bracket")
+	}
+}
+
+func TestSet_List(t *testing.T) {
+	s := newTS()
+	s.Add("1", "2", "3", "4")
+
+	// this returns a slice of interface{}
+	if len(s.List()) != 4 {
+		t.Error("List: slice size should be four.")
+	}
+
+	for _, item := range s.List() {
+		r := reflect.TypeOf(item)
+		if r.Kind().String() != "string" {
+			t.Error("List: slice item should be a string")
+		}
+	}
+}
+
+func TestSet_Copy(t *testing.T) {
+	s := newTS()
+	s.Add("1", "2", "3", "4")
+	r := s.Copy()
+
+	if !s.IsEqual(r) {
+		t.Error("Copy: set s and r are not equal")
+	}
+}
+
+func TestSet_Merge(t *testing.T) {
+	s := newTS()
+	s.Add("1", "2", "3")
+	r := newTS()
+	r.Add("3", "4", "5")
+	s.Merge(r)
+
+	if s.Size() != 5 {
+		t.Error("Merge: the set doesn't have all items in it.")
+	}
+
+	if !s.Has("1", "2", "3", "4", "5") {
+		t.Error("Merge: merged items are not availabile in the set.")
+	}
+}
+
+func TestSet_Separate(t *testing.T) {
+	s := newTS()
+	s.Add("1", "2", "3")
+	r := newTS()
+	r.Add("3", "5")
+	s.Separate(r)
+
+	if s.Size() != 2 {
+		t.Error("Separate: the set doesn't have all items in it.")
+	}
+
+	if !s.Has("1", "2") {
+		t.Error("Separate: items after separation are not availabile in the set.")
+	}
+}
+
+func TestSet_RaceAdd(t *testing.T) {
+	// Create two sets. Add concurrently items to each of them. Remove from the
+	// other one.
+	// "go test -race" should detect this if the library is not thread-safe.
+	s := newTS()
+	u := newTS()
+
+	go func() {
+		for i := 0; i < 1000; i++ {
+			item := "item" + strconv.Itoa(i)
+			go func(i int) {
+				s.Add(item)
+				u.Add(item)
+			}(i)
+		}
+	}()
+
+	for i := 0; i < 1000; i++ {
+		item := "item" + strconv.Itoa(i)
+		go func(i int) {
+			s.Add(item)
+			u.Add(item)
+		}(i)
+	}
+}

+ 68 - 0
RO_Server_Trunk-branch_0.1.39/roserver/baseserver/shm/shared_memory_linux.go

@@ -0,0 +1,68 @@
+package shm
+
+import (
+	"syscall"
+)
+
+//映射地址对应mapid
+var SharedMemIdsToShmids map[uint16]uintptr = map[uint16]uintptr{}
+
+const (
+	IPC_CREATE = 01000 //create entry if key does not exist
+	IPC_EXCL   = 02000 //fail if key exists
+	IPC_NOWAIT = 04000 //error if request must wait
+
+	IPC_RMID = 0 //remove identifier
+	IPC_SET  = 1 //set options
+	IPC_STAT = 2 //get options
+)
+
+func CreateSharedMemory(size uint32, sharedMemId *uint16) uintptr {
+	shmId, _, err := syscall.Syscall(syscall.SYS_SHMGET, uintptr(*sharedMemId), uintptr(size), IPC_CREATE|IPC_EXCL|0666)
+	if err != 0 {
+		return uintptr(0)
+	}
+	SharedMemIdsToShmids[*sharedMemId] = shmId
+
+	accessAddress, _, err := syscall.Syscall(syscall.SYS_SHMAT, shmId, 0, 0)
+	if err != 0 {
+		return uintptr(0)
+	}
+	return accessAddress
+}
+
+func AccessSharedMemory(sharedMemId *uint16) uintptr {
+	shmId, _, err := syscall.Syscall(syscall.SYS_SHMGET, uintptr(*sharedMemId), 0, 0666)
+	if err != 0 {
+		return uintptr(0)
+	}
+
+	accessAddress, _, err := syscall.Syscall(syscall.SYS_SHMAT, shmId, 0, 0)
+	if err != 0 {
+		return uintptr(0)
+	}
+	return accessAddress
+}
+
+//shm cannot be use after use this method
+func CloseShardMemory(accessAddress uintptr) bool {
+	_, _, err := syscall.Syscall(syscall.SYS_SHMDT, accessAddress, 0, 0)
+	if err != 0 {
+		return false
+	}
+	return true
+}
+
+func destroySharedMemory(sharedMemId *uint16, force bool) {
+	value, ok := SharedMemIdsToShmids[*sharedMemId]
+	if ok {
+		syscall.Syscall(syscall.SYS_SHMCTL, value, IPC_RMID, 0)
+		delete(SharedMemIdsToShmids, *sharedMemId)
+	} else if force {
+		shmId, _, err := syscall.Syscall(syscall.SYS_SHMGET, uintptr(*sharedMemId), 0, 0666)
+		if err != 0 {
+			return
+		}
+		syscall.Syscall(syscall.SYS_SHMCTL, shmId, IPC_RMID, 0)
+	}
+}

+ 88 - 0
RO_Server_Trunk-branch_0.1.39/roserver/baseserver/shm/shared_memory_windows.go

@@ -0,0 +1,88 @@
+package shm
+
+import (
+	"syscall"
+	"unsafe"
+)
+
+//映射地址对应mapid
+var AccessAddressesToHandles map[uintptr]syscall.Handle = map[uintptr]syscall.Handle{}
+
+func CreateSharedMemory(size uint32, sharedMemId *uint16) uintptr {
+	hMapFile, err := syscall.CreateFileMapping(syscall.InvalidHandle, nil, syscall.PAGE_EXECUTE_READWRITE, 0, size, sharedMemId)
+	if err != nil {
+		//util.WarnF("[SHDMEM] cannot create file mapping for smid:%v error %v", *sharedMemId, err)
+		return uintptr(0)
+	}
+
+	accessAddress, _ := syscall.MapViewOfFile(hMapFile,
+		syscall.FILE_MAP_WRITE|syscall.FILE_MAP_READ, 0, 0, 0)
+	AccessAddressesToHandles[accessAddress] = hMapFile
+	return accessAddress
+}
+
+//下面注释有另外一种实现方法
+func AccessSharedMemory(sharedMemId *uint16) uintptr {
+	procOpenFileMapping := syscall.NewLazyDLL("kernel32.dll").NewProc("OpenFileMappingW")
+	//执行syscall,出现exception,一般是参数类型错误导致
+	r0, _, e1 := syscall.Syscall(procOpenFileMapping.Addr(), 3,
+		uintptr(syscall.FILE_MAP_WRITE|syscall.FILE_MAP_READ), uintptr(0), uintptr(unsafe.Pointer(sharedMemId)))
+	handle := syscall.Handle(r0)
+	if e1 != 0 {
+		//util.WarnF("[SHDMEM] OpenFileMappingW failed %v error:%v", *sharedMemId, e1)
+		return uintptr(0)
+	}
+
+	accessAddress, _ := syscall.MapViewOfFile(handle,
+		syscall.FILE_MAP_WRITE|syscall.FILE_MAP_READ, 0, 0, 0)
+	AccessAddressesToHandles[accessAddress] = handle
+	return accessAddress
+}
+
+func CloseShardMemory(accessAddress uintptr) bool {
+	err := syscall.UnmapViewOfFile(accessAddress)
+	if err != nil {
+		//util.WarnF("[SHDMEM] UnmapViewOfFile failed err:%v", err)
+		return false
+	}
+
+	value, ok := AccessAddressesToHandles[accessAddress]
+	if ok {
+		err = syscall.CloseHandle(value)
+		if err != nil {
+			//util.WarnF("[SHDMEM] CloseHandle failed err:%v", err)
+		}
+		delete(AccessAddressesToHandles, accessAddress)
+		return true
+	}
+
+	return false
+}
+
+//this method does nothing under windows, destroying is automatic.
+func destroySharedMemory(sharedMemId *uint16, force bool) {
+}
+
+/*
+func AccessSharedMemory(sharedName string) uintptr {
+	shareNameByte,_ :=syscall.BytePtrFromString("Global/" + sharedName)
+	var shareNameId = uintptr(unsafe.Pointer(shareNameByte))
+
+	procOpenFileMapping := syscall.NewLazyDLL("kernel32.dll").NewProc("OpenFileMappingW")
+	hMapFile,_,err := procOpenFileMapping.Call(syscall.FILE_MAP_WRITE|syscall.FILE_MAP_READ, 0, shareNameId)
+	if err != nil {
+		util.WarnF("[SHDMEM] OpenFileMappingW failed error:%v", err)
+		return uintptr(0)
+	}
+
+	accessAddress,err1 := syscall.MapViewOfFile(syscall.Handle(hMapFile),
+		syscall.FILE_MAP_WRITE|syscall.FILE_MAP_READ, 0, 0,0)
+	if err1 != nil {
+		util.WarnF("[SHDMEM] MapViewOfFile failed error:%v", err)
+		return uintptr(0)
+	}
+	AccessAddressesToHandles[accessAddress] = syscall.Handle(hMapFile)
+	return accessAddress
+
+}
+*/

+ 82 - 0
RO_Server_Trunk-branch_0.1.39/roserver/baseserver/shm/shm.go

@@ -0,0 +1,82 @@
+package shm
+
+import (
+	"log"
+	_ "syscall"
+	"unsafe"
+)
+
+type nameStr struct {
+	name []byte
+	age  int
+}
+
+func MakeShareMemory(shmId uint32) uintptr {
+	//string方式
+	//shareName,_ := syscall.BytePtrFromString("Global/1")
+	//shareNameId := (*uint16)(unsafe.Pointer(shareName))
+
+	//数值方式
+	smid := (*uint16)(unsafe.Pointer(&shmId))
+	segment := CreateSharedMemory(1024, smid)
+	if segment == 0 {
+		//under linux,segment may have not been destroyed if the MS crashed:destroy
+		//See /proc/sysvipc/shm for the list of allocated segments
+		//如果是重新直接使用的话,这边不能做销毁操作,应该直接使用共享内存,快速启动进程
+		destroySharedMemory(smid, true)
+		//util.InfoF("destroyed shared memory segment,smid:%v", smid)
+
+		segment = CreateSharedMemory(1024, smid)
+	}
+
+	if segment == 0 {
+		//util.InfoF("cannot create shared memory segment,smid:%v", smid)
+		return uintptr(0)
+	}
+	//defer CloseShardMemory(segment)
+
+	return segment
+}
+
+func ReadSharedMemory(shmId uint32) uintptr {
+	smid := (*uint16)(unsafe.Pointer(&shmId))
+	return AccessSharedMemory(smid)
+}
+
+func TestMake() {
+	segment := MakeShareMemory(1)
+	if segment == 0 {
+		return
+	}
+
+	nameList := (*nameStr)(unsafe.Pointer(segment))
+	nameList.name = []byte("chy1")
+	nameList.age = 1111
+	log.Printf("make:%v", segment)
+
+	/*
+	*nameList = append(*nameList, &nameStr{name:[]byte("chy1"),age:30})
+	*nameList = append(*nameList, &nameStr{name:[]byte("chy2"),age:31})
+	*nameList = append(*nameList, &nameStr{name:[]byte("chy13"),age:32})
+
+	 */
+}
+
+func TestRead() {
+	segment := ReadSharedMemory(1)
+	if segment == 0 {
+		return
+	}
+
+	nameList := (*nameStr)(unsafe.Pointer(segment))
+	log.Printf("namelist:%v %v", string(nameList.name), nameList.age)
+	/*
+		if nameList != nil {
+			for key,_ :=range *nameList {
+				log.Printf("name:%v age:%v", string((*nameList)[key].name), (*nameList)[key].age)
+			}
+		}
+
+	*/
+
+}

+ 11 - 0
RO_Server_Trunk-branch_0.1.39/roserver/baseserver/version.go

@@ -0,0 +1,11 @@
+package baseserver
+
+var (
+	BuildVersion = ""
+	BuildGitRev  = ""
+)
+
+func init() {
+	//flag.Parse()
+	//log.Printf("version=%v gitrev=%v", BuildVersion, BuildGitRev)
+}

+ 72 - 0
RO_Server_Trunk-branch_0.1.39/roserver/battleboss/main.go

@@ -0,0 +1,72 @@
+package main
+
+import (
+	"io/ioutil"
+	_ "net/http/pprof"
+	"os"
+	"rocommon"
+	"rocommon/service"
+	_ "rocommon/socket"
+	_ "rocommon/socket/tcp"
+	"roserver/baseserver"
+	"roserver/baseserver/model"
+	self "roserver/battleboss/model"
+	_ "roserver/battleboss/msg"
+	"runtime"
+	"strconv"
+	"syscall"
+)
+
+//todo...
+// 单点有状态服务器
+func main() {
+	//记录battleboss pid用来做关闭操作
+	sysType := runtime.GOOS
+	if sysType != "windows" {
+		if pid := syscall.Getpid(); pid != 1 {
+			fileName := "battleboss_server.pid" + strconv.Itoa(pid)
+			ioutil.WriteFile(fileName, []byte(strconv.Itoa(pid)), 0777)
+			defer os.Remove(fileName)
+		}
+	}
+
+	//go func(){
+	//	log.Println(http.ListenAndServe("localhost:8005", nil))
+	//}()
+
+	//CPU
+	//prof := profile.Start(profile.CPUProfile, profile.ProfilePath("./pprof/serverboss.pprof"), profile.NoShutdownHook)
+
+	baseserver.Init(model.SERVICE_NODE_TYPE_BOSS_STR, self.ConfigInit, &self.BossUpdate{})
+
+	//prof := profile.Start(profile.MemProfile, profile.ProfilePath("./pprof/serverbossmem.pprof"), profile.NoShutdownHook)
+
+	sConfig := service.GetServiceConfig()
+	//先建立服务器对应的连接,在监听客户端
+	//创建监听器
+	var acceNode rocommon.ServerNode = nil
+	if sConfig.Node.Addr != "" {
+		acceNode = baseserver.CreateAcceptor(baseserver.ServiceParam{
+			ServiceType: "tcpAcceptor",
+			ServiceName: model.SERVICE_NODE_TYPE_BOSS_STR,
+			ProcName:    "common.backend",
+			LisAddr:     sConfig.Node.Addr,
+		}, sConfig)
+	}
+
+	for _, concern := range sConfig.Node.Concern {
+		//建立需要链接的服务器,可以通过服务器发现etcd来处理(包含在了CreateConnector中)
+		baseserver.CreateConnector(baseserver.ServiceParam{
+			DiscoveryServiceName: concern,
+			DiscoveryServiceZone: sConfig.Node.Zone,
+			ServiceType:          "tcpConnector",
+			ServiceName:          model.SERVICE_NODE_TYPE_BOSS_STR,
+			ProcName:             "common.backend",
+		})
+	}
+
+	baseserver.Wait()
+	//CPU
+	//prof.Stop()
+	baseserver.Exit(acceNode)
+}

+ 757 - 0
RO_Server_Trunk-branch_0.1.39/roserver/battleboss/model/boss_manager.go

@@ -0,0 +1,757 @@
+package model
+
+import (
+	"rocommon/service"
+	"rocommon/util"
+	"roserver/baseserver/model"
+	"roserver/baseserver/set"
+	"roserver/serverproto"
+	"time"
+)
+
+const MAX_AOI_LINE_BOSS_NUM = 100
+const MAX_BOSS_CHALLENGE_PLAYER_NUM = 8
+const BOSS_REWARD_MAIL_CONFIG_ID_Other = 2
+
+const (
+	BOSS_RESULT_WIN      = 1
+	BOSS_RESULT_TIME_OUT = 2
+
+	INIT_STATE_NONE   = 0
+	INIT_STATE_INIT   = 1 //获取数据
+	INIT_STATE_FINISH = 2 //初始化完成
+)
+const NO_AOILINE_BOSS = "NOAOI"
+const MAX_NO_AOILINE_BOSS_NUM = 20
+
+type RefreshBossInfo struct {
+	posId         int32
+	summonTimeIdx int
+	bossData      *model.ConvertWorldBossData
+
+	refreshTime time.Time //刷新boss的时间错,逻辑中使用
+
+	stop bool
+}
+
+func (this *RefreshBossInfo) printDebugString(addStr string) {
+	util.DebugF("msg=%v pos=%v bossid=%v summonidx=%v refreshtime=%v", addStr, this.posId,
+		this.bossData.Id, this.summonTimeIdx, this.refreshTime.String())
+}
+
+////////////////////////////////AoiLineBossManager
+type WorldBossManager struct {
+	mapRouterNode string
+	socialNode    string
+	updateTimer   util.ServerTimer //定时器
+
+	bossList map[uint64]*PlayerBoss //[bossId *PlayerBoss]
+
+	//挑战玩家所在boss场景
+	challengePlayerList map[uint64]*PlayerBoss
+
+	initStartUp                 int32 //维护时需要加载维护前的boss状态信息(血量,攻击记录)
+	refreshBossInfoList         map[int32]*RefreshBossInfo
+	refreshBossInfoActivityList map[int32]*RefreshBossInfo
+
+	startUpDayTime time.Time //开服整数点时间
+	startDiffDay   int32     //当前距离开服时间的天数
+}
+
+func newWorldBossManager() *WorldBossManager {
+	mag := &WorldBossManager{
+		bossList:                    map[uint64]*PlayerBoss{},
+		challengePlayerList:         map[uint64]*PlayerBoss{},
+		mapRouterNode:               "",
+		socialNode:                  "",
+		refreshBossInfoList:         map[int32]*RefreshBossInfo{},
+		refreshBossInfoActivityList: map[int32]*RefreshBossInfo{},
+	}
+
+	mag.challengePlayerList = map[uint64]*PlayerBoss{}
+	mag.updateTimer = util.NewDurationTimer(util.GetTimeMilliseconds(), 500)
+
+	mag.initRefresh()
+
+	return mag
+}
+
+//获取最近一天的boss刷新时间
+func (this *WorldBossManager) getCurrentDayBossData(currentDay int32, pos int32) *model.ConvertWorldBossData {
+	valList, ok := model.ConvertWorldBoss[pos]
+	if !ok {
+		return nil
+	}
+
+	var retData *model.ConvertWorldBossData = nil
+	for idx := 0; idx < len(valList); idx++ {
+		if valList[idx].StartDay <= currentDay {
+			retData = valList[idx]
+		} else if valList[idx].StartDay > currentDay {
+			break
+		}
+	}
+	if retData == nil {
+		if len(valList) > 0 {
+			retData = valList[len(valList)-1]
+		}
+	}
+	return retData
+}
+
+func (this *WorldBossManager) initRefresh() bool {
+	startUpTime := service.GetServiceStartupTime() //ms
+	if startUpTime <= 0 {
+		return false
+	}
+
+	this.startUpDayTime = util.GetDayByTimeStr2(startUpTime)
+	this.startDiffDay = util.GetDurationDay1(startUpTime, uint64(util.GetTimeMilliseconds())) + 1
+
+	//util.DebugF("nowhourtime=%v", nowHourTime.String())
+	//普通世界boss
+	for key := range model.ConvertWorldBoss {
+		tmp := this.getRefreshInfo(key)
+		tmp.printDebugString("initrefresh")
+	}
+	//活动世界boss(变身)
+	for _, bossDataInfo := range model.ConvertWorldBossChangePlayList {
+		this.getRefreshInfoChangePlay(bossDataInfo)
+	}
+
+	this.initStartUp = INIT_STATE_FINISH
+
+	//开服时间
+	return true
+}
+
+func (this *WorldBossManager) getRefreshInfo(pos int32) *RefreshBossInfo {
+	bFind := false
+	k := 0
+	tmpStartDiffDay := this.startDiffDay
+	nowHourTime := util.GetHourByTime(0)
+	//key == 0 表示最后一个位置
+	bossDataInfo := this.getCurrentDayBossData(tmpStartDiffDay, pos)
+	if bossDataInfo == nil {
+		return nil
+	}
+	for k = 0; k < len(bossDataInfo.SummonTime); k++ {
+		if bossDataInfo.SummonTime[k].After(nowHourTime) {
+			bFind = true
+			break
+		}
+	}
+
+	if !bFind {
+		k = 0
+		tmpStartDiffDay++
+		bossDataInfo = this.getCurrentDayBossData(tmpStartDiffDay, pos)
+		if bossDataInfo != nil && len(bossDataInfo.SummonTime) > 0 {
+			bFind = true
+		}
+	}
+
+	if bFind {
+		tmpTime := this.startUpDayTime.AddDate(0, 0, int(tmpStartDiffDay-1))
+		tmpSummonTime := bossDataInfo.SummonTime[k].Hour()*60*60 + bossDataInfo.SummonTime[k].Minute()*60 + bossDataInfo.SummonTime[k].Second()
+		tmpTime = tmpTime.Add(time.Duration(tmpSummonTime) * time.Second)
+		//util.DebugF("%v tmpTime:%v :%v", key, tmpTime.String(), tmpSummonTime)
+		refreshInfo := &RefreshBossInfo{
+			posId:       bossDataInfo.RefreshId,
+			bossData:    bossDataInfo,
+			refreshTime: tmpTime,
+		}
+		refreshInfo.summonTimeIdx = k + int(tmpStartDiffDay-1)*len(bossDataInfo.SummonTime)
+		this.refreshBossInfoList[pos] = refreshInfo
+		return refreshInfo
+	}
+	return nil
+}
+
+func (this *WorldBossManager) getRefreshInfoChangePlay(bossDataInfo *model.ConvertWorldBossData) *RefreshBossInfo {
+	tmpStartDiffDay := this.startDiffDay
+	nowHourTime := util.GetHourByTime(0)
+
+	//<=0表示根据给定的时间来开启[BossBeginTime,BossEndTime]
+	if bossDataInfo.StartDay <= 0 {
+		bFind := false
+		k := 0
+		for k = 0; k < len(bossDataInfo.SummonTime); k++ {
+			if bossDataInfo.SummonTime[k].After(nowHourTime) {
+				bFind = true
+				break
+			}
+		}
+		if !bFind {
+			k = 0
+			tmpStartDiffDay++
+			bFind = true
+		}
+
+		tmpTime := this.startUpDayTime.AddDate(0, 0, int(tmpStartDiffDay-1))
+		tmpSummonTime := bossDataInfo.SummonTime[k].Hour()*60*60 + bossDataInfo.SummonTime[k].Minute()*60 + bossDataInfo.SummonTime[k].Second()
+		tmpTime = tmpTime.Add(time.Duration(tmpSummonTime) * time.Second)
+
+		refreshInfo := &RefreshBossInfo{
+			bossData:    bossDataInfo,
+			refreshTime: tmpTime,
+		}
+		refreshInfo.summonTimeIdx = k + int(tmpStartDiffDay-1)*len(bossDataInfo.SummonTime)
+		this.refreshBossInfoActivityList[refreshInfo.bossData.Id] = refreshInfo
+
+		util.DebugF("getRefreshInfoChangePlay bossid=%v summonidx=%v refreshtime=%v",
+			bossDataInfo.Id, refreshInfo.summonTimeIdx, tmpTime.String())
+		return refreshInfo
+	} else {
+		//todo...
+	}
+
+	return nil
+}
+
+func (this *WorldBossManager) refreshBoss() {
+	if len(this.refreshBossInfoList) <= 0 {
+		return
+	}
+
+	nowTime := util.GetCurrentTimeNow()
+	for _, info := range this.refreshBossInfoList {
+		//util.InfoF("now=%v summon=%v", nowHourTime.String(), info.bossData.SummonTime[info.summonTimeIdx].String())
+		if nowTime.After(info.refreshTime) {
+			//refresh key-pos boss
+			//1,remove old-pos boss
+			//2,add new-pos boss
+			bRefresh := true
+			for _, bossVal := range this.bossList {
+				if bossVal.summonBossType != model.SummonBossType_Normal {
+					continue
+				}
+				if int32(bossVal.bossUid)%4 == info.posId {
+					//正在挑战中的boss不进行刷新处理
+					if bossVal.GetState() == BOSS_STATE_FIGHTING {
+						bRefresh = false
+					} else {
+						DelWorldBossList(bossVal)
+						delete(this.bossList, bossVal.bossUid)
+					}
+					break
+				}
+			}
+
+			if bRefresh {
+				this.AddBossFromRefresh(info.bossData, int32(info.summonTimeIdx))
+			}
+
+			tmpIdx := info.summonTimeIdx % len(info.bossData.SummonTime)
+			//if tmpIdx <= 0 && info.summonTimeIdx > 0 {
+			//	tmpIdx = len(info.bossData.SummonTime)
+			//}
+			startUpTime := service.GetServiceStartupTime()
+			this.startDiffDay = util.GetDurationDay1(startUpTime, uint64(util.GetTimeMilliseconds())) + 1
+			tmpAddDay := this.startDiffDay
+
+			if len(info.bossData.SummonTime) <= tmpIdx+1 {
+				//boss存活时间可能到下一天
+				//判断下一天是否有新的boss刷新
+				if info.refreshTime.Day() == nowTime.Day() {
+					//如果当前刷新时间已经用完,则直接找第二天的刷新时间(需要判断刷新时对应的天数和当前时间做比较)
+					tmpAddDay++
+				}
+				nextBossInfo := this.getCurrentDayBossData(tmpAddDay, info.posId)
+				info.bossData = nextBossInfo
+			}
+
+			if nowTime.Day() != info.refreshTime.Day() { //应对测试期间之前改天数的方式
+				tmpPosId := info.posId
+				info = this.getRefreshInfo(tmpPosId)
+			} else {
+				info.summonTimeIdx++
+
+				k := info.summonTimeIdx % len(info.bossData.SummonTime)
+				tmpTime := this.startUpDayTime.AddDate(0, 0, int(tmpAddDay-1))
+				tmpSummonTime := info.bossData.SummonTime[k].Hour()*60*60 + info.bossData.SummonTime[k].Minute()*60 + info.bossData.SummonTime[k].Second()
+				tmpTime = tmpTime.Add(time.Duration(tmpSummonTime) * time.Second)
+				info.refreshTime = tmpTime
+			}
+			info.printDebugString("RefreshBoss")
+		}
+	}
+}
+
+func (this *WorldBossManager) refreshBossChangePlay(ms uint64) {
+	if len(this.refreshBossInfoActivityList) <= 0 {
+		return
+	}
+	nowTime := util.GetTimeByUint64(ms)
+	for key, info := range this.refreshBossInfoActivityList {
+		//活动过期
+		if nowTime.After(info.bossData.BossEndTime) {
+			bossVal, ok := this.bossList[uint64(info.bossData.Id)]
+			if ok {
+				bossVal.SwitchState(int32(BOSS_STATE_TIME_OUT), nil)
+				delete(this.bossList, uint64(info.bossData.Id))
+			}
+			delete(this.refreshBossInfoActivityList, key)
+			continue
+		}
+
+		if nowTime.Before(info.refreshTime) || nowTime.Before(info.bossData.BossBeginTime) {
+			continue
+		}
+
+		bRefresh := true
+		bossVal, ok := this.bossList[uint64(info.bossData.Id)]
+		if ok {
+			if bossVal.GetState() == BOSS_STATE_FIGHTING {
+				bRefresh = false
+			} else {
+				DelWorldBossList(bossVal)
+				delete(this.bossList, bossVal.bossUid)
+			}
+		}
+		if bRefresh {
+			this.AddBossFromRefresh(info.bossData, int32(info.summonTimeIdx))
+		}
+
+		tmpIdx := info.summonTimeIdx % len(info.bossData.SummonTime)
+		startUpTime := service.GetServiceStartupTime()
+		this.startDiffDay = util.GetDurationDay1(startUpTime, uint64(util.GetTimeMilliseconds())) + 1
+		tmpAddDay := this.startDiffDay
+		if len(info.bossData.SummonTime) <= tmpIdx+1 {
+			//boss存活时间可能到下一天
+			//判断下一天是否有新的boss刷新
+			if info.refreshTime.Day() == nowTime.Day() {
+				//如果当前刷新时间已经用完,则直接找第二天的刷新时间(需要判断刷新时对应的天数和当前时间做比较)
+				tmpAddDay++
+			}
+			info.summonTimeIdx = 0
+		} else {
+			info.summonTimeIdx++
+		}
+
+		if nowTime.Day() != info.refreshTime.Day() { //应对测试期间之前改天数的方式
+			info = this.getRefreshInfoChangePlay(info.bossData)
+		} else {
+			//info.summonTimeIdx++
+
+			k := info.summonTimeIdx % len(info.bossData.SummonTime)
+			tmpTime := this.startUpDayTime.AddDate(0, 0, int(tmpAddDay-1))
+			tmpSummonTime := info.bossData.SummonTime[k].Hour()*60*60 + info.bossData.SummonTime[k].Minute()*60 + info.bossData.SummonTime[k].Second()
+			tmpTime = tmpTime.Add(time.Duration(tmpSummonTime) * time.Second)
+			info.refreshTime = tmpTime
+		}
+
+		if bRefresh {
+			util.DebugF("nextWorldBossRefreshTime=%v", info.refreshTime.String())
+		}
+
+		info.printDebugString("RefreshBoss")
+	}
+}
+
+func (this *WorldBossManager) PlayerOffline(uid uint64) {
+	if playerBoss, ok := this.challengePlayerList[uid]; ok {
+		playerBoss.leaveNotify(uid)
+	}
+}
+
+func (this *WorldBossManager) Update(ms uint64) {
+	switch this.initStartUp {
+	case INIT_STATE_NONE:
+		if GetWorldBossList(this) {
+			this.initStartUp = INIT_STATE_INIT
+			util.InfoF("load from db worldboss len=%v", len(this.bossList))
+		} else {
+			this.initStartUp = INIT_STATE_NONE
+			return
+		}
+	case INIT_STATE_INIT:
+		if !this.initRefresh() {
+			return
+		}
+	}
+
+	if !this.updateTimer.IsStart() || !this.updateTimer.IsExpired(ms) ||
+		this.initStartUp != INIT_STATE_FINISH {
+		return
+	}
+
+	for _, boss := range this.bossList {
+		boss.broadcastBossHp()
+		if boss.finish {
+			//不从列表中删除,客户端实现需要
+			//delete(this.bossList, boss.bossUid)
+			continue
+		}
+		if !boss.checkTimeValid(ms) {
+			boss.SwitchState(int32(BOSS_STATE_TIME_OUT), nil)
+		}
+
+		//处理boss的定时掉血。
+		if boss.GetState() != BOSS_STATE_TIME_OUT && boss.GetState() != BOSS_STATE_DIED {
+			boss.updateBossHp(ms)
+		}
+	}
+
+	//判断是否需要重新刷新boss
+	this.refreshBoss()             //普通世界boss
+	this.refreshBossChangePlay(ms) //活动世界boss
+}
+
+//DB中加载获取boss状态信息
+func (this *WorldBossManager) AddBossFromDB(stateInfo *serverproto.WorldBossStateInfo) bool {
+	var summonId int32 = 0
+	if stateInfo.SummonBossType == model.SummonBossType_Normal {
+		cfgData, ok := model.ConvertWorldBossList[stateInfo.BossId]
+		if !ok {
+			return false
+		}
+		summonId = cfgData.SummonId
+	} else {
+		cfgData, ok := model.ConvertWorldBossChangePlayList[stateInfo.BossId]
+		if !ok {
+			return false
+		}
+		summonId = cfgData.SummonId
+	}
+
+	npcCfgData, ok1 := serverproto.NpcCfgLoader[summonId]
+	if !ok1 {
+		return false
+	}
+
+	playerBoss := newPlayerBoss(this)
+	playerBoss.bossUid = uint64(stateInfo.BossId)
+	playerBoss.summonBossId = summonId
+	playerBoss.summonBossType = stateInfo.SummonBossType
+	playerBoss.summonTime = stateInfo.SummonTime
+	playerBoss.durationTime = uint64(stateInfo.DurationTime) * 1000
+	playerBoss.summonBossIdx = stateInfo.SummonIdx
+	playerBoss.SetTotalHp(stateInfo.Hp)
+	playerBoss.maxHp = int32(npcCfgData.Hp)
+	playerBoss.lastHPReduceTime = 0
+	if playerBoss.totalHp < playerBoss.maxHp {
+		playerBoss.lastHPReduceTime = util.GetTimeMilliseconds()
+	}
+	//add challenge uid
+	for idx := 0; idx < len(stateInfo.UidList); idx++ {
+		playerBoss.allChallengeList.Add(stateInfo.UidList[idx])
+	}
+
+	nowTime := util.GetTimeMilliseconds()
+	endTime := stateInfo.SummonTime + uint64(stateInfo.DurationTime)*1000
+	if endTime <= nowTime {
+		playerBoss.SwitchState(int32(BOSS_STATE_TIME_OUT), true) //表示来自db
+	} else {
+
+		if playerBoss.totalHp <= 0 {
+			playerBoss.SwitchState(int32(BOSS_STATE_DIED), true) //表示来自db
+		} else {
+			playerBoss.SwitchState(int32(BOSS_STATE_FIGHTING), nil)
+		}
+	}
+
+	this.bossList[playerBoss.bossUid] = playerBoss
+
+	util.DebugF("msg=AddBossFromDB bossid=%v summonidx=%v", playerBoss.bossUid, playerBoss.summonBossIdx)
+	return true
+}
+
+const SystemMessageType_WorldBoss = 6 //召喚世界BOSS通知
+func (this *WorldBossManager) AddBossFromRefresh(bossData *model.ConvertWorldBossData, summonIdx int32) bool {
+	var summonId int32 = 0
+	if bossData.SummonType == model.SummonBossType_Normal {
+		cfgData, ok := serverproto.WorldBossCfgLoader[bossData.Id]
+		if !ok {
+			util.InfoF("AddBossFromRefresh WorldBossCfgLoader not find boss=%v ", bossData.Id)
+			return false
+		}
+
+		summonId = cfgData.SummonId
+	} else {
+		cfgData, ok := serverproto.WorldBossChangePlayCfgLoader[bossData.Id]
+		if !ok {
+			util.InfoF("AddBossFromRefresh WorldBossChangePlayCfgLoader not find boss=%v ", bossData.Id)
+			return false
+		}
+
+		summonId = cfgData.SummonId
+	}
+
+	npcCfgData, ok1 := serverproto.NpcCfgLoader[summonId]
+	if !ok1 {
+		util.InfoF("AddBossFromRefresh npc data not find summonid=%v ", summonId)
+		return false
+	}
+	summonHp := int32(npcCfgData.Hp)
+
+	playerBoss := newPlayerBoss(this)
+	playerBoss.bossUid = uint64(bossData.Id)
+	playerBoss.summonBossId = summonId
+	playerBoss.summonTime = util.GetTimeMilliseconds()
+	playerBoss.durationTime = uint64(bossData.DurationTime) * 1000
+	playerBoss.summonBossIdx = summonIdx
+	playerBoss.SetTotalHp(summonHp)
+	playerBoss.lastHPReduceTime = 0
+	playerBoss.summonBossType = bossData.SummonType
+
+	playerBoss.SwitchState(int32(BOSS_STATE_FIGHTING), nil)
+
+	this.bossList[playerBoss.bossUid] = playerBoss
+
+	//add to db
+	UpdateWorldBossList(playerBoss)
+
+	util.DebugF("msg=AddBossFromRefresh bossid=%v summonidx=%v", bossData.Id, summonIdx)
+
+	//发送给所有game服务器
+	ssMsgNtf := &serverproto.SSSystemMessageNtf{}
+	ssMsg := &serverproto.SystemMessage{
+		Type:     SystemMessageType_WorldBoss,
+		ParamId:  []int32{int32(playerBoss.bossUid), bossData.SummonType},
+		SendTime: util.GetTimeMilliseconds(),
+	}
+	ssMsgNtf.SysMsg = append(ssMsgNtf.SysMsg, ssMsg)
+	SendToAllGame(ssMsgNtf)
+
+	return true
+}
+
+func (this *WorldBossManager) PlayerChallengeSummonBoss(uid, challengeBossUid uint64, clientId model.ClientID,
+	fightInfo *serverproto.FightRoleInfo) serverproto.ErrorCode {
+	//当前玩家是否正在挑战boss
+	if bossInfo, ok := this.challengePlayerList[uid]; ok {
+		if bossInfo.finish {
+			delete(this.challengePlayerList, uid)
+		} else {
+			bossInfo.leaveNotify(uid)
+			//util.InfoF("PlayerChallengeSummonBoss already in other boss=%v uid=%v", bossInfo, uid)
+			//return serverproto.ErrorCode_ERROR_AOI_BOSS_CHALLENGING
+		}
+	}
+
+	//查找是否存在Boss
+	bossInfo, ok := this.bossList[challengeBossUid]
+	if !ok {
+		return serverproto.ErrorCode_ERROR_AOI_BOSS_NOT_FOUND
+	}
+
+	ret := bossInfo.canChallenge(uid)
+	if ret != serverproto.ErrorCode_ERROR_OK {
+		return ret
+	}
+
+	//添加挑战玩家信息
+	bossInfo.addChallengePlayer(uid, clientId, fightInfo)
+
+	return serverproto.ErrorCode_ERROR_OK
+}
+
+func (this *WorldBossManager) DoSummonHp(uid, bossUid uint64, damageHp int32) {
+	bossInfo, ok := this.challengePlayerList[uid]
+	if !ok {
+		util.InfoF("DoSummonHp boss not find uId=%v boss=%v damageHp=%v", uid, bossUid, damageHp)
+		return
+	}
+
+	if bossInfo.bossUid != bossUid {
+		util.InfoF("DoSummonHp bossId invalid uid=%v boss=%v dobossid=%v", uid, bossInfo.bossUid, bossUid)
+		return
+	}
+
+	bossInfo.ProcessBattle(damageHp)
+}
+
+func (this *WorldBossManager) GetWorldBossInfo(bossUid uint64) *serverproto.WorldBossContentInfo {
+	bossInfo, ok1 := this.bossList[bossUid]
+	if !ok1 {
+		return nil
+	}
+
+	info := &serverproto.WorldBossContentInfo{
+		BossId:         int32(bossInfo.bossUid),
+		CfgId:          bossInfo.summonBossId,
+		FighterNum:     int32(len(bossInfo.challengeList)),
+		ExpireTime:     bossInfo.summonTime + bossInfo.durationTime,
+		TotalHp:        bossInfo.maxHp,
+		CurHp:          bossInfo.totalHp,
+		BossSummonType: bossInfo.summonBossType,
+	}
+
+	return info
+}
+
+func (this *WorldBossManager) getBossRefreshInfo(posIdx int32) *RefreshBossInfo {
+	if data, ok := this.refreshBossInfoList[posIdx]; ok {
+		return data
+	}
+	return nil
+}
+
+func (this *WorldBossManager) getBossRefreshInfoChangePlay(bossId int32) *RefreshBossInfo {
+	if data, ok := this.refreshBossInfoActivityList[bossId]; ok {
+		refreshTime := uint64(data.refreshTime.Unix()) * 1000
+		if data.bossData.BossEndTimeStmp > refreshTime {
+			return data
+		}
+	}
+	return nil
+}
+
+func (this *WorldBossManager) GetWorldBossList() *serverproto.SCPlayerWorldBossListAck {
+	if len(this.bossList) <= 0 {
+		var tmpAckMsg = &serverproto.SCPlayerWorldBossListAck{}
+		//if len(tmpAckMsg.WorldBossList) > 0 {
+		//	return tmpAckMsg
+		//}
+		//普通世界boss
+		for _, val := range this.refreshBossInfoList {
+			npcCfgData, ok1 := serverproto.NpcCfgLoader[val.bossData.SummonId]
+			if !ok1 {
+				util.InfoF("NpcCfgLoader npc data not find summonid=%v ", val.bossData.SummonId)
+				continue
+			}
+
+			info := &serverproto.WorldBossContentInfo{
+				BossId:          int32(val.bossData.Id),
+				CfgId:           val.bossData.SummonId,
+				FighterNum:      0,
+				ExpireTime:      0,
+				NextRefreshTime: uint64(val.refreshTime.Unix()) * 1000,
+				TotalHp:         int32(npcCfgData.Hp),
+				CurHp:           int32(npcCfgData.Hp),
+			}
+			tmpAckMsg.WorldBossList = append(tmpAckMsg.WorldBossList, info)
+		}
+		//变身类活动世界boss
+		nowTime := util.GetCurrentTimeNow()
+		for _, val := range this.refreshBossInfoActivityList {
+			npcCfgData, ok1 := serverproto.NpcCfgLoader[val.bossData.SummonId]
+			if !ok1 {
+				util.InfoF("NpcCfgLoader npc data not find summonid=%v ", val.bossData.SummonId)
+				continue
+			}
+			if nowTime.Before(val.bossData.BossBeginTime) || nowTime.After(val.bossData.BossEndTime) {
+				continue
+			}
+
+			info := &serverproto.WorldBossContentInfo{
+				BossId:          int32(val.bossData.Id),
+				CfgId:           val.bossData.SummonId,
+				FighterNum:      0,
+				ExpireTime:      0,
+				NextRefreshTime: uint64(val.refreshTime.Unix()) * 1000,
+				TotalHp:         int32(npcCfgData.Hp),
+				CurHp:           int32(npcCfgData.Hp),
+				BossSummonType:  val.bossData.SummonType,
+			}
+			tmpAckMsg.WorldBossList = append(tmpAckMsg.WorldBossList, info)
+		}
+		return tmpAckMsg
+	} else {
+		ackMsg := &serverproto.SCPlayerWorldBossListAck{}
+		nowTime := util.GetTimeMilliseconds()
+		hasBossList := set.New(set.NonThreadSafe)
+		hasChangePlayBossList := set.New(set.NonThreadSafe)
+		for _, bossInfo := range this.bossList {
+			if bossInfo.summonBossType <= 0 {
+				hasBossList.Add(int32(bossInfo.bossUid) % 4)
+			} else {
+				hasChangePlayBossList.Add(int32(bossInfo.bossUid))
+			}
+			info := &serverproto.WorldBossContentInfo{
+				BossId:        int32(bossInfo.bossUid),
+				BossSummonIdx: bossInfo.summonBossIdx,
+				CfgId:         bossInfo.summonBossId,
+				FighterNum:    int32(len(bossInfo.challengeList)),
+				//ExpireTime:     bossInfo.summonTime + bossInfo.durationTime,
+				TotalHp:        bossInfo.maxHp,
+				CurHp:          bossInfo.totalHp,
+				BossSummonType: bossInfo.summonBossType,
+			}
+
+			expireTime := bossInfo.summonTime + bossInfo.durationTime
+			if bossInfo.summonBossType == model.SummonBossType_ChangePlay {
+				changBossDataInfo, ok := model.ConvertWorldBossChangePlayList[int32(bossInfo.bossUid)]
+				if ok {
+					if expireTime > changBossDataInfo.BossEndTimeStmp {
+						expireTime = changBossDataInfo.BossEndTimeStmp
+					}
+				}
+			}
+			info.ExpireTime = expireTime
+
+			if nowTime > expireTime || bossInfo.totalHp <= 0 {
+				info.FighterNum = 0
+				info.ExpireTime = 0
+
+				switch bossInfo.summonBossType {
+				case model.SummonBossType_Normal:
+					bossRefreshInfo := this.getBossRefreshInfo(info.BossId % 4)
+					if bossRefreshInfo != nil {
+						info.NextRefreshTime = uint64(bossRefreshInfo.refreshTime.Unix()) * 1000
+					}
+				case model.SummonBossType_ChangePlay:
+					bossRefreshInfo := this.getBossRefreshInfoChangePlay(info.BossId)
+					if bossRefreshInfo != nil {
+						info.NextRefreshTime = uint64(bossRefreshInfo.refreshTime.Unix()) * 1000
+					} else {
+						continue
+					}
+				}
+			}
+			ackMsg.WorldBossList = append(ackMsg.WorldBossList, info)
+		}
+
+		for _, val := range this.refreshBossInfoList {
+			if hasBossList.Has(val.posId) {
+				continue
+			}
+			npcCfgData, ok1 := serverproto.NpcCfgLoader[val.bossData.SummonId]
+			if !ok1 {
+				util.InfoF("NpcCfgLoader npc data not find summonid=%v ", val.bossData.SummonId)
+				continue
+			}
+
+			info := &serverproto.WorldBossContentInfo{
+				BossId:          int32(val.bossData.Id),
+				CfgId:           val.bossData.SummonId,
+				FighterNum:      0,
+				ExpireTime:      0,
+				NextRefreshTime: uint64(val.refreshTime.Unix()) * 1000,
+				TotalHp:         int32(npcCfgData.Hp),
+				CurHp:           int32(npcCfgData.Hp),
+			}
+			ackMsg.WorldBossList = append(ackMsg.WorldBossList, info)
+		}
+
+		nowTime1 := util.GetCurrentTimeNow()
+		for _, val := range this.refreshBossInfoActivityList {
+			if hasChangePlayBossList.Has(val.bossData.Id) {
+				continue
+			}
+			npcCfgData, ok1 := serverproto.NpcCfgLoader[val.bossData.SummonId]
+			if !ok1 {
+				util.InfoF("NpcCfgLoader npc data not find summonid=%v ", val.bossData.SummonId)
+				continue
+			}
+			if nowTime1.Before(val.bossData.BossBeginTime) || nowTime1.After(val.bossData.BossEndTime) {
+				continue
+			}
+
+			info := &serverproto.WorldBossContentInfo{
+				BossId:          int32(val.bossData.Id),
+				CfgId:           val.bossData.SummonId,
+				FighterNum:      0,
+				ExpireTime:      0,
+				NextRefreshTime: uint64(val.refreshTime.Unix()) * 1000,
+				TotalHp:         int32(npcCfgData.Hp),
+				CurHp:           int32(npcCfgData.Hp),
+				BossSummonType:  val.bossData.SummonType,
+			}
+			ackMsg.WorldBossList = append(ackMsg.WorldBossList, info)
+		}
+
+		return ackMsg
+	}
+}

+ 28 - 0
RO_Server_Trunk-branch_0.1.39/roserver/battleboss/model/boss_model.go

@@ -0,0 +1,28 @@
+package model
+
+import (
+	"rocommon"
+)
+
+var (
+	updateList []interface{}
+
+	AoiLineMag *WorldBossManager = nil
+)
+
+type BossUpdate struct {
+	rocommon.UpdateModule //eventqueue.go
+}
+
+//定义初始化模块,比方说角色管理模块,任务模块等,然后通过update来处理定时器相关的处理
+func (this *BossUpdate) Init() {
+	AoiLineMag = newWorldBossManager()
+	updateList = append(updateList, AoiLineMag)
+}
+
+func (this *BossUpdate) Update(ms uint64) {
+	//对管理器进行更新操作
+	for _, data := range updateList {
+		data.(rocommon.UpdateLogic).Update(ms)
+	}
+}

+ 129 - 0
RO_Server_Trunk-branch_0.1.39/roserver/battleboss/model/boss_orm_helper.go

@@ -0,0 +1,129 @@
+package model
+
+import (
+	"encoding/base64"
+	"rocommon"
+	"rocommon/service"
+	"rocommon/util"
+	"roserver/baseserver/model"
+	"roserver/serverproto"
+	"strconv"
+)
+
+const (
+	WorldBossStatePrefix        = "wb_state_"
+	WorldBossStateUidListPrefix = "wb_state_list_"
+)
+
+func GetWorldBossList(bossMag *WorldBossManager) bool {
+	wbList, err := service.GetRedis().HGetAll(WorldBossStatePrefix).Result()
+	if err != nil && err != service.NIL {
+		util.InfoF("GetWorldBossList key=%v err=%v", WorldBossStatePrefix, err)
+		return false
+	}
+
+	for key, val := range wbList {
+		worldBossId, _ := model.Str2Num(key)
+		if worldBossId > 0 {
+			msgStr, err := base64.StdEncoding.DecodeString(val)
+			if err != nil {
+				util.InfoF("GetWorldBossList key=%v err=%v", key, err)
+				continue
+			}
+			stateInfo := &serverproto.WorldBossStateInfo{}
+			err = rocommon.GetCodec().Unmarshal(msgStr, stateInfo)
+			if err != nil {
+				continue
+			}
+
+			//challenge uid list
+			key := WorldBossStateUidListPrefix + key
+			uidListLen, err := service.GetRedis().LLen(key).Result()
+			if uidListLen > 0 {
+				var idx int64 = 0
+				for {
+					uidStrList, _ := service.GetRedis().LRange(key, idx, idx+200).Result()
+					if len(uidStrList) <= 0 {
+						break
+					}
+					for idx := 0; idx < len(uidStrList); idx++ {
+						tmpUid, _ := model.Str2NumU64(uidStrList[idx])
+						if tmpUid > 0 {
+							stateInfo.UidList = append(stateInfo.UidList, tmpUid)
+						}
+					}
+
+					idx += 100
+					if idx >= uidListLen {
+						break
+					}
+				}
+			}
+			util.InfoF("GetWorldBossList key=%v err=%v len=%v", key, err, uidListLen)
+			//add failed,then remove current item
+			if !bossMag.AddBossFromDB(stateInfo) {
+				service.GetRedis().HDel(WorldBossStatePrefix, key)
+			}
+		}
+	}
+
+	return true
+}
+
+func UpdateWorldBossList(bossInfo *PlayerBoss) bool {
+	if bossInfo.bossUid <= 0 {
+		util.InfoF("UpdateWorldBossList bossId=%v", bossInfo.bossUid)
+		return false
+	}
+
+	stateInfo := &serverproto.WorldBossStateInfo{
+		BossId:         int32(bossInfo.bossUid),
+		Hp:             bossInfo.totalHp,
+		SummonTime:     bossInfo.summonTime,
+		DurationTime:   int32(bossInfo.durationTime / 1000),
+		SummonIdx:      bossInfo.summonBossIdx,
+		SummonBossType: bossInfo.summonBossType,
+	}
+
+	msgData, err := rocommon.GetCodec().Marshal(stateInfo)
+	if err != nil {
+		util.InfoF("UpdateWorldBossList bossId=%v err=%v", bossInfo.bossUid, err)
+		return false
+	}
+	msgStr := base64.StdEncoding.EncodeToString(msgData.([]byte))
+	fieldStr := strconv.Itoa(int(bossInfo.bossUid))
+	service.GetRedis().HSet(WorldBossStatePrefix, fieldStr, msgStr)
+
+	return true
+}
+
+func DelWorldBossList(bossInfo *PlayerBoss) bool {
+	if bossInfo.bossUid <= 0 {
+		util.InfoF("UpdateWorldBossList bossId=%v", bossInfo.bossUid)
+		return false
+	}
+
+	//boss info
+	fieldStr := strconv.Itoa(int(bossInfo.bossUid))
+	service.GetRedis().HDel(WorldBossStatePrefix, fieldStr)
+
+	//boss challenge uid list
+	bossIdStr := strconv.Itoa(int(bossInfo.bossUid))
+	keyStr := WorldBossStateUidListPrefix + bossIdStr
+	service.GetRedis().Del(keyStr)
+
+	return true
+}
+
+func WorldBossListAddChallenge(bossInfo *PlayerBoss, uid uint64) bool {
+	if uid <= 0 || bossInfo.bossUid <= 0 {
+		util.ErrorF("UpdateWorldBossList bossId=%v", bossInfo.bossUid)
+		return false
+	}
+
+	bossIdStr := strconv.Itoa(int(bossInfo.bossUid))
+	keyStr := WorldBossStateUidListPrefix + bossIdStr
+	service.GetRedis().LPush(keyStr, uid)
+
+	return true
+}

+ 455 - 0
RO_Server_Trunk-branch_0.1.39/roserver/battleboss/model/boss_player.go

@@ -0,0 +1,455 @@
+package model
+
+import (
+	"container/heap"
+	"math/rand"
+	"rocommon/util"
+	"roserver/baseserver/model"
+	"roserver/baseserver/set"
+	"roserver/serverproto"
+	"sort"
+)
+
+////////////////////////////////PlayerBoss
+type BossRoom struct {
+	roomId  int32
+	uidList map[uint64]struct{}
+}
+
+func (this *BossRoom) AddUid(uid uint64) {
+	this.uidList[uid] = struct{}{}
+}
+
+func (this *BossRoom) RemUid(uid uint64) {
+	delete(this.uidList, uid)
+}
+
+type PlayerBoss struct {
+	model.StateMachineCore
+
+	mag            *WorldBossManager
+	bossUid        uint64 //worldbosscfgid
+	summonBossId   int32  //bossCfgId
+	summonBossType int32  //SummonBossType
+	summonBossIdx  int32  //召唤次数
+	summonTime     uint64 //召唤时间戳
+	durationTime   uint64 //boss持续时间s
+	totalHp        int32
+	maxHp          int32
+	hpDirty        bool
+
+	SummonRewardList                            []*serverproto.KeyValueType //参与boss挑战奖励
+	KillNormalRewardList, KillSpecialRewardList serverproto.KeyValueType    //击杀参与奖 drop //击杀大奖 drop
+
+	challengeList     map[uint64]model.ClientID             //当前正在挑战的玩家列表
+	allChallengeList  set.Interface                         //挑战玩家列表,包行当前正在挑战玩家
+	challengeDataList map[uint64]*serverproto.FightRoleInfo //玩家数据
+
+	maxPoint int32 //最大点数
+
+	uidRoomList      map[uint64]int32    //[uid,roomId]
+	roomList         map[int32]*BossRoom //[roomId,[uid...]]
+	freeRoomList     *model.MinHeap      //[roomId]
+	maxRoomId        int32
+	lastHPReduceTime uint64
+
+	finish bool
+}
+
+func newPlayerBoss(mag *WorldBossManager) *PlayerBoss {
+	playerBoss := &PlayerBoss{
+		mag:         mag,
+		roomList:    map[int32]*BossRoom{},
+		uidRoomList: map[uint64]int32{},
+	}
+	playerBoss.challengeList = map[uint64]model.ClientID{}
+	playerBoss.allChallengeList = set.New(set.NonThreadSafe)
+	playerBoss.challengeDataList = map[uint64]*serverproto.FightRoleInfo{}
+	//min heap
+	playerBoss.freeRoomList = &model.MinHeap{}
+	heap.Init(playerBoss.freeRoomList)
+
+	return playerBoss
+}
+
+func (this *PlayerBoss) Init() {
+	this.InitState()
+
+	this.RegisterState(int32(BOSS_STATE_FIGHTING), bossStateFighting)
+	this.RegisterState(int32(BOSS_STATE_DIED), bossStateDie)
+	this.RegisterState(int32(BOSS_STATE_TIME_OUT), bossStateTimeout)
+}
+
+func (this *PlayerBoss) SetTotalHp(hp int32) {
+	this.totalHp = hp
+	this.maxHp = hp
+}
+
+func (this *PlayerBoss) clear() {
+	for uid, _ := range this.challengeList {
+		delete(this.mag.challengePlayerList, uid)
+		delete(this.challengeList, uid)
+	}
+
+	this.allChallengeList.Clear()
+	this.challengeDataList = map[uint64]*serverproto.FightRoleInfo{}
+
+	this.maxRoomId = 0
+	this.uidRoomList = map[uint64]int32{}
+	this.roomList = map[int32]*BossRoom{}
+}
+
+//是否在挑战boss时间内
+func (this *PlayerBoss) checkTimeValid(nowTime uint64) bool {
+	if this.summonTime > 0 {
+		oldTime := this.summonTime + this.durationTime
+		return oldTime > nowTime
+	}
+	return false
+}
+
+func (this *PlayerBoss) addChallengePlayer(uid uint64, id model.ClientID, roleData *serverproto.FightRoleInfo) {
+	if !this.allChallengeList.Has(uid) {
+		this.allChallengeList.Add(uid)
+		WorldBossListAddChallenge(this, uid)
+	}
+
+	//self
+	this.bossChangePlay(roleData)
+	this.challengeList[uid] = id
+	this.challengeDataList[uid] = roleData
+
+	//manager
+	this.mag.challengePlayerList[uid] = this
+
+	//use for notify(enter/leave)
+	var tmpRoomId int32 = 0
+	if this.freeRoomList.Len() > 0 {
+		tmpRoomId = heap.Pop(this.freeRoomList).(int32)
+	} else {
+		this.maxRoomId++
+		tmpRoomId = this.maxRoomId
+	}
+	this.uidRoomList[uid] = tmpRoomId
+	if this.roomList[tmpRoomId] == nil {
+		this.roomList[tmpRoomId] = &BossRoom{
+			uidList: map[uint64]struct{}{},
+		}
+	}
+	this.roomList[tmpRoomId].AddUid(uid)
+	if len(this.roomList[tmpRoomId].uidList) < MAX_BOSS_CHALLENGE_PLAYER_NUM {
+		heap.Push(this.freeRoomList, tmpRoomId)
+	}
+
+	//通知自己和其他玩家
+	this.enterNotify(uid, tmpRoomId)
+}
+
+//玩家挑战boss触发变身操作
+func (this *PlayerBoss) bossChangePlay(roleData *serverproto.FightRoleInfo) {
+	switch this.summonBossType {
+	case model.SummonBossType_ChangePlay:
+		cfgData, ok := model.ConvertWorldBossChangePlayList[int32(this.bossUid)]
+		if !ok {
+			util.InfoF("AddBossFromRefresh WorldBossChangePlayCfgLoader not find boss=%v ", this.summonBossId)
+			return
+		}
+		changePlayId := cfgData.RandChangePlayId()
+		if changePlayId > 0 {
+			roleData.ChangePlayId = changePlayId
+		}
+	}
+}
+
+func (this *PlayerBoss) canChallenge(uid uint64) serverproto.ErrorCode {
+	if len(this.challengeList) >= 1000 {
+		return serverproto.ErrorCode_ERROR_AOI_BOSS_CHALLENGE_NUM_LIMIT
+	}
+
+	if this.totalHp <= 0 {
+		return serverproto.ErrorCode_ERROR_AOI_BOSS_NOT_FOUND
+	}
+
+	return serverproto.ErrorCode_ERROR_OK
+}
+
+//通知自己和其他玩家
+func (this *PlayerBoss) enterNotify(enterUid uint64, roomId int32) {
+	//发送其他玩家信息给自己,并发送自己信息给其他玩家
+	selfNtfMsg := &serverproto.SSPlayerEnterChallengeNtf{
+		BossUid:          this.bossUid,
+		EnterUid:         enterUid,
+		SelfChangePlayId: this.challengeDataList[enterUid].ChangePlayId,
+		SummonBossType:   this.summonBossType,
+	}
+	otherNtfMsg := &serverproto.SSPlayerEnterChallengeNtf{
+		BossUid:        this.bossUid,
+		EnterUid:       enterUid,
+		SummonBossType: this.summonBossType,
+	}
+	otherNtfMsg.FightList = append(otherNtfMsg.FightList, this.challengeDataList[enterUid])
+
+	var otherSendList = map[string][]uint64{}
+	roomInfo := this.roomList[roomId]
+	for tmpUid, _ := range roomInfo.uidList {
+		if tmpUid == enterUid {
+			continue
+		}
+		tmpUidCli, ok := this.challengeList[tmpUid]
+		if !ok {
+			continue
+		}
+		selfNtfMsg.FightList = append(selfNtfMsg.FightList, this.challengeDataList[tmpUid])
+		otherSendList[tmpUidCli.ServiceID] = append(otherSendList[tmpUidCli.ServiceID], tmpUid)
+	}
+
+	sort.Slice(selfNtfMsg.FightList, func(i, j int) bool {
+		return selfNtfMsg.FightList[i].BriefInfo.Uid < selfNtfMsg.FightList[j].BriefInfo.Uid
+	})
+	//send self
+	this.mag.SendGame(selfNtfMsg, this.challengeList[enterUid].ServiceID, 0)
+
+	//send other
+	for idx := range otherSendList {
+		otherNtfMsg.NotifyList = otherNtfMsg.NotifyList[:0]
+		otherNtfMsg.NotifyList = append(otherSendList[idx])
+		this.mag.SendGame(otherNtfMsg, idx, 0)
+	}
+}
+
+//离开boss,发送其他玩家信息给当前玩家
+func (this *PlayerBoss) leaveNotify(leaveUid uint64) {
+	var notifyList = map[string][]uint64{}
+	if leaveUidData, ok := this.challengeList[leaveUid]; ok {
+		//需要做rand点处理
+		_, ok := this.mag.challengePlayerList[leaveUid]
+		if ok {
+			//需要做rand点处理
+			pointNtfMsg := &serverproto.SCPlayerWorldBossRandNtf{
+				PointInfo: &serverproto.WorldBossRandPointInfo{
+					BossSummonType: this.summonBossType,
+				},
+			}
+			pointNtfMsg.PointInfo.BossId = int32(this.bossUid)
+			pointNtfMsg.PointInfo.BossSummonIdx = this.summonBossIdx
+			this.mag.SendGame(pointNtfMsg, leaveUidData.ServiceID, leaveUid)
+
+			delete(this.mag.challengePlayerList, leaveUid)
+		}
+		delete(this.challengeList, leaveUid)
+
+		if roomId, ok := this.uidRoomList[leaveUid]; ok {
+			roomInfo := this.roomList[roomId]
+			for tmpUid, _ := range roomInfo.uidList {
+				if tmpUid == leaveUid {
+					continue
+				}
+
+				if notifyData, ok := this.challengeList[tmpUid]; ok {
+					notifyList[notifyData.ServiceID] = append(notifyList[notifyData.ServiceID], tmpUid)
+				}
+			}
+
+			roomInfo.RemUid(leaveUid)
+			bPushed := false
+			for idx := 0; idx < this.freeRoomList.Len(); idx++ {
+				if this.freeRoomList.ItemList[idx] == roomId {
+					bPushed = true
+					break
+				}
+			}
+			if !bPushed {
+				heap.Push(this.freeRoomList, roomId)
+			}
+			delete(this.uidRoomList, leaveUid)
+		}
+	}
+
+	leaveNtfMsg := &serverproto.SSPlayerLeaveChallengeNtf{
+		LeaveUid: leaveUid,
+	}
+	for serviceNode := range notifyList {
+		leaveNtfMsg.NotifyList = leaveNtfMsg.NotifyList[:0]
+		leaveNtfMsg.NotifyList = append(notifyList[serviceNode])
+		this.mag.SendGame(leaveNtfMsg, serviceNode, 0)
+	}
+}
+
+func (this *PlayerBoss) updateBossHp(ms uint64) {
+	//boss没人打过,则不触发掉血
+	if this.GetState() == BOSS_STATE_TIME_OUT {
+		return
+	}
+	if this.totalHp >= this.maxHp || this.lastHPReduceTime == 0 {
+		return
+	}
+	cfgData, ok := model.ConvertWorldBossList[int32(this.bossUid)]
+	if !ok || cfgData.ReduceHp.Key <= 0 || cfgData.ReduceHp.Value <= 0 {
+		return
+	}
+
+	if ms > this.lastHPReduceTime+uint64(cfgData.ReduceHp.Key)*1000 {
+		reduceHp := (this.maxHp / 10000) * cfgData.ReduceHp.Value
+		if reduceHp > 0 {
+			this.hpDirty = true
+			this.totalHp -= reduceHp
+			if this.totalHp <= 0 {
+				this.totalHp = 0
+				util.InfoF("update world boss reduce hp bossid= %v  hp= %v", this.bossUid, cfgData.ReduceHp.Value)
+				this.SwitchState(int32(BOSS_STATE_DIED), nil)
+			}
+			this.lastHPReduceTime = ms
+		}
+	}
+}
+
+func (this *PlayerBoss) broadcastBossHp() {
+	if len(this.challengeList) <= 0 {
+		return
+	}
+
+	if !this.hpDirty {
+		return
+	}
+	this.hpDirty = false
+
+	//update to db
+	UpdateWorldBossList(this)
+
+	var notifyList = map[string][]uint64{}
+	for uid, data := range this.challengeList {
+		notifyList[data.ServiceID] = append(notifyList[data.ServiceID], uid)
+	}
+
+	hpNtfMsg := &serverproto.SSPlayerChallengeHpNtf{
+		CurBossHp: this.totalHp,
+	}
+	sendCount := 50
+	for serviceNode := range notifyList {
+		uidLen := len(notifyList[serviceNode])
+		if uidLen <= 0 {
+			continue
+		}
+
+		idx := 0
+		if uidLen > sendCount {
+			idx = 0
+		}
+		for {
+			if idx+sendCount < uidLen {
+				hpNtfMsg.NotifyList = notifyList[serviceNode][idx : idx+sendCount]
+				idx += sendCount
+			} else {
+				hpNtfMsg.NotifyList = notifyList[serviceNode][idx:uidLen]
+				this.mag.SendGame(hpNtfMsg, serviceNode, 0)
+				break
+			}
+			this.mag.SendGame(hpNtfMsg, serviceNode, 0)
+		}
+	}
+}
+
+func (this *PlayerBoss) broadcastResult(result int32) {
+	if len(this.challengeList) <= 0 {
+		return
+	}
+	var notifyList = map[string][]uint64{}
+	for uid, data := range this.challengeList {
+		notifyList[data.ServiceID] = append(notifyList[data.ServiceID], uid)
+	}
+
+	resultNtfMsg := &serverproto.SSPlayerChallengeResultNtf{
+		Result: result,
+	}
+	for serviceNode := range notifyList {
+		resultNtfMsg.NotifyList = resultNtfMsg.NotifyList[:0]
+		resultNtfMsg.NotifyList = append(notifyList[serviceNode])
+		this.mag.SendGame(resultNtfMsg, serviceNode, 0)
+	}
+}
+
+func (this *PlayerBoss) battleTimeOut(fromDB bool) {
+	util.InfoF("battleTimeOut bossid=%v", this.bossUid)
+
+	if !fromDB {
+		//非正常结束战斗
+		this.broadcastResult(BOSS_RESULT_TIME_OUT)
+	}
+
+	this.finish = true
+	//清理数据
+	this.clear()
+}
+
+func (this *PlayerBoss) battleBossDie(fromDB bool) {
+	util.InfoF("battleWin bossid=%v", this.bossUid)
+
+	if !fromDB {
+		this.broadcastResult(BOSS_RESULT_WIN)
+		this.battleReward()
+	}
+
+	this.finish = true
+	//清理数据
+	this.clear()
+}
+
+func (this *PlayerBoss) battleReward() {
+	if len(this.challengeList) > 0 {
+		//需要做rand点处理
+		pointNtfMsg := &serverproto.SCPlayerWorldBossRandNtf{
+			PointInfo: &serverproto.WorldBossRandPointInfo{},
+		}
+
+		for uid, data := range this.challengeList {
+			pointNtfMsg.PointInfo.BossId = int32(this.bossUid)
+			this.mag.SendGame(pointNtfMsg, data.ServiceID, uid)
+		}
+	}
+
+	////参与boss奖励
+	//// 发送邮件奖励
+	//cfgData, ok := model.ConvertWorldBossList[int32(this.bossUid)]
+	//if ok {
+	//	normalMailNtfMsg := &serverproto.SSAddMailNtf{
+	//		MailConfigId: BOSS_REWARD_MAIL_CONFIG_ID_Other,
+	//		MailType:     int32(serverproto.MailType_MailType_Boss),
+	//	}
+	//	normalMailNtfMsg.RewardList = append(normalMailNtfMsg.RewardList, cfgData.SummonRewardList...)
+	//	normalMailNtfMsg.MailParamList = append(normalMailNtfMsg.MailParamList, cfgData.Id)
+	//
+	//	for _, data := range this.allChallengeList.List() {
+	//		normalMailNtfMsg.NotifyList = append(normalMailNtfMsg.NotifyList, data.(uint64))
+	//	}
+	//
+	//	this.mag.SendSocial(normalMailNtfMsg)
+	//}
+}
+
+//boss战斗
+func (this *PlayerBoss) ProcessBattle(damageHp int32) {
+	if this.totalHp > 0 && damageHp > 0 {
+		this.hpDirty = true
+		this.totalHp -= damageHp
+		if this.totalHp <= 0 {
+			this.totalHp = 0
+			util.InfoF("ProcessBattle battle finish success")
+			this.SwitchState(int32(BOSS_STATE_DIED), nil)
+		}
+		this.lastHPReduceTime = util.GetTimeMilliseconds()
+	}
+}
+
+func (this *PlayerBoss) RandPoint(uid uint64) (serverproto.ErrorCode, bool, int32) {
+	_, ok := this.challengeDataList[uid]
+	if !ok {
+		return serverproto.ErrorCode_ERROR_FAIL, false, 0
+	}
+
+	rand.Seed(int64(util.GetTimeMilliseconds()))
+	randNum := rand.Int31n(100) + 1
+	if randNum >= this.maxPoint {
+		return serverproto.ErrorCode_ERROR_OK, true, randNum
+	}
+	return serverproto.ErrorCode_ERROR_OK, false, randNum
+}

+ 40 - 0
RO_Server_Trunk-branch_0.1.39/roserver/battleboss/model/boss_player_state.go

@@ -0,0 +1,40 @@
+package model
+
+import (
+	"roserver/baseserver/model"
+	"unsafe"
+)
+
+const (
+	BOSS_STATE_FIGHTING = 1 //正在战斗中
+	BOSS_STATE_DIED     = 2 //死亡
+	BOSS_STATE_TIME_OUT = 3 //召唤持续时间达到上限
+	BOSS_STATE_REFRESH  = 4 //系统刷新方式
+)
+
+var bossStateFighting = func(r *model.StateMachineCore, data interface{}) int32 {
+	//parent := unsafe.Pointer(r)
+	//return (*PlayerBoss)(parent).pullingRoleList()
+	//return ROLE_STATE_PULLING_LIST
+	return BOSS_STATE_FIGHTING
+}
+
+var bossStateDie = func(r *model.StateMachineCore, data interface{}) int32 {
+	parent := unsafe.Pointer(r)
+	if data != nil {
+		(*PlayerBoss)(parent).battleBossDie(data.(bool))
+	} else {
+		(*PlayerBoss)(parent).battleBossDie(false)
+	}
+	return BOSS_STATE_DIED
+}
+
+var bossStateTimeout = func(r *model.StateMachineCore, data interface{}) int32 {
+	parent := unsafe.Pointer(r)
+	if data != nil {
+		(*PlayerBoss)(parent).battleTimeOut(data.(bool))
+	} else {
+		(*PlayerBoss)(parent).battleTimeOut(false)
+	}
+	return BOSS_STATE_TIME_OUT
+}

+ 61 - 0
RO_Server_Trunk-branch_0.1.39/roserver/battleboss/model/config.go

@@ -0,0 +1,61 @@
+package model
+
+import (
+	"os"
+	"rocommon/service"
+	"rocommon/util"
+	"roserver/baseserver/model"
+	"runtime/debug"
+)
+
+func ConfigInit() {
+	defer func() {
+		if err := recover(); err != nil {
+			util.InfoF("Stack---::%v\n%s\n", err, string(debug.Stack()))
+			panic(nil)
+		}
+	}()
+
+	sConfig := service.GetServiceConfig()
+	model.BaseConfigInit(sConfig)
+}
+
+var WorldBossFileName = "WorldBossState.bin"
+var fileWorldBoss *os.File = nil
+
+type TestBin struct {
+	BossId          int32
+	ChallengeIdList []uint64
+}
+
+func WorldBossWrite2File() {
+	if fileWorldBoss == nil {
+		var err error = nil
+		fileWorldBoss, err = os.OpenFile(WorldBossFileName, os.O_CREATE|os.O_RDWR|os.O_APPEND, 0660)
+		if err != nil {
+			panic(err)
+		}
+	}
+	//todo...
+
+	//info := &TestBin{
+	//	BossId: 10001,
+	//}
+	//for i := 1; i < 2000; i++ {
+	//	info.ChallengeIdList = append(info.ChallengeIdList, uint64(i))
+	//}
+	//var binBuf bytes.Buffer
+	//binary.Write(&binBuf, binary.LittleEndian, info)
+	//b := binBuf.Len()
+	//fileWorldBoss.
+	//_, err := fileWorldBoss.Write(binBuf.Bytes())
+	//if err != nil {
+	//	log.Print("err:", err)
+	//	return
+	//}
+
+}
+
+func WorldBossReadFromFile() {
+	//todo...
+}

+ 146 - 0
RO_Server_Trunk-branch_0.1.39/roserver/battleboss/model/msg_send.go

@@ -0,0 +1,146 @@
+package model
+
+import (
+	"rocommon/rpc"
+	"rocommon/util"
+	"roserver/baseserver/model"
+	"roserver/serverproto"
+)
+
+/////////////////////////////////////////////发送数据
+func (this *WorldBossManager) SendMapRouter(msg interface{}, uid uint64) bool {
+	data, meta, err := rpc.EncodeMessage(msg)
+	if err != nil {
+		util.InfoF("[SendMapRouter] EncodeMessage err:%v %v", err, msg)
+		return false
+	}
+
+	if this.mapRouterNode == "" {
+		this.mapRouterNode = model.SelectServiceNode(model.SERVICE_NODE_TYPE_MAP_ROUTER_STR, 0)
+	}
+	if this.mapRouterNode == "" {
+		util.InfoF("[SendMapRouter] map router node not exist msg:%v", msg)
+		return false
+	}
+
+	mapRouterSess := model.GetServiceNode(this.mapRouterNode)
+	if mapRouterSess == nil {
+		util.InfoF("[SendMapRouter] aoiRouter session not exist:%v", this.mapRouterNode)
+	} else {
+		//如果玩家信息存在,ClientId中存放的是玩家ID,否则存放的是玩家的gate sessionId
+		mapRouterSess.Send(&serverproto.ServiceTransmitAck{
+			MsgId:   uint32(meta.ID),
+			MsgData: data,
+			//todo...
+			// 对应的玩家 gate channelId channelRoleList[key]
+			// 后续和gate直接通信时使用,如果断线重连需要重新绑定
+			ClientId: uid, //对应的玩家 gate uuid uuidRoleList[key]
+		})
+	}
+	return true
+}
+
+func (this *WorldBossManager) SendSocial(msg interface{}) bool {
+	data, meta, err := rpc.EncodeMessage(msg)
+	if err != nil {
+		util.ErrorF("[SendSocial] EncodeMessage err:%v %v", err, msg)
+		return false
+	}
+
+	if this.socialNode == "" {
+		this.socialNode = model.SelectServiceNode(model.SERVICE_NODE_TYPE_SOCIAL_STR, 0)
+	}
+	if this.socialNode == "" {
+		util.ErrorF("[SendSocial] social node not exist msg:%v", msg)
+		return false
+	}
+
+	socialSess := model.GetServiceNode(this.socialNode)
+	if socialSess == nil {
+		util.ErrorF("[SendSocial] social session not exist:%v", this.mapRouterNode)
+	} else {
+		//如果玩家信息存在,ClientId中存放的是玩家ID,否则存放的是玩家的gate sessionId
+		socialSess.Send(&serverproto.ServiceTransmitAck{
+			MsgId:   uint32(meta.ID),
+			MsgData: data,
+		})
+	}
+	return true
+}
+
+func SendDB(msg interface{}) bool {
+	data, meta, err := rpc.EncodeMessage(msg)
+	if err != nil {
+		util.InfoF("[SendDB] EncodeMessage err:%v %v", err, msg)
+		return false
+	}
+
+	dbNode := model.SelectServiceNode(model.SERVICE_NODE_TYPE_DB_STR, 0)
+	if dbNode == "" {
+		util.InfoF("[SendDB] db node not exist msg:%v", msg)
+		return false
+	}
+
+	dbSess := model.GetServiceNode(dbNode)
+	if dbSess == nil {
+		util.ErrorF("[SendDB] db session not exist:%v", dbSess)
+		return false
+	} else {
+		//如果玩家信息存在,ClientId中存放的是玩家ID,否则存放的是玩家的gate sessionId
+		dbSess.Send(&serverproto.ServiceTransmitAck{
+			MsgId:   uint32(meta.ID),
+			MsgData: data,
+		})
+	}
+	return true
+}
+
+func (this *WorldBossManager) SendGame(msg interface{}, gameNode string, uid uint64) bool {
+	return this.SendServiceByNode(msg, gameNode, uid)
+}
+
+func (this *WorldBossManager) SendServiceByNode(msg interface{}, serviceNode string, uid uint64) bool {
+	data, meta, err := rpc.EncodeMessage(msg)
+	if err != nil {
+		util.InfoF("[SendServiceByNode] EncodeMessage err:%v %v", err, msg)
+		return false
+	}
+
+	nodeSess := model.GetServiceNode(serviceNode)
+	if nodeSess == nil {
+		util.InfoF("[SendServiceByNode] service session not exist:%v", serviceNode)
+	} else {
+		//如果玩家信息存在,ClientId中存放的是玩家ID,否则存放的是玩家的gate sessionId
+		ackMsg := &serverproto.ServiceTransmitAck{
+			MsgId:   uint32(meta.ID),
+			MsgData: data,
+		}
+		if uid != 0 {
+			ackMsg.ClientId = uid
+		}
+		nodeSess.Send(ackMsg)
+	}
+	return true
+}
+
+func SendToAllGame(msg interface{}) {
+	data, info, err := rpc.EncodeMessage(msg)
+	if err != nil {
+		util.InfoF("[SendGame]EncodeMessage err:%v %v", err, msg)
+		return
+	}
+	sendMsg := &serverproto.ServiceTransmitAck{
+		MsgId:   uint32(info.ID),
+		MsgData: data,
+	}
+
+	serviceList := model.GetAllServiceNodeByName(model.SERVICE_NODE_TYPE_GAME_STR)
+	if len(serviceList) > 0 {
+		for _, node := range serviceList {
+			gameSess := model.GetServiceNode(node)
+			if gameSess != nil {
+				gameSess.Send(sendMsg)
+			}
+		}
+	}
+}

+ 61 - 0
RO_Server_Trunk-branch_0.1.39/roserver/battleboss/msg/battle_msg.go

@@ -0,0 +1,61 @@
+package msg
+
+import (
+	"rocommon"
+	"rocommon/util"
+	"roserver/baseserver/model"
+	model2 "roserver/battleboss/model"
+	"roserver/serverproto"
+)
+
+func init() {
+	//玩家下线处理/主动离开boss场景
+	serverproto.Handle_BATTLEBOSS_SSPlayerOfflineNtf = model.HandleBackendMessage(func(ev rocommon.ProcEvent, cliId model.ClientID) {
+		msg := ev.Msg().(*serverproto.SSPlayerOfflineNtf)
+		util.InfoF("receive SSPlayerOfflineNtf msg:%v", msg)
+
+		model2.AoiLineMag.PlayerOffline(msg.Uid)
+	})
+
+	//挑战召唤物
+	serverproto.Handle_BATTLEBOSS_CSPlayerChallengeSummonReq = model.HandleBackendMessage(func(ev rocommon.ProcEvent, cliId model.ClientID) {
+		msg := ev.Msg().(*serverproto.CSPlayerChallengeSummonReq)
+		util.InfoF("receive CSPlayerChallengeSummonReq msg:%v", msg)
+
+		ret := model2.AoiLineMag.PlayerChallengeSummonBoss(msg.Uid, msg.ChallengeBossUid, cliId, msg.FightInfo)
+		ackMsg := &serverproto.SCPlayerChallengeSummonAck{
+			Error:    int32(ret),
+			BossInfo: model2.AoiLineMag.GetWorldBossInfo(msg.ChallengeBossUid),
+		}
+
+		//删除boss使用
+		if ret == serverproto.ErrorCode_ERROR_AOI_BOSS_NOT_FOUND {
+			ackMsg.BossInfo = &serverproto.WorldBossContentInfo{
+				BossId: int32(msg.ChallengeBossUid),
+			}
+			//更新boss信息
+		} else if ret == serverproto.ErrorCode_ERROR_AOI_BOSS_CHALLENGE_NUM_LIMIT {
+			ackMsg.BossInfo = model2.AoiLineMag.GetWorldBossInfo(msg.ChallengeBossUid)
+		}
+
+		model.ServiceReplay(ev, ackMsg)
+	})
+
+	//血量上报
+	serverproto.Handle_BATTLEBOSS_CSPlayerChallengeHpReq = model.HandleBackendMessage(func(ev rocommon.ProcEvent, cliId model.ClientID) {
+		msg := ev.Msg().(*serverproto.CSPlayerChallengeHpReq)
+		util.InfoF("receive CSPlayerChallengeHpReq msg:%v %v", msg, cliId.SessID)
+
+		model2.AoiLineMag.DoSummonHp(cliId.SessID, msg.ActionUid, msg.DamageHp)
+	})
+
+	//获取WorldBoss列表
+	serverproto.Handle_BATTLEBOSS_CSPlayerWorldBossListReq = model.HandleBackendMessage(func(ev rocommon.ProcEvent, cliId model.ClientID) {
+		msg := ev.Msg().(*serverproto.CSPlayerWorldBossListReq)
+		util.DebugF("receive CSPlayerWorldBossListReq msg:%v %v", msg, cliId.SessID)
+
+		ackMsg := model2.AoiLineMag.GetWorldBossList()
+
+		model.ServiceReplay(ev, ackMsg)
+	})
+}

+ 62 - 0
RO_Server_Trunk-branch_0.1.39/roserver/battlerecord/main.go

@@ -0,0 +1,62 @@
+package main
+
+import (
+	"io/ioutil"
+	"os"
+	"rocommon"
+	"rocommon/service"
+	_ "rocommon/socket"
+	_ "rocommon/socket/tcp"
+	"roserver/baseserver"
+	"roserver/baseserver/model"
+	_ "roserver/battlerecord/msg"
+	"runtime"
+	"strconv"
+	"syscall"
+)
+
+func main() {
+	//记录battleboss pid用来做关闭操作
+	sysType := runtime.GOOS
+	if sysType != "windows" {
+		if pid := syscall.Getpid(); pid != 1 {
+			fileName := "battlerecord_server.pid" + strconv.Itoa(pid)
+			ioutil.WriteFile(fileName, []byte(strconv.Itoa(pid)), 0777)
+			defer os.Remove(fileName)
+		}
+	}
+	//CPU
+	//prof := profile.Start(profile.CPUProfile, profile.ProfilePath("./pprof/rank.pprof"), profile.NoShutdownHook)
+	//prof := profile.Start(profile.MemProfile, profile.ProfilePath("./pprof/rankmem.pprof"), profile.NoShutdownHook)
+
+	baseserver.Init(model.SERVICE_NODE_TYPE_BATTLERECORD_STR, nil, nil)
+	//先建立服务器对应的连接,在监听客户端
+	sConfig := service.GetServiceConfig()
+	//配置文件初始化,如果后续做热更新的话,需要加锁,或者用sync.map
+	//创建监听器
+	var acceNode rocommon.ServerNode = nil
+	if sConfig.Node.Addr != "" {
+		acceNode = baseserver.CreateAcceptor(baseserver.ServiceParam{
+			ServiceType: "tcpAcceptor",
+			ServiceName: model.SERVICE_NODE_TYPE_BATTLERECORD_STR,
+			ProcName:    "common.backend",
+			LisAddr:     sConfig.Node.Addr,
+		}, sConfig)
+	}
+
+	for _, concern := range sConfig.Node.Concern {
+		//建立需要链接的服务器,可以通过服务器发现etcd来处理(包含在了CreateConnector中)
+		baseserver.CreateConnector(baseserver.ServiceParam{
+			DiscoveryServiceName: concern,
+			DiscoveryServiceZone: sConfig.Node.Zone,
+			ServiceType:          "tcpConnector",
+			ServiceName:          model.SERVICE_NODE_TYPE_BATTLERECORD_STR,
+			ProcName:             "common.backend",
+		})
+	}
+
+	baseserver.Wait()
+	//CPU
+	//prof.Stop()
+	baseserver.Exit(acceNode)
+}

+ 22 - 0
RO_Server_Trunk-branch_0.1.39/roserver/battlerecord/model/config.go

@@ -0,0 +1,22 @@
+package model
+
+import (
+	"rocommon/service"
+	"rocommon/util"
+	"roserver/baseserver/model"
+	"runtime/debug"
+)
+
+func ConfigInit() {
+	defer func() {
+		if err := recover(); err != nil {
+			util.InfoF("Stack---::%v\n%s\n", err, string(debug.Stack()))
+			panic(nil)
+		}
+	}()
+
+	sConfig := service.GetServiceConfig()
+	model.BaseConfigInit(sConfig)
+
+	util.InfoF("config load success!!!")
+}

+ 97 - 0
RO_Server_Trunk-branch_0.1.39/roserver/battlerecord/model/record_helper.go

@@ -0,0 +1,97 @@
+package model
+
+import (
+	"container/list"
+	"encoding/base64"
+	"rocommon/service"
+	"rocommon/util"
+	"roserver/baseserver/model"
+	"roserver/serverproto"
+	"strconv"
+)
+
+type RecordCache struct {
+	record    uint64
+	recordStr string
+}
+
+var BattleRecordCacheList = map[uint64]*list.Element{}
+var BattleRecordCacheFifoList = list.New()
+
+func BattleRecordSave(recordId uint64, battleRecord string) bool {
+	if recordId <= 0 {
+		return false
+	}
+
+	memberStr := strconv.FormatUint(recordId, 10)
+	ret, err := service.GetRedis().SIsMember(model.BattleRecordDetailCheckPrefix, memberStr).Result()
+	if err != nil || memberStr == "" {
+		util.DebugF("BattleRecordSave is member failed recordId=%v err=%v", recordId, err)
+		return false
+	}
+	//不存在该记录无法进行保存
+	if !ret {
+		util.DebugF("BattleRecordSave not find recordId=%v", recordId)
+		return false
+	}
+	service.GetRedis().SRem(model.BattleRecordDetailCheckPrefix, memberStr)
+
+	keyStr := model.BattleRecordDetailPrefix + memberStr
+	msgStr := base64.StdEncoding.EncodeToString([]byte(battleRecord))
+	_, err = service.GetRedis().Set(keyStr, msgStr, 0).Result()
+	if err != nil {
+		util.DebugF("BattleRecordSave recordId=%v save err=%v key=%v", recordId, err, keyStr)
+		return false
+	}
+
+	return true
+}
+
+func BattleRecordGet(recordId uint64, ackMsg *serverproto.SCPlayerBattleRecordDetailAck) bool {
+	if elem, ok := BattleRecordCacheList[recordId]; ok {
+		recordCache := elem.Value.(*RecordCache)
+
+		ackMsg.BattleRecordUid = recordId
+		ackMsg.BattleRecord = recordCache.recordStr
+
+		//重新调整位置
+		BattleRecordCacheFifoList.Remove(elem)
+		delete(BattleRecordCacheList, recordId)
+		newElem := BattleRecordCacheFifoList.PushBack(recordCache)
+		BattleRecordCacheList[recordId] = newElem
+
+		return true
+	}
+
+	memberStr := strconv.FormatUint(recordId, 10)
+	keyStr := model.BattleRecordDetailPrefix + memberStr
+
+	ret, err := service.GetRedis().Get(keyStr).Result()
+	if err != nil {
+		util.DebugF("BattleRecordGet recordId=%v err=%v key=%v", recordId, err, keyStr)
+		return false
+	}
+	msgData, err := base64.StdEncoding.DecodeString(ret)
+	if err != nil {
+		util.DebugF("BattleRecordGet recordId=%v  DecodeStringErr=%v key=%v", recordId, err, keyStr)
+		return false
+	}
+
+	ackMsg.BattleRecordUid = recordId
+	ackMsg.BattleRecord = string(msgData)
+
+	//最近获取的1000个记录放到cache中
+	if BattleRecordCacheFifoList.Len() > 1000 {
+		elem := BattleRecordCacheFifoList.Front()
+		delete(BattleRecordCacheList, elem.Value.(*RecordCache).record)
+		BattleRecordCacheFifoList.Remove(elem)
+	}
+	recordCache := &RecordCache{
+		record:    recordId,
+		recordStr: ackMsg.BattleRecord,
+	}
+	elem := BattleRecordCacheFifoList.PushBack(recordCache)
+	BattleRecordCacheList[recordId] = elem
+
+	return true
+}

+ 38 - 0
RO_Server_Trunk-branch_0.1.39/roserver/battlerecord/msg/record_msg.go

@@ -0,0 +1,38 @@
+package msg
+
+import (
+	"rocommon"
+	"rocommon/util"
+	"roserver/baseserver/model"
+	model2 "roserver/battlerecord/model"
+	"roserver/serverproto"
+)
+
+func init() {
+	//保存战报相信信息
+	serverproto.Handle_BATTLERECORD_CSPlayerBattleRecordDetailSaveReq = model.HandleBackendMessage(func(ev rocommon.ProcEvent, cliId model.ClientID) {
+		msg := ev.Msg().(*serverproto.CSPlayerBattleRecordDetailSaveReq)
+		util.DebugF("openid=%v receive CSPlayerBattleRecordDetailSaveReq msglen=%v sid=%v ", msg.OpenId, len(msg.BattleRecord), cliId.SessID)
+
+		ackMsg := &serverproto.SCPlayerBattleRecordDetailSaveAck{}
+		ret := model2.BattleRecordSave(msg.BattleRecordUid, msg.BattleRecord)
+		if !ret {
+			ackMsg.Error = int32(serverproto.ErrorCode_ERROR_BATTLE_RECORD_SAVE)
+		}
+		model.ServiceReplay(ev, ackMsg)
+	})
+
+	//获取战报相信信息
+	serverproto.Handle_BATTLERECORD_CSPlayerBattleRecordDetailReq = model.HandleBackendMessage(func(ev rocommon.ProcEvent, cliId model.ClientID) {
+		msg := ev.Msg().(*serverproto.CSPlayerBattleRecordDetailReq)
+		util.DebugF("openi=%v receive CSPlayerBattleRecordDetailReq msg=%v sid=%v", msg.OpenId, msg, cliId.SessID)
+
+		ackMsg := &serverproto.SCPlayerBattleRecordDetailAck{}
+		ret := model2.BattleRecordGet(msg.BattleRecordUid, ackMsg)
+		if !ret {
+			ackMsg.Error = int32(serverproto.ErrorCode_ERROR_BATTLE_RECORD_INVALID)
+		}
+
+		model.ServiceReplay(ev, ackMsg)
+	})
+}

Nem az összes módosított fájl került megjelenítésre, mert túl sok fájl változott