pet_home_server/src/server/game/Player.go
2024-11-25 15:01:25 +08:00

683 lines
18 KiB
Go

package game
import (
// "server/GoUtil"
// "server/MergeConst"
"errors"
"fmt"
"server/GoUtil"
"server/MergeConst"
itemCfg "server/conf/item"
"server/game/mod/item"
"server/game/mod/limitedTimeEvent"
MsgMod "server/game/mod/msg"
"server/game/mod/quest"
"server/msg"
"sync"
"time"
"server/pkg/github.com/name5566/leaf/gate"
"server/pkg/github.com/name5566/leaf/log"
"server/pkg/github.com/name5566/leaf/timer"
"github.com/robfig/cron/v3"
"google.golang.org/protobuf/proto"
)
// import "reflect"
//"fmt"
type Player struct {
playerdata map[string]PlayerDataModule
playerdataIF map[string]interface{}
PlayMod PlayerMod
M_DwUin int32
agent gate.Agent
PAMgr *PlayerActiveMgr
lock sync.Mutex
stopSignal chan bool
Msg map[string]PlayerMsg
Trigger []*quest.Trigger
MDispatr *timer.Dispatcher
McronSave *cron.Cron
McronSaveID cron.EntryID
msgChan chan *MsgMod.Msg
args map[string]interface{}
timerList map[string]*timer.Timer
stop bool
}
type PlayerBackUp struct {
PlayerBaseData *PlayerBaseData
PlayMod []byte
}
type PlayerMsg struct {
F string
B []byte
}
func (p *Player) Stop() {
select {
case <-p.stopSignal:
// 通道已经关闭
return
default:
close(p.stopSignal)
close(p.msgChan)
}
G_GameLogicPtr.AddLog(&Log{
Uid: p.M_DwUin,
Type: LoginOut_log,
})
p.McronSave.Stop()
p.stop = true
}
func (p *Player) CallEvent(Duration time.Duration, F func(), Label string) {
if v, ok := p.timerList[Label]; ok {
v.Stop()
}
t := p.MDispatr.AfterFunc(Duration, F)
p.timerList[Label] = t
}
// 异步请求
func (p *Player) Send(m *MsgMod.Msg) {
p.msgChan <- m
}
func (p *Player) Call(m MsgMod.Msg) {
HandleMsg(p, &m)
}
func (p *Player) SendClientRes() {
for _, v := range p.Msg {
G_GameLogicPtr.PackResInfo(p.GetAgent(), v.F, v.B)
}
p.Msg = make(map[string]PlayerMsg)
}
func (p *Player) PushClientRes(m proto.Message) {
key := GetStructName(m)
buff, _ := proto.Marshal(m)
p.Msg[key] = PlayerMsg{
F: key,
B: buff,
}
}
func (p *Player) PushAndSendClienRes(m proto.Message) {
key := GetStructName(m)
buff, _ := proto.Marshal(m)
G_GameLogicPtr.PackResInfo(p.GetAgent(), key, buff)
}
func (p *Player) SendErrClienRes(m proto.Message) {
key := GetStructName(m)
buff, _ := proto.Marshal(m)
G_GameLogicPtr.PackResInfo(p.GetAgent(), key, buff)
}
func (p *Player) QuestTrigger(tr *quest.Trigger) {
p.Trigger = append(p.Trigger, tr)
}
func (p *Player) QuestTriggerList(tr []*quest.Trigger) {
p.Trigger = append(p.Trigger, tr...)
}
func (p *Player) ProcessTrigger() {
IsDailyBack := false
DailyTaskMod := p.PlayMod.getDailyTaskMod()
for _, tr := range p.Trigger {
if DailyTaskMod.Trigger(tr) {
IsDailyBack = true
}
}
if IsDailyBack {
p.PushClientRes(DailyTaskMod.BackData())
}
p.Trigger = make([]*quest.Trigger, 0)
}
// 接口请求之前备份数据
func (p *Player) BackUp() *PlayerBackUp {
BackUp := PlayerBackUp{}
p.PlayMod.BackUp(&BackUp)
BackUp.PlayerBaseData = p.GetPlayerBaseMod().BackUp()
return &BackUp
}
// 接口发生错误时 还原数据
func (p *Player) Recover(backUp *PlayerBackUp) {
backUp.PlayerBaseData.PlayerData = NewPlayerData(PLAYER_BASE_DATA, p)
p.playerdata[PLAYER_BASE_DATA] = backUp.PlayerBaseData
p.playerdataIF[PLAYER_BASE_DATA] = backUp.PlayerBaseData
p.PlayMod.Recover(backUp)
p.Msg = make(map[string]PlayerMsg)
}
func (p *Player) InitPlayer(UserName string) error {
p.lock.Lock()
defer p.lock.Unlock()
p.msgChan = make(chan *MsgMod.Msg, 100)
p.Msg = make(map[string]PlayerMsg)
p.args = make(map[string]interface{})
p.timerList = make(map[string]*timer.Timer)
p.MDispatr = timer.NewDispatcher(10)
p.stopSignal = make(chan bool)
p.playerdata = make(map[string]PlayerDataModule)
p.playerdataIF = make(map[string]interface{})
Base := &PlayerBaseData{PlayerData: NewPlayerData(PLAYER_BASE_DATA, p)}
p.playerdata[PLAYER_BASE_DATA] = Base
p.playerdataIF[PLAYER_BASE_DATA] = Base
// 玩家基础数据
ok := Base.LoadDataFromDB(UserName)
if !ok {
log.Debug("load PlayerBaseData failed:", UserName)
return errors.New("load PlayerBaseData failed")
}
p.playerdata[PLAYER_BASE_DATA] = Base
p.playerdataIF[PLAYER_BASE_DATA] = Base
p.M_DwUin = Base.Data.DwUin
// 发射器解锁数据
unlock := &PlayerEmitUnlockData{PlayerData: NewPlayerData("PlayerEmitUnlockData", p)}
ok = unlock.LoadDataFromDB(Base.Data.DwUin)
if !ok {
log.Debug("load PlayerEmitUnlockData failed:", UserName)
return errors.New("load PlayerEmitUnlockData failed")
}
p.playerdata["PlayerEmitUnlockData"] = unlock
p.playerdataIF["PlayerEmitUnlockData"] = unlock
// 发射器数据
Detail := &PlayerEmitDetailData{PlayerData: NewPlayerData("PlayerEmitDetailData", p)}
ok = Detail.LoadDataFromDB(Base.Data.DwUin)
if !ok {
log.Debug("load PlayerEmitDetailData failed! username: %s", UserName)
return errors.New("load PlayerEmitDetailData failed")
}
p.playerdata["PlayerEmitDetailData"] = Detail
p.playerdataIF["PlayerEmitDetailData"] = Detail
G_getGameLogic().Mlogger.Debug("load PlayerEmitDetailData:", Base.Data.DwUin)
// 棋盘数据
Chess := &PlayerChessData{PlayerData: NewPlayerData("PlayerChessData", p)}
ok = Chess.LoadDataFromDB(Base.Data.DwUin)
if !ok {
log.Debug("load PlayerChessData failed:", UserName)
return errors.New("load PlayerChessData failed")
}
p.playerdata["PlayerChessData"] = Chess
p.playerdataIF["PlayerChessData"] = Chess
// 玩家解锁宝箱数据
Chest := &PlayerUnlockingChestData{PlayerData: NewPlayerData("PlayerUnlockingChestData", p)}
ok = Chest.LoadDataFromDB(Base.Data.DwUin)
if !ok {
log.Debug("load PlayerUnlockingChestData failed:", UserName)
return errors.New("load PlayerUnlockingChestData failed")
}
p.playerdata["PlayerUnlockingChestData"] = Chest
p.playerdataIF["PlayerUnlockingChestData"] = Chest
// 玩家解锁宝箱数据
Single := &PlayerSingleData{PlayerData: NewPlayerData("PlayerSingleData", p)}
ok = Single.LoadDataFromDB(Base.Data.DwUin)
if !ok {
log.Debug("load PlayerSingleData failed:", UserName)
return errors.New("load PlayerSingleData failed")
}
p.playerdata["PlayerSingleData"] = Single
p.playerdataIF["PlayerSingleData"] = Single
// 玩家订单数据
Charge := &PlayerChargeData{PlayerData: NewPlayerData("PlayerChargeData", p)}
ok = Charge.LoadDataFromDB(Base.Data.DwUin)
if !ok {
log.Debug("load PlayerChargeData failed:", UserName)
return errors.New("load PlayerChargeData failed")
}
p.playerdata["PlayerChargeData"] = Charge
p.playerdataIF["PlayerChargeData"] = Charge
// 玩家好友数据
friendEvt := &PlayerFriendEventData{PlayerData: NewPlayerData("PlayerFriendEventData", p)}
ok = friendEvt.LoadDataFromDB(Base.Data.DwUin)
if !ok {
log.Debug("load PlayerFriendEventData failed:", UserName)
return errors.New("load PlayerFriendEventData failed")
}
p.playerdata["PlayerFriendEventData"] = friendEvt
p.playerdataIF["PlayerFriendEventData"] = friendEvt
// 玩家模块数据
modData := &PlayerModData{PlayerData: NewPlayerData("PlayerModData", p)}
ok = modData.LoadDataFromDB(Base.Data.DwUin)
if !ok {
log.Debug("load PlayerModData failed:", UserName)
return errors.New("load PlayerModData failed")
}
IsUpdate, err := modData.InitMod()
if err != nil {
log.Debug("InitMod failed:", err)
return err
}
p.PlayMod.mod_list = modData.ModList
p.PlayMod.is_update = IsUpdate
p.PAMgr = new(PlayerActiveMgr)
p.PAMgr.InitActiveMgr(p)
go func() { // 处理数据回调
var cb *timer.Timer
for {
select {
case <-p.stopSignal:
return
case cb = <-p.MDispatr.ChanTimer:
if cb != nil {
cb.Cb()
} else {
log.Debug("Timer callback or Timer is nil")
}
case msg := <-p.msgChan:
fmt.Println("player recive msg:", msg)
go HandleMsg(p, msg)
}
}
}()
p.McronSave = cron.New()
_, err = p.McronSave.AddFunc("@every 1m", p.AutoSaveData)
if err != nil {
log.Debug("AddFunc failed:", err)
}
p.McronSave.Start()
p.ZeroUpdate(nil)
p.NoonUpdate(nil)
p.Login()
p.LoginBackData()
GoUtil.RegisterEvent(MergeConst.Notify_Daily_Renew, p.ZeroUpdate, p)
GoUtil.RegisterEvent(MergeConst.Notify_Midday_Renew, p.ZeroUpdate, p)
SyncFriendMsg(p)
return nil
}
// 异步发送消息
func (p *Player) SendMsg(m *MsgMod.Msg) {
p.msgChan <- m
}
func (p *Player) Test() {
p.PlayMod.getBaseMod().EnergyMul = 100
}
// 零点更新
func (p *Player) ZeroUpdate(a []interface{}) {
VarMod := p.PlayMod.getVarMod()
zeroTimestamp := GoUtil.ZeroTimestamp()
PlayerBaseMod := p.GetPlayerBaseMod()
// 零点更新
if VarMod.DailyResetTime < zeroTimestamp {
VarMod.DailyResetTime = zeroTimestamp
VarMod.DailyVar = make(map[int]interface{})
//卡牌
p.PlayMod.getCardMod().ZeroUpdate()
p.PushClientRes(p.PlayMod.getCardMod().BackData())
// 每日任务
p.PlayMod.getDailyTaskMod().ZeroUpdate(p.GetPlayerBaseMod().GetLevel(), p.PlayMod.getDecorateMod().GetAreaId())
p.PushClientRes(p.PlayMod.getDailyTaskMod().BackData())
// 能量商店
p.PlayMod.getBaseMod().ZeroUpdate()
p.PushClientRes(p.PlayMod.getBaseMod().BackData())
// 七日签到
p.PlayMod.getSevenLoginMod().ZeroUpdate(PlayerBaseMod.GetSevenLoginAdd(), PlayerBaseMod.GetLastLoginTime())
p.PushClientRes(p.PlayMod.getSevenLoginMod().BackData())
// 礼包充值
ChessMod := p.PlayMod.getChessMod()
p.PlayMod.getChargeMod().ZeroUpdate(ChessMod.GetEmitList())
p.PushClientRes(p.PlayMod.getChargeMod().BackData())
// 无尽礼包
p.PlayMod.getEndlessMod().ZeroUpdate(p.PlayMod.getChargeMod().GetMaxCharge())
p.PushClientRes(p.PlayMod.getEndlessMod().BackData())
p.PlayMod.save()
}
// 周更新
weekZeroTimestamp := GoUtil.WeekZeroTimestamp()
if VarMod.WeeklyResetTime < weekZeroTimestamp {
VarMod.WeeklyResetTime = weekZeroTimestamp
VarMod.WeeklyVar = make(map[int]interface{})
p.PlayMod.getDailyTaskMod().WeekUpdate()
p.PushClientRes(p.PlayMod.getDailyTaskMod().BackData())
p.PlayMod.getLimitedTimeEventMod().WeekUpdate()
p.PlayMod.save()
}
}
// 十二点更新
func (p *Player) NoonUpdate(a []interface{}) {
VarMod := p.PlayMod.getVarMod()
noonTimestamp := GoUtil.NoonTimestamp()
// 零点更新
if VarMod.NoonResetTime < noonTimestamp {
VarMod.NoonResetTime = noonTimestamp
ChessMod := p.PlayMod.getChessMod()
// 礼包充值
p.PlayMod.getChargeMod().NoonUpdate(ChessMod.GetEmitList())
p.PushClientRes(p.PlayMod.getChargeMod().BackData())
p.PlayMod.save()
}
}
func (p *Player) Login() {
// 添加定时器
// 限时事件触发
LimitedTimeEventTrigger(p, 0)
// 猪猪银行触发
LimitedTimePiggyBankTrigger(p)
p.PlayMod.getCardMod().Login(G_GameLogicPtr.SeverInfo.OpenTime)
}
// 离线 保存数据
func (p *Player) ClearData() {
p.lock.Lock()
defer p.lock.Unlock()
log.Release("uid: %d, ClearData", p.M_DwUin)
for k, v := range p.playerdata {
if k == PLAYER_BASE_DATA || k == "PlayerChessData" {
v.ClearData()
}
}
p.PlayMod.ClearData(p)
GoUtil.RemoveEvent(MergeConst.Notify_Daily_Renew, p.ZeroUpdate, p)
p.Stop()
}
func (p *Player) AutoSaveData() {
//保存数据
for _, v := range p.playerdata {
v.SaveDataFromDB("")
}
p.PlayMod.ClearData(p)
}
// 重新连接
func (p *Player) Reconnect() {
for _, v := range p.playerdata {
v.Reconnect(true)
}
p.LoginBackData()
}
// 获取conn连接
func (p *Player) GetAgent() gate.Agent {
return p.agent
}
// 设置conn连接
func (p *Player) SetAgent(a gate.Agent) {
p.agent = a
}
func (p *Player) GetIFGameData(key string) interface{} {
v, ok := p.playerdataIF[key]
if ok {
return v
}
return nil
}
func (p *Player) GetPlayerBaseMod() *PlayerBaseData {
v, ok := p.playerdataIF[PLAYER_BASE_DATA]
if ok {
return v.(*PlayerBaseData)
}
return nil
}
func (p *Player) GetGameData(key string) PlayerDataModule {
v, ok := p.playerdata[key]
if ok {
return v
}
return nil
}
func (p *Player) GetGameMod(key string) interface{} {
v, ok := p.playerdata[key]
if ok {
return v
}
return nil
}
func (p *Player) GetAgentByPlayer() gate.Agent {
return p.agent
}
// 处理物品
func (p *Player) HandleItem(itemList []*item.Item, Label string) error {
if len(itemList) == 0 {
return nil
}
is_update := false
ResCard := make([]*msg.CardPack, 0)
ResItem := make([]*msg.ItemInfo, 0)
for _, v := range itemList {
if v.Num == 0 {
continue
}
if v.Num > 0 && Label != "" {
ResItem = append(ResItem, &msg.ItemInfo{Id: int32(v.Id), Num: int32(v.Num)})
}
IType := itemCfg.GetItemType(v.Id)
switch IType {
case item.ITEM_TYPE_ENERGY: // 能量
err := p.GetPlayerBaseMod().AddEnergy(v.Num)
is_update = true
if err != nil {
return err
}
case item.ITEM_TYPE_STAR: // 星星
err := p.GetPlayerBaseMod().AddStar(v.Num)
is_update = true
if err != nil {
return err
}
case item.ITEM_TYPE_DIAMOND: // 钻石
err := p.GetPlayerBaseMod().AddDiamond(v.Num)
is_update = true
if err != nil {
return err
}
case item.ITEM_TYPE_CARD_PACK: // 卡包
CardMod := p.PlayMod.getCardMod()
Effect := itemCfg.GetItemEffect(v.Id)
for i := 0; i < v.Num; i++ {
NewCard, err := CardMod.OpenCardPack(Effect)
if err != nil {
return err
}
ResCard = append(ResCard, &msg.CardPack{Id: int32(v.Id), Card: GoUtil.SliceIntToInt32(NewCard)})
}
p.PushClientRes(CardMod.BackData())
case item.ITEM_TYPE_CHESS: // 棋子
ChessMod := p.PlayMod.getChessMod()
for i := 0; i < v.Num; i++ {
ChessMod.AddChessBuff(v.Id)
}
p.PushClientRes(ChessMod.BackData())
case item.ITEM_TYPE_LIMIED_TIME_EVENT: // 限时事件
if p.GetPlayerBaseMod().GetLevel() < 6 { // 等级小于6级不触发
continue
}
EffectList := itemCfg.GetItemEffectList(v.Id)
LimitedTimeEventMod := p.PlayMod.getLimitedTimeEventMod()
if len(EffectList) < 2 {
log.Debug("Effect List error;item id :%d", v.Id)
continue
}
EndTime := LimitedTimeEventMod.AddEvent(EffectList[0], EffectList[1])
p.PushClientRes(&msg.LimitEventNotify{
Id: int32(EffectList[0]),
Type: limitedTimeEvent.EVENT_NOTIFY_TYPE_ADD,
EndTime: int32(EndTime),
Cd: int32(EffectList[1]),
})
LimitedTimeEventTrigger(p, EffectList[0])
case item.ITEM_TYPE_PIGGY_BANK: // 猪猪银行
PiggyBankMod := p.PlayMod.getPiggyBankMod()
Effect := itemCfg.GetItemEffect(v.Id)
PiggyBankMod.AddPiggyBank(Effect)
LimitedTimePiggyBankTrigger(p)
p.PushClientRes(PiggyBankMod.BackData())
default:
log.Debug("Item type error;item id :%d", v.Id)
}
}
ResItemPopId := 0
if v, ok := p.args["ResItemPopId"]; ok {
ResItemPopId = v.(int)
}
if len(ResItem) != 0 || len(ResCard) != 0 {
p.SendErrClienRes(&msg.ResItemPop{
Id: int32(ResItemPopId),
Items: ResItem,
CardPacks: ResCard,
Lable: Label,
})
}
NotifyCard := &msg.ResNotifyCard{}
NotifyCard.Card = make(map[int32]int32)
for _, v := range ResCard {
for _, c := range v.Card {
NotifyCard.Card[c]++
}
}
p.PushClientRes(NotifyCard)
if is_update {
p.PushClientRes(p.GetPlayerBaseMod().BackAsset())
}
return nil
}
// 登录返回数据
func (p *Player) LoginBackData() {
p.PushClientRes(p.PlayMod.mod_list.Base.BackData())
p.PushClientRes(p.PlayMod.mod_list.Handbook.BackData())
p.PushClientRes(p.PlayMod.mod_list.Base.BackData())
p.PushClientRes(p.PlayMod.mod_list.Chess.BackData())
p.PushClientRes(p.PlayMod.mod_list.Order.BackData())
p.PushClientRes(p.PlayMod.mod_list.Card.BackData())
p.PushClientRes(p.PlayMod.mod_list.Decorate.BackData())
p.PushClientRes(p.PlayMod.mod_list.DailyTask.BackData())
p.PushClientRes(p.PlayMod.mod_list.SevenLogin.BackData())
p.PushClientRes(p.PlayMod.mod_list.Activity.BackData())
p.PushClientRes(p.PlayMod.mod_list.LimitedTimeEvent.ProgressBackData())
p.PushClientRes(p.PlayMod.mod_list.Charge.BackData())
p.PushClientRes(p.PlayMod.mod_list.Endless.BackData())
p.PushClientRes(p.PlayMod.mod_list.PiggyBank.BackData())
p.PushClientRes(p.GetPlayerBaseMod().BackAsset())
p.PushClientRes(p.GetPlayerBaseMod().BackKv())
MyRank := G_GameLogicPtr.RankMgr.getMyRank(RANK_TYPE_CHAMPSHIP, int(p.M_DwUin))
p.PushClientRes(p.PlayMod.mod_list.Champship.BackData(MyRank))
BackUserInfo(p)
}
// 获取玩家简单数据
func (p *Player) GetSimpleData(Uid int, simple *PlayerSimpleData) error {
p.lock.Lock()
defer p.lock.Unlock()
p.Msg = make(map[string]PlayerMsg)
p.args = make(map[string]interface{})
p.timerList = make(map[string]*timer.Timer)
p.MDispatr = timer.NewDispatcher(10)
p.stopSignal = make(chan bool)
p.playerdata = make(map[string]PlayerDataModule)
p.playerdataIF = make(map[string]interface{})
Base := &PlayerBaseData{PlayerData: NewPlayerData(PLAYER_BASE_DATA, p)}
p.playerdata[PLAYER_BASE_DATA] = Base
p.playerdataIF[PLAYER_BASE_DATA] = Base
// 玩家基础数据
ok := Base.GetDataByUid(Uid)
if !ok {
return errors.New("load PlayerBaseData failed")
}
p.playerdata[PLAYER_BASE_DATA] = Base
p.playerdataIF[PLAYER_BASE_DATA] = Base
p.M_DwUin = Base.Data.DwUin
// 玩家模块数据
modData := &PlayerModData{PlayerData: NewPlayerData("PlayerModData", p)}
ok = modData.LoadDataFromDB(Base.Data.DwUin)
if !ok {
return errors.New("load PlayerModData failed")
}
modData.InitMod()
p.PlayMod.mod_list = modData.ModList
simple.Name = p.GetPlayerBaseMod().GetName()
simple.Avatar = p.PlayMod.getAvatarMod().SetId
simple.Face = p.PlayMod.getFaceMod().SetId
simple.Level = p.GetPlayerBaseMod().GetLevel()
simple.Decorate = p.PlayMod.getDecorateMod().DecorateNum
simple.Login = int64(Base.Data.LoginTime)
simple.Loginout = int64(Base.Data.LogoutTime)
return nil
}
func (p *Player) HandleInUserRank() {
DecorateMod := p.PlayMod.getDecorateMod()
AreaId := DecorateMod.GetAreaId()
Progress := DecorateMod.GetProgress()
Score := float64(AreaId*1000 + Progress)
// 更新排行榜
m := &MsgMod.Msg{
Type: MsgMod.HANDLE_TYPE_RANK,
SendT: GoUtil.Now(),
Extra: RankMsg{
Uid: int(p.M_DwUin),
Score: Score,
RankType: RANK_TYPE_USER,
},
}
G_GameLogicPtr.RankMgrSend(m)
}
func (p *Player) HandleInChampshipRank() {
ChampshipMod := p.PlayMod.getChampshipMod()
Score := float64(ChampshipMod.GetScore())
// 更新排行榜
m := &MsgMod.Msg{
Type: MsgMod.HANDLE_TYPE_RANK,
SendT: GoUtil.Now(),
Extra: RankMsg{
Uid: int(p.M_DwUin),
Score: Score,
RankType: RANK_TYPE_CHAMPSHIP,
},
}
G_GameLogicPtr.RankMgrSend(m)
}