461 lines
13 KiB
Go
461 lines
13 KiB
Go
package modules
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"go_dreamfactory/comm"
|
|
"go_dreamfactory/lego/base"
|
|
"go_dreamfactory/lego/core"
|
|
"go_dreamfactory/lego/core/cbase"
|
|
"time"
|
|
|
|
"go_dreamfactory/lego/sys/log"
|
|
"go_dreamfactory/pb"
|
|
cfg "go_dreamfactory/sys/configure/structs"
|
|
"go_dreamfactory/sys/db"
|
|
|
|
"google.golang.org/protobuf/proto"
|
|
"google.golang.org/protobuf/types/known/anypb"
|
|
)
|
|
|
|
/*
|
|
基础业务模块实现 封装一些通用的接口提供给业务模块使用
|
|
*/
|
|
type ModuleBase struct {
|
|
cbase.ModuleBase
|
|
module core.IModule
|
|
service base.IRPCXService
|
|
options IOptions
|
|
scomp comm.ISC_GateRouteComp //网关服务组件
|
|
//常用的一些通用模块 在底层注册好
|
|
ModuleSys comm.ISys //系统
|
|
ModuleUser comm.IUser //用户模块
|
|
ModuleItems comm.IItems //道具背包模块
|
|
ModuleHero comm.IHero //英雄模块
|
|
ModuleEquipment comm.IEquipment //装备模块
|
|
ModuleTask comm.ITask //任务
|
|
ModuleFriend comm.IFriend //好友
|
|
ModuleRtask comm.IRtask //随机任务
|
|
}
|
|
|
|
//重构模块配置对象
|
|
func (this *ModuleBase) NewOptions() (options core.IModuleOptions) {
|
|
return new(Options)
|
|
}
|
|
|
|
//模块初始化接口
|
|
func (this *ModuleBase) Init(service core.IService, module core.IModule, options core.IModuleOptions) (err error) {
|
|
err = this.ModuleBase.Init(service, module, options)
|
|
this.service = service.(base.IRPCXService)
|
|
this.module = module
|
|
this.options = options.(IOptions)
|
|
this.options.GetLog().SetName("module." + string(module.GetType()))
|
|
return
|
|
}
|
|
|
|
//模块启动接口
|
|
func (this *ModuleBase) Start() (err error) {
|
|
err = this.ModuleBase.Start()
|
|
var comp core.IServiceComp
|
|
//注册远程路由
|
|
if comp, err = this.service.GetComp(comm.SC_ServiceGateRouteComp); err != nil {
|
|
return
|
|
}
|
|
this.scomp = comp.(comm.ISC_GateRouteComp)
|
|
var module core.IModule
|
|
if module, err = this.service.GetModule(comm.ModuleUser); err != nil {
|
|
return
|
|
}
|
|
|
|
this.ModuleUser = module.(comm.IUser)
|
|
if module, err = this.service.GetModule(comm.ModuleItems); err != nil {
|
|
return
|
|
}
|
|
this.ModuleItems = module.(comm.IItems)
|
|
if module, err = this.service.GetModule(comm.ModuleHero); err != nil {
|
|
return
|
|
}
|
|
this.ModuleHero = module.(comm.IHero)
|
|
if module, err = this.service.GetModule(comm.ModuleEquipment); err != nil {
|
|
return
|
|
}
|
|
this.ModuleEquipment = module.(comm.IEquipment)
|
|
|
|
if module, err = this.service.GetModule(comm.ModuleTask); err != nil {
|
|
return
|
|
}
|
|
this.ModuleTask = module.(comm.ITask)
|
|
|
|
if module, err = this.service.GetModule(comm.ModuleFriend); err != nil {
|
|
return
|
|
}
|
|
this.ModuleFriend = module.(comm.IFriend)
|
|
|
|
if module, err = this.service.GetModule(comm.ModuleRtask); err != nil {
|
|
return
|
|
}
|
|
this.ModuleRtask = module.(comm.IRtask)
|
|
|
|
if module, err = this.service.GetModule(comm.ModuleSys); err != nil {
|
|
return
|
|
}
|
|
|
|
this.ModuleSys = module.(comm.ISys)
|
|
return
|
|
}
|
|
|
|
//判断当前环境是本服还还是跨服
|
|
func (this *ModuleBase) IsCross() bool {
|
|
return db.IsCross()
|
|
}
|
|
|
|
//获取跨服标签
|
|
func (this *ModuleBase) GetCrossTag() string {
|
|
return db.CrossTag()
|
|
}
|
|
|
|
func (this *ModuleBase) GetUserSession(uid string) (session comm.IUserSession, ok bool) {
|
|
var udata *pb.CacheUser
|
|
if udata = this.ModuleUser.GetUserSession(uid); udata == nil {
|
|
ok = false
|
|
return
|
|
}
|
|
session = this.scomp.GetUserSession(udata)
|
|
ok = true
|
|
return
|
|
}
|
|
|
|
func (this *ModuleBase) PutUserSession(session comm.IUserSession) {
|
|
session.Reset()
|
|
this.scomp.PutUserSession(session)
|
|
return
|
|
}
|
|
|
|
//向指定用户发送消息
|
|
func (this *ModuleBase) SendMsgToUser(mainType, subType string, msg proto.Message, uid string) (err error) {
|
|
user := this.ModuleUser.GetUserSession(uid)
|
|
if user == nil {
|
|
err = fmt.Errorf("user:%v on found", uid)
|
|
return
|
|
}
|
|
session := this.scomp.GetUserSession(user)
|
|
session.SendMsg(mainType, subType, msg)
|
|
err = session.Push()
|
|
this.scomp.PutUserSession(session)
|
|
return
|
|
}
|
|
|
|
//向多个用户发送消息
|
|
func (this *ModuleBase) SendMsgToUsers(mainType, subType string, msg proto.Message, uids ...string) (err error) {
|
|
var (
|
|
users map[string]*pb.CacheUser = make(map[string]*pb.CacheUser)
|
|
gateways map[string]map[string][]string = make(map[string]map[string][]string)
|
|
cluster map[string][]string = make(map[string][]string)
|
|
gateway []string
|
|
ok bool
|
|
)
|
|
for _, v := range uids {
|
|
if user := this.ModuleUser.GetUserSession(v); user != nil {
|
|
if user == nil {
|
|
err = fmt.Errorf("user:%v on found", v)
|
|
continue
|
|
}
|
|
users[v] = user
|
|
}
|
|
}
|
|
for _, v := range users {
|
|
if cluster, ok = gateways[v.ServiceTag]; !ok {
|
|
cluster = make(map[string][]string)
|
|
gateways[v.ServiceTag] = cluster
|
|
}
|
|
if gateway, ok = cluster[v.GatewayServiceId]; !ok {
|
|
gateway = make([]string, 0)
|
|
cluster[v.GatewayServiceId] = gateway
|
|
}
|
|
cluster[v.GatewayServiceId] = append(cluster[v.GatewayServiceId], v.SessionId)
|
|
}
|
|
data, _ := anypb.New(msg)
|
|
for k, v := range gateways {
|
|
for k1, v1 := range v {
|
|
if _, err = this.service.AcrossClusterRpcGo(context.Background(), k, fmt.Sprintf("%s/%s", comm.Service_Gateway, k1), string(comm.Rpc_GatewaySendBatchMsg), &pb.BatchMessageReq{
|
|
UserSessionIds: v1,
|
|
MainType: mainType,
|
|
SubType: subType,
|
|
Data: data,
|
|
}, nil); err != nil {
|
|
log.Errorf("SendMsgToUsers:%s.%s->%s.%s err:%v", k1, k, mainType, subType, err)
|
|
}
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
//向多个用户发送消息
|
|
func (this *ModuleBase) SendMsgToCUsers(mainType, subType string, msg proto.Message, users ...*pb.CacheUser) (err error) {
|
|
var (
|
|
gateways map[string]map[string][]string = make(map[string]map[string][]string)
|
|
cluster map[string][]string = make(map[string][]string)
|
|
gateway []string
|
|
ok bool
|
|
)
|
|
for _, v := range users {
|
|
if cluster, ok = gateways[v.ServiceTag]; !ok {
|
|
cluster = make(map[string][]string)
|
|
gateways[v.ServiceTag] = cluster
|
|
}
|
|
if gateway, ok = cluster[v.GatewayServiceId]; !ok {
|
|
gateway = make([]string, 0)
|
|
cluster[v.GatewayServiceId] = gateway
|
|
}
|
|
cluster[v.GatewayServiceId] = append(cluster[v.GatewayServiceId], v.SessionId)
|
|
}
|
|
data, _ := anypb.New(msg)
|
|
for k, v := range gateways {
|
|
for k1, v1 := range v {
|
|
if _, err = this.service.AcrossClusterRpcGo(context.Background(), k, fmt.Sprintf("%s/%s", comm.Service_Gateway, k1), string(comm.Rpc_GatewaySendBatchMsg), &pb.BatchMessageReq{
|
|
UserSessionIds: v1,
|
|
MainType: mainType,
|
|
SubType: subType,
|
|
Data: data,
|
|
}, nil); err != nil {
|
|
log.Errorf("SendMsgToUsers:%s.%s->%s.%s err:%v", k1, k, mainType, subType, err)
|
|
}
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
// 只校验资源 参数 atn格式
|
|
func (this *ModuleBase) CheckRes(session comm.IUserSession, res []*cfg.Gameatn) (code pb.ErrorCode) {
|
|
//校验消费资源是否充足
|
|
for _, v := range res {
|
|
if v.A == comm.AttrType { //用户属性资源
|
|
if amount := this.ModuleUser.QueryAttributeValue(session.GetUserId(), v.T); amount < int64(v.N) {
|
|
code = pb.ErrorCode_ResNoEnough
|
|
this.Errorf("道具不足:A:%s,T:%s,N:%d", v.A, v.T, v.N)
|
|
return
|
|
}
|
|
} else if v.A == comm.ItemType { //道具资源
|
|
// if resID, err = strconv.Atoi(v.T); err != nil {
|
|
// code = pb.ErrorCode_ConfigurationException
|
|
// return
|
|
// }
|
|
if amount := this.ModuleItems.QueryItemAmount(session.GetUserId(), v.T); amount < uint32(v.N) {
|
|
code = pb.ErrorCode_ResNoEnough
|
|
this.Errorf("道具不足:A:%s,T:%s,N:%d", v.A, v.T, v.N)
|
|
return
|
|
}
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
//消耗资源
|
|
func (this *ModuleBase) ConsumeRes(session comm.IUserSession, res []*cfg.Gameatn, bPush bool) (code pb.ErrorCode) {
|
|
var (
|
|
items map[string]int32 // 道具背包 批量处理
|
|
attrs map[string]int32 // 属性
|
|
)
|
|
items = make(map[string]int32, 0)
|
|
attrs = make(map[string]int32, 0)
|
|
|
|
for _, v := range res {
|
|
switch v.A {
|
|
case comm.AttrType:
|
|
attrs[v.T] -= v.N
|
|
case comm.ItemType:
|
|
items[v.T] -= v.N
|
|
default:
|
|
this.Errorf("not found res type") // 找不到资源类型
|
|
}
|
|
}
|
|
|
|
// 校验数量
|
|
for k, v := range attrs {
|
|
if this.ModuleUser.QueryAttributeValue(session.GetUserId(), k) < -int64(v) { // -v 负负得正
|
|
code = pb.ErrorCode_ResNoEnough
|
|
this.Errorf("资源不足: A: attr, T: %s, N: %d", k, v)
|
|
return
|
|
}
|
|
}
|
|
for k, v := range items {
|
|
if int32(this.ModuleItems.QueryItemAmount(session.GetUserId(), k)) < -v {
|
|
code = pb.ErrorCode_ResNoEnough
|
|
this.Errorf("道具不足: A: item, T:%s, N:%d", k, v)
|
|
return
|
|
}
|
|
}
|
|
// 真正消耗
|
|
if len(attrs) > 0 {
|
|
code = this.ModuleUser.AddAttributeValues(session, attrs, bPush)
|
|
if code != pb.ErrorCode_Success {
|
|
return
|
|
}
|
|
this.Debugf("消耗玩家资源: %v", attrs)
|
|
}
|
|
if len(items) > 0 {
|
|
code = this.ModuleItems.AddItems(session, items, bPush)
|
|
if code != pb.ErrorCode_Success {
|
|
return
|
|
}
|
|
this.Debugf("消耗道具资源: %v", items)
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
//发放资源
|
|
func (this *ModuleBase) DispenseRes(session comm.IUserSession, res []*cfg.Gameatn, bPush bool) (code pb.ErrorCode) {
|
|
var (
|
|
items map[string]int32 // 道具背包 批量处理
|
|
heros map[string]int32 // 英雄
|
|
attrs map[string]int32 // 属性
|
|
equips map[string]uint32 // 装备
|
|
)
|
|
items = make(map[string]int32, 0)
|
|
heros = make(map[string]int32, 0)
|
|
attrs = make(map[string]int32, 0)
|
|
equips = make(map[string]uint32, 0)
|
|
|
|
for _, v := range res {
|
|
switch v.A {
|
|
case comm.AttrType:
|
|
attrs[v.T] += v.N
|
|
case comm.ItemType:
|
|
items[v.T] += v.N
|
|
case comm.HeroType:
|
|
heros[v.T] += v.N
|
|
case comm.EquipmentType:
|
|
if v.N > 0 { // 不允许减少装备
|
|
equips[v.T] += uint32(v.N)
|
|
}
|
|
default:
|
|
this.Errorf("not found res type") // 找不到资源类型
|
|
}
|
|
}
|
|
|
|
if len(attrs) > 0 { //用户属性资源
|
|
code = this.ModuleUser.AddAttributeValues(session, attrs, bPush)
|
|
this.Debugf("发放用户资源: %v [%v]", attrs, code)
|
|
}
|
|
if len(items) > 0 { //道具资源
|
|
code = this.ModuleItems.AddItems(session, items, bPush)
|
|
this.Debugf("发放道具资源: %v [%v]", items, code)
|
|
}
|
|
if len(heros) > 0 { //卡片资源
|
|
code = this.ModuleHero.CreateRepeatHeros(session, heros, bPush)
|
|
this.Debugf("发放英雄资源: %v [%v]", heros, code)
|
|
}
|
|
if len(equips) > 0 {
|
|
code = this.ModuleEquipment.AddNewEquipments(session, equips, bPush)
|
|
this.Debugf("发放装备资源: %v [%v]", equips, code)
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
//跨服对象获取数据操作对象
|
|
func (this *ModuleBase) GetDBNodule(session comm.IUserSession, tableName string, expired time.Duration) (model *db.DBModel, err error) {
|
|
var conn *db.DBConn
|
|
if session.GetServiecTag() == this.service.GetTag() {
|
|
if conn, err = db.Local(); err != nil {
|
|
return
|
|
}
|
|
} else {
|
|
if conn, err = db.ServerDBConn(session.GetServiecTag()); err != nil {
|
|
return
|
|
}
|
|
}
|
|
model = db.NewDBModel(tableName, expired, conn)
|
|
return
|
|
}
|
|
|
|
//跨服对象获取数据操作对象
|
|
func (this *ModuleBase) GetDBNoduleByUid(uid, tableName string, expired time.Duration) (model *db.DBModel, err error) {
|
|
var (
|
|
stag string
|
|
conn *db.DBConn
|
|
)
|
|
if stag, err = comm.UidToSTag(uid); err != nil {
|
|
return
|
|
}
|
|
if stag == this.service.GetTag() {
|
|
if conn, err = db.Local(); err != nil {
|
|
return
|
|
}
|
|
} else {
|
|
if conn, err = db.ServerDBConn(stag); err != nil {
|
|
return
|
|
}
|
|
}
|
|
model = db.NewDBModel(tableName, expired, conn)
|
|
return
|
|
}
|
|
|
|
//日志接口
|
|
func (this *ModuleBase) Debug(msg string, args ...log.Field) {
|
|
this.options.GetLog().Debug(msg, args...)
|
|
}
|
|
func (this *ModuleBase) Info(msg string, args ...log.Field) {
|
|
this.options.GetLog().Info(msg, args...)
|
|
}
|
|
func (this *ModuleBase) Print(msg string, args ...log.Field) {
|
|
this.options.GetLog().Print(msg, args...)
|
|
}
|
|
func (this *ModuleBase) Warn(msg string, args ...log.Field) {
|
|
this.options.GetLog().Warn(msg, args...)
|
|
}
|
|
func (this *ModuleBase) Error(msg string, args ...log.Field) {
|
|
this.options.GetLog().Error(msg, args...)
|
|
}
|
|
func (this *ModuleBase) Panic(msg string, args ...log.Field) {
|
|
this.options.GetLog().Panic(msg, args...)
|
|
}
|
|
func (this *ModuleBase) Fatal(msg string, args ...log.Field) {
|
|
this.options.GetLog().Fatal(msg, args...)
|
|
}
|
|
|
|
func (this *ModuleBase) Debugf(format string, args ...interface{}) {
|
|
this.options.GetLog().Debugf(format, args...)
|
|
}
|
|
func (this *ModuleBase) Infof(format string, args ...interface{}) {
|
|
this.options.GetLog().Infof(format, args...)
|
|
}
|
|
func (this *ModuleBase) Printf(format string, args ...interface{}) {
|
|
this.options.GetLog().Printf(format, args...)
|
|
}
|
|
func (this *ModuleBase) Warnf(format string, args ...interface{}) {
|
|
this.options.GetLog().Warnf(format, args...)
|
|
}
|
|
func (this *ModuleBase) Errorf(format string, args ...interface{}) {
|
|
this.options.GetLog().Errorf(format, args...)
|
|
}
|
|
func (this *ModuleBase) Fatalf(format string, args ...interface{}) {
|
|
this.options.GetLog().Fatalf(format, args...)
|
|
}
|
|
func (this *ModuleBase) Panicf(format string, args ...interface{}) {
|
|
this.options.GetLog().Panicf(format, args...)
|
|
}
|
|
|
|
func (this *ModuleBase) Debugln(args ...interface{}) {
|
|
this.options.GetLog().Debugln(args...)
|
|
}
|
|
func (this *ModuleBase) Infoln(args ...interface{}) {
|
|
this.options.GetLog().Infoln(args...)
|
|
}
|
|
func (this *ModuleBase) Println(args ...interface{}) {
|
|
this.options.GetLog().Println(args...)
|
|
}
|
|
func (this *ModuleBase) Warnln(args ...interface{}) {
|
|
this.options.GetLog().Warnln(args...)
|
|
}
|
|
func (this *ModuleBase) Errorln(args ...interface{}) {
|
|
this.options.GetLog().Errorln(args...)
|
|
}
|
|
func (this *ModuleBase) Fatalln(args ...interface{}) {
|
|
this.options.GetLog().Fatalln(args...)
|
|
}
|
|
func (this *ModuleBase) Panicln(args ...interface{}) {
|
|
this.options.GetLog().Panicln(args...)
|
|
}
|