mirror of
https://github.com/FlourishingWorld/hk4e.git
synced 2026-03-01 00:35:36 +08:00
优化架构
This commit is contained in:
211
gs/game/aoi/aoi.go
Normal file
211
gs/game/aoi/aoi.go
Normal file
@@ -0,0 +1,211 @@
|
||||
package aoi
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"hk4e/logger"
|
||||
)
|
||||
|
||||
// aoi管理模块
|
||||
type AoiManager struct {
|
||||
// 区域边界坐标
|
||||
minX int16
|
||||
maxX int16
|
||||
minY int16
|
||||
maxY int16
|
||||
minZ int16
|
||||
maxZ int16
|
||||
numX int16 // x方向格子的数量
|
||||
numY int16 // y方向的格子数量
|
||||
numZ int16 // z方向的格子数量
|
||||
gridMap map[uint32]*Grid // 当前区域中都有哪些格子 key:gid value:格子对象
|
||||
}
|
||||
|
||||
// 初始化aoi区域
|
||||
func NewAoiManager(minX, maxX, numX, minY, maxY, numY, minZ, maxZ, numZ int16) (r *AoiManager) {
|
||||
r = new(AoiManager)
|
||||
r.minX = minX
|
||||
r.maxX = maxX
|
||||
r.minY = minY
|
||||
r.maxY = maxY
|
||||
r.numX = numX
|
||||
r.numY = numY
|
||||
r.minZ = minZ
|
||||
r.maxZ = maxZ
|
||||
r.numZ = numZ
|
||||
r.gridMap = make(map[uint32]*Grid)
|
||||
logger.LOG.Info("start init aoi area grid, num: %v", uint32(numX)*uint32(numY)*uint32(numZ))
|
||||
// 初始化aoi区域中所有的格子
|
||||
for x := int16(0); x < numX; x++ {
|
||||
for y := int16(0); y < numY; y++ {
|
||||
for z := int16(0); z < numZ; z++ {
|
||||
// 利用格子坐标得到格子id gid从0开始按xzy的顺序增长
|
||||
gid := uint32(y)*(uint32(numX)*uint32(numZ)) + uint32(z)*uint32(numX) + uint32(x)
|
||||
// 初始化一个格子放在aoi中的map里 key是当前格子的id
|
||||
grid := NewGrid(
|
||||
gid,
|
||||
r.minX+x*r.GridXLen(),
|
||||
r.minX+(x+1)*r.GridXLen(),
|
||||
r.minY+y*r.GridYLen(),
|
||||
r.minY+(y+1)*r.GridYLen(),
|
||||
r.minZ+z*r.GridZLen(),
|
||||
r.minZ+(z+1)*r.GridZLen(),
|
||||
)
|
||||
r.gridMap[gid] = grid
|
||||
}
|
||||
}
|
||||
}
|
||||
logger.LOG.Info("init aoi area grid finish")
|
||||
return r
|
||||
}
|
||||
|
||||
// 每个格子在x轴方向的长度
|
||||
func (a *AoiManager) GridXLen() int16 {
|
||||
return (a.maxX - a.minX) / a.numX
|
||||
}
|
||||
|
||||
// 每个格子在y轴方向的长度
|
||||
func (a *AoiManager) GridYLen() int16 {
|
||||
return (a.maxY - a.minY) / a.numY
|
||||
}
|
||||
|
||||
// 每个格子在z轴方向的长度
|
||||
func (a *AoiManager) GridZLen() int16 {
|
||||
return (a.maxZ - a.minZ) / a.numZ
|
||||
}
|
||||
|
||||
// 通过坐标获取对应的格子id
|
||||
func (a *AoiManager) GetGidByPos(x, y, z float32) uint32 {
|
||||
gx := (int16(x) - a.minX) / a.GridXLen()
|
||||
gy := (int16(y) - a.minY) / a.GridYLen()
|
||||
gz := (int16(z) - a.minZ) / a.GridZLen()
|
||||
return uint32(gy)*(uint32(a.numX)*uint32(a.numZ)) + uint32(gz)*uint32(a.numX) + uint32(gx)
|
||||
}
|
||||
|
||||
// 判断坐标是否存在于aoi区域内
|
||||
func (a *AoiManager) IsValidAoiPos(x, y, z float32) bool {
|
||||
if (int16(x) > a.minX && int16(x) < a.maxX) &&
|
||||
(int16(y) > a.minY && int16(y) < a.maxY) &&
|
||||
(int16(z) > a.minZ && int16(z) < a.maxZ) {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// 打印信息方法
|
||||
func (a *AoiManager) DebugString() string {
|
||||
s := fmt.Sprintf("AoiMgr: minX: %d, maxX: %d, numX: %d, minY: %d, maxY: %d, numY: %d, minZ: %d, maxZ: %d, numZ: %d\n",
|
||||
a.minX, a.maxX, a.numX, a.minY, a.maxY, a.numY, a.minZ, a.maxZ, a.numZ)
|
||||
s += "gridList in AoiMgr:\n"
|
||||
for _, grid := range a.gridMap {
|
||||
s += fmt.Sprintln(grid.DebugString())
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
// 根据格子的gid得到当前周边的格子信息
|
||||
func (a *AoiManager) GetSurrGridListByGid(gid uint32) (gridList []*Grid) {
|
||||
gridList = make([]*Grid, 0)
|
||||
// 判断grid是否存在
|
||||
grid, exist := a.gridMap[gid]
|
||||
if !exist {
|
||||
return gridList
|
||||
}
|
||||
// 添加自己
|
||||
gridList = append(gridList, grid)
|
||||
// 根据gid得到当前格子所在的x轴编号
|
||||
idx := int16(gid % (uint32(a.numX) * uint32(a.numZ)) % uint32(a.numX))
|
||||
// 判断当前格子左边是否还有格子
|
||||
if idx > 0 {
|
||||
gridList = append(gridList, a.gridMap[gid-1])
|
||||
}
|
||||
// 判断当前格子右边是否还有格子
|
||||
if idx < a.numX-1 {
|
||||
gridList = append(gridList, a.gridMap[gid+1])
|
||||
}
|
||||
// 将x轴当前的格子都取出进行遍历 再分别得到每个格子的平面上下是否有格子
|
||||
// 得到当前x轴的格子id集合
|
||||
gidListX := make([]uint32, 0)
|
||||
for _, v := range gridList {
|
||||
gidListX = append(gidListX, v.gid)
|
||||
}
|
||||
// 遍历x轴格子
|
||||
for _, v := range gidListX {
|
||||
// 计算该格子的idz
|
||||
idz := int16(v % (uint32(a.numX) * uint32(a.numZ)) / uint32(a.numX))
|
||||
// 判断当前格子平面上方是否还有格子
|
||||
if idz > 0 {
|
||||
gridList = append(gridList, a.gridMap[v-uint32(a.numX)])
|
||||
}
|
||||
// 判断当前格子平面下方是否还有格子
|
||||
if idz < a.numZ-1 {
|
||||
gridList = append(gridList, a.gridMap[v+uint32(a.numX)])
|
||||
}
|
||||
}
|
||||
// 将xoz平面当前的格子都取出进行遍历 再分别得到每个格子的空间上下是否有格子
|
||||
// 得到当前xoz平面的格子id集合
|
||||
gidListXOZ := make([]uint32, 0)
|
||||
for _, v := range gridList {
|
||||
gidListXOZ = append(gidListXOZ, v.gid)
|
||||
}
|
||||
// 遍历xoz平面格子
|
||||
for _, v := range gidListXOZ {
|
||||
// 计算该格子的idy
|
||||
idy := int16(v / (uint32(a.numX) * uint32(a.numZ)))
|
||||
// 判断当前格子空间上方是否还有格子
|
||||
if idy > 0 {
|
||||
gridList = append(gridList, a.gridMap[v-uint32(a.numX)*uint32(a.numZ)])
|
||||
}
|
||||
// 判断当前格子空间下方是否还有格子
|
||||
if idy < a.numY-1 {
|
||||
gridList = append(gridList, a.gridMap[v+uint32(a.numX)*uint32(a.numZ)])
|
||||
}
|
||||
}
|
||||
return gridList
|
||||
}
|
||||
|
||||
// 通过坐标得到周边格子内的全部entityId
|
||||
func (a *AoiManager) GetEntityIdListByPos(x, y, z float32) (entityIdList []uint32) {
|
||||
// 根据坐标得到当前坐标属于哪个格子id
|
||||
gid := a.GetGidByPos(x, y, z)
|
||||
// 根据格子id得到周边格子的信息
|
||||
gridList := a.GetSurrGridListByGid(gid)
|
||||
entityIdList = make([]uint32, 0)
|
||||
for _, v := range gridList {
|
||||
tmp := v.GetEntityIdList()
|
||||
entityIdList = append(entityIdList, tmp...)
|
||||
//logger.LOG.Debug("Grid: gid: %d, tmp len: %v", v.gid, len(tmp))
|
||||
}
|
||||
return entityIdList
|
||||
}
|
||||
|
||||
// 通过gid获取当前格子的全部entityId
|
||||
func (a *AoiManager) GetEntityIdListByGid(gid uint32) (entityIdList []uint32) {
|
||||
grid := a.gridMap[gid]
|
||||
entityIdList = grid.GetEntityIdList()
|
||||
return entityIdList
|
||||
}
|
||||
|
||||
// 添加一个entityId到一个格子中
|
||||
func (a *AoiManager) AddEntityIdToGrid(entityId uint32, gid uint32) {
|
||||
grid := a.gridMap[gid]
|
||||
grid.AddEntityId(entityId)
|
||||
}
|
||||
|
||||
// 移除一个格子中的entityId
|
||||
func (a *AoiManager) RemoveEntityIdFromGrid(entityId uint32, gid uint32) {
|
||||
grid := a.gridMap[gid]
|
||||
grid.RemoveEntityId(entityId)
|
||||
}
|
||||
|
||||
// 通过坐标添加一个entityId到一个格子中
|
||||
func (a *AoiManager) AddEntityIdToGridByPos(entityId uint32, x, y, z float32) {
|
||||
gid := a.GetGidByPos(x, y, z)
|
||||
a.AddEntityIdToGrid(entityId, gid)
|
||||
}
|
||||
|
||||
// 通过坐标把一个entityId从对应的格子中删除
|
||||
func (a *AoiManager) RemoveEntityIdFromGridByPos(entityId uint32, x, y, z float32) {
|
||||
gid := a.GetGidByPos(x, y, z)
|
||||
a.RemoveEntityIdFromGrid(entityId, gid)
|
||||
}
|
||||
30
gs/game/aoi/aoi_test.go
Normal file
30
gs/game/aoi/aoi_test.go
Normal file
@@ -0,0 +1,30 @@
|
||||
package aoi
|
||||
|
||||
import (
|
||||
"hk4e/common/config"
|
||||
"hk4e/logger"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestAoiManagerGetSurrGridListByGid(t *testing.T) {
|
||||
filePath := "./application.toml"
|
||||
config.InitConfig(filePath)
|
||||
logger.InitLogger("")
|
||||
aoiManager := NewAoiManager(
|
||||
-150, 150, 3,
|
||||
-150, 150, 3,
|
||||
-150, 150, 3,
|
||||
)
|
||||
logger.LOG.Debug("aoiManager: %s", aoiManager.DebugString())
|
||||
for k := range aoiManager.gridMap {
|
||||
// 得到当前格子周边的九宫格
|
||||
gridList := aoiManager.GetSurrGridListByGid(k)
|
||||
// 得到九宫格所有的id
|
||||
logger.LOG.Debug("gid: %d gridList len: %d", k, len(gridList))
|
||||
gidList := make([]uint32, 0, len(gridList))
|
||||
for _, grid := range gridList {
|
||||
gidList = append(gidList, grid.gid)
|
||||
}
|
||||
logger.LOG.Debug("Grid: gid: %d, surr grid gid list: %v", k, gidList)
|
||||
}
|
||||
}
|
||||
63
gs/game/aoi/grid.go
Normal file
63
gs/game/aoi/grid.go
Normal file
@@ -0,0 +1,63 @@
|
||||
package aoi
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"hk4e/logger"
|
||||
)
|
||||
|
||||
// 地图格子
|
||||
type Grid struct {
|
||||
gid uint32 // 格子id
|
||||
// 格子边界坐标
|
||||
minX int16
|
||||
maxX int16
|
||||
minY int16
|
||||
maxY int16
|
||||
minZ int16
|
||||
maxZ int16
|
||||
entityIdMap map[uint32]bool // k:entityId v:是否存在
|
||||
}
|
||||
|
||||
// 初始化格子
|
||||
func NewGrid(gid uint32, minX, maxX, minY, maxY, minZ, maxZ int16) (r *Grid) {
|
||||
r = new(Grid)
|
||||
r.gid = gid
|
||||
r.minX = minX
|
||||
r.maxX = maxX
|
||||
r.minY = minY
|
||||
r.maxY = maxY
|
||||
r.minZ = minZ
|
||||
r.maxZ = maxZ
|
||||
r.entityIdMap = make(map[uint32]bool)
|
||||
return r
|
||||
}
|
||||
|
||||
// 向格子中添加一个实体id
|
||||
func (g *Grid) AddEntityId(entityId uint32) {
|
||||
g.entityIdMap[entityId] = true
|
||||
}
|
||||
|
||||
// 从格子中删除一个实体id
|
||||
func (g *Grid) RemoveEntityId(entityId uint32) {
|
||||
_, exist := g.entityIdMap[entityId]
|
||||
if exist {
|
||||
delete(g.entityIdMap, entityId)
|
||||
} else {
|
||||
logger.LOG.Error("remove entity id but it not exist, entityId: %v", entityId)
|
||||
}
|
||||
}
|
||||
|
||||
// 获取格子中所有实体id
|
||||
func (g *Grid) GetEntityIdList() (entityIdList []uint32) {
|
||||
entityIdList = make([]uint32, 0)
|
||||
for k := range g.entityIdMap {
|
||||
entityIdList = append(entityIdList, k)
|
||||
}
|
||||
return entityIdList
|
||||
}
|
||||
|
||||
// 打印信息方法
|
||||
func (g *Grid) DebugString() string {
|
||||
return fmt.Sprintf("Grid: gid: %d, minX: %d, maxX: %d, minY: %d, maxY: %d, minZ: %d, maxZ: %d, entityIdMap: %v",
|
||||
g.gid, g.minX, g.maxX, g.minY, g.maxY, g.minZ, g.maxZ, g.entityIdMap)
|
||||
}
|
||||
122
gs/game/game_manager.go
Normal file
122
gs/game/game_manager.go
Normal file
@@ -0,0 +1,122 @@
|
||||
package game
|
||||
|
||||
import (
|
||||
pb "google.golang.org/protobuf/proto"
|
||||
"hk4e/common/utils/alg"
|
||||
"hk4e/gate/entity/gm"
|
||||
"hk4e/gate/kcp"
|
||||
"hk4e/gs/dao"
|
||||
"hk4e/gs/model"
|
||||
"hk4e/logger"
|
||||
"hk4e/protocol/cmd"
|
||||
"hk4e/protocol/proto"
|
||||
)
|
||||
|
||||
type GameManager struct {
|
||||
dao *dao.Dao
|
||||
netMsgInput chan *cmd.NetMsg
|
||||
netMsgOutput chan *cmd.NetMsg
|
||||
snowflake *alg.SnowflakeWorker
|
||||
// 本地事件队列管理器
|
||||
localEventManager *LocalEventManager
|
||||
// 接口路由管理器
|
||||
routeManager *RouteManager
|
||||
// 用户管理器
|
||||
userManager *UserManager
|
||||
// 世界管理器
|
||||
worldManager *WorldManager
|
||||
// 游戏服务器tick
|
||||
tickManager *TickManager
|
||||
}
|
||||
|
||||
func NewGameManager(dao *dao.Dao, netMsgInput chan *cmd.NetMsg, netMsgOutput chan *cmd.NetMsg) (r *GameManager) {
|
||||
r = new(GameManager)
|
||||
r.dao = dao
|
||||
r.netMsgInput = netMsgInput
|
||||
r.netMsgOutput = netMsgOutput
|
||||
r.snowflake = alg.NewSnowflakeWorker(1)
|
||||
r.localEventManager = NewLocalEventManager(r)
|
||||
r.routeManager = NewRouteManager(r)
|
||||
r.userManager = NewUserManager(dao, r.localEventManager.localEventChan)
|
||||
r.worldManager = NewWorldManager(r.snowflake)
|
||||
r.tickManager = NewTickManager(r)
|
||||
|
||||
//r.worldManager.worldStatic.InitTerrain()
|
||||
//r.worldManager.worldStatic.Pathfinding()
|
||||
//r.worldManager.worldStatic.ConvPathVectorListToAiMoveVectorList()
|
||||
|
||||
// 大世界的主人
|
||||
r.OnRegOk(false, &proto.SetPlayerBornDataReq{AvatarId: 10000007, NickName: "大世界的主人"}, 1, 0)
|
||||
bigWorldOwner := r.userManager.GetOnlineUser(1)
|
||||
bigWorldOwner.SceneLoadState = model.SceneEnterDone
|
||||
bigWorldOwner.DbState = model.DbNormal
|
||||
r.worldManager.InitBigWorld(bigWorldOwner)
|
||||
|
||||
return r
|
||||
}
|
||||
|
||||
func (g *GameManager) Start() {
|
||||
g.routeManager.InitRoute()
|
||||
g.userManager.StartAutoSaveUser()
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case netMsg := <-g.netMsgOutput:
|
||||
// 接收客户端消息
|
||||
g.routeManager.RouteHandle(netMsg)
|
||||
case <-g.tickManager.ticker.C:
|
||||
// 游戏服务器定时帧
|
||||
g.tickManager.OnGameServerTick()
|
||||
case localEvent := <-g.localEventManager.localEventChan:
|
||||
// 处理本地事件
|
||||
g.localEventManager.LocalEventHandle(localEvent)
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func (g *GameManager) Stop() {
|
||||
g.worldManager.worldStatic.SaveTerrain()
|
||||
}
|
||||
|
||||
// 发送消息给客户端
|
||||
func (g *GameManager) SendMsg(cmdId uint16, userId uint32, clientSeq uint32, payloadMsg pb.Message) {
|
||||
if userId < 100000000 {
|
||||
return
|
||||
}
|
||||
netMsg := new(cmd.NetMsg)
|
||||
netMsg.UserId = userId
|
||||
netMsg.EventId = cmd.NormalMsg
|
||||
netMsg.CmdId = cmdId
|
||||
netMsg.ClientSeq = clientSeq
|
||||
// 在这里直接序列化成二进制数据 防止发送的消息内包含各种游戏数据指针 而造成并发读写的问题
|
||||
payloadMessageData, err := pb.Marshal(payloadMsg)
|
||||
if err != nil {
|
||||
logger.LOG.Error("parse payload msg to bin error: %v", err)
|
||||
return
|
||||
}
|
||||
netMsg.PayloadMessageData = payloadMessageData
|
||||
g.netMsgInput <- netMsg
|
||||
}
|
||||
|
||||
func (g *GameManager) ReconnectPlayer(userId uint32) {
|
||||
g.SendMsg(cmd.ClientReconnectNotify, userId, 0, new(proto.ClientReconnectNotify))
|
||||
}
|
||||
|
||||
func (g *GameManager) DisconnectPlayer(userId uint32) {
|
||||
g.SendMsg(cmd.ServerDisconnectClientNotify, userId, 0, new(proto.ServerDisconnectClientNotify))
|
||||
}
|
||||
|
||||
func (g *GameManager) KickPlayer(userId uint32) {
|
||||
info := new(gm.KickPlayerInfo)
|
||||
info.UserId = userId
|
||||
// 客户端提示信息为服务器断开连接
|
||||
info.Reason = uint32(kcp.EnetServerKick)
|
||||
var result bool
|
||||
ok := false
|
||||
//ok := r.hk4eGatewayConsumer.CallFunction("RpcManager", "KickPlayer", &info, &result)
|
||||
if ok == true && result == true {
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
34
gs/game/local_event_manager.go
Normal file
34
gs/game/local_event_manager.go
Normal file
@@ -0,0 +1,34 @@
|
||||
package game
|
||||
|
||||
const (
|
||||
LoadLoginUserFromDbFinish = iota
|
||||
CheckUserExistOnRegFromDbFinish
|
||||
)
|
||||
|
||||
type LocalEvent struct {
|
||||
EventId int
|
||||
Msg any
|
||||
}
|
||||
|
||||
type LocalEventManager struct {
|
||||
localEventChan chan *LocalEvent
|
||||
gameManager *GameManager
|
||||
}
|
||||
|
||||
func NewLocalEventManager(gameManager *GameManager) (r *LocalEventManager) {
|
||||
r = new(LocalEventManager)
|
||||
r.localEventChan = make(chan *LocalEvent, 1000)
|
||||
r.gameManager = gameManager
|
||||
return r
|
||||
}
|
||||
|
||||
func (l *LocalEventManager) LocalEventHandle(localEvent *LocalEvent) {
|
||||
switch localEvent.EventId {
|
||||
case LoadLoginUserFromDbFinish:
|
||||
playerLoginInfo := localEvent.Msg.(*PlayerLoginInfo)
|
||||
l.gameManager.OnLoginOk(playerLoginInfo.UserId, playerLoginInfo.Player, playerLoginInfo.ClientSeq)
|
||||
case CheckUserExistOnRegFromDbFinish:
|
||||
playerRegInfo := localEvent.Msg.(*PlayerRegInfo)
|
||||
l.gameManager.OnRegOk(playerRegInfo.Exist, playerRegInfo.Req, playerRegInfo.UserId, playerRegInfo.ClientSeq)
|
||||
}
|
||||
}
|
||||
104
gs/game/msg_common_handler.go
Normal file
104
gs/game/msg_common_handler.go
Normal file
@@ -0,0 +1,104 @@
|
||||
package game
|
||||
|
||||
import (
|
||||
pb "google.golang.org/protobuf/proto"
|
||||
"hk4e/gs/model"
|
||||
"hk4e/logger"
|
||||
"hk4e/protocol/cmd"
|
||||
"hk4e/protocol/proto"
|
||||
"time"
|
||||
)
|
||||
|
||||
func (g *GameManager) PlayerSetPauseReq(player *model.Player, payloadMsg pb.Message) {
|
||||
logger.LOG.Debug("user pause, uid: %v", player.PlayerID)
|
||||
req := payloadMsg.(*proto.PlayerSetPauseReq)
|
||||
isPaused := req.IsPaused
|
||||
|
||||
player.Pause = isPaused
|
||||
|
||||
// PacketPlayerSetPauseRsp
|
||||
playerSetPauseRsp := new(proto.PlayerSetPauseRsp)
|
||||
g.SendMsg(cmd.PlayerSetPauseRsp, player.PlayerID, player.ClientSeq, playerSetPauseRsp)
|
||||
}
|
||||
|
||||
func (g *GameManager) TowerAllDataReq(player *model.Player, payloadMsg pb.Message) {
|
||||
logger.LOG.Debug("user get tower all data, uid: %v", player.PlayerID)
|
||||
|
||||
// PacketTowerAllDataRsp
|
||||
towerAllDataRsp := new(proto.TowerAllDataRsp)
|
||||
towerAllDataRsp.TowerScheduleId = 29
|
||||
towerAllDataRsp.TowerFloorRecordList = []*proto.TowerFloorRecord{{FloorId: 1001}}
|
||||
towerAllDataRsp.CurLevelRecord = &proto.TowerCurLevelRecord{IsEmpty: true}
|
||||
towerAllDataRsp.NextScheduleChangeTime = 4294967295
|
||||
towerAllDataRsp.FloorOpenTimeMap = make(map[uint32]uint32)
|
||||
towerAllDataRsp.FloorOpenTimeMap[1024] = 1630486800
|
||||
towerAllDataRsp.FloorOpenTimeMap[1025] = 1630486800
|
||||
towerAllDataRsp.FloorOpenTimeMap[1026] = 1630486800
|
||||
towerAllDataRsp.FloorOpenTimeMap[1027] = 1630486800
|
||||
towerAllDataRsp.ScheduleStartTime = 1630486800
|
||||
g.SendMsg(cmd.TowerAllDataRsp, player.PlayerID, player.ClientSeq, towerAllDataRsp)
|
||||
}
|
||||
|
||||
func (g *GameManager) EntityAiSyncNotify(player *model.Player, payloadMsg pb.Message) {
|
||||
logger.LOG.Debug("user entity ai sync, uid: %v", player.PlayerID)
|
||||
req := payloadMsg.(*proto.EntityAiSyncNotify)
|
||||
|
||||
if len(req.LocalAvatarAlertedMonsterList) == 0 {
|
||||
return
|
||||
}
|
||||
|
||||
// PacketEntityAiSyncNotify
|
||||
entityAiSyncNotify := new(proto.EntityAiSyncNotify)
|
||||
entityAiSyncNotify.InfoList = make([]*proto.AiSyncInfo, 0)
|
||||
for _, monsterId := range req.LocalAvatarAlertedMonsterList {
|
||||
entityAiSyncNotify.InfoList = append(entityAiSyncNotify.InfoList, &proto.AiSyncInfo{
|
||||
EntityId: monsterId,
|
||||
HasPathToTarget: true,
|
||||
IsSelfKilling: false,
|
||||
})
|
||||
}
|
||||
g.SendMsg(cmd.EntityAiSyncNotify, player.PlayerID, player.ClientSeq, entityAiSyncNotify)
|
||||
}
|
||||
|
||||
func (g *GameManager) ClientTimeNotify(userId uint32, clientTime uint32) {
|
||||
player := g.userManager.GetOnlineUser(userId)
|
||||
if player == nil {
|
||||
logger.LOG.Error("player is nil, uid: %v", userId)
|
||||
return
|
||||
}
|
||||
logger.LOG.Debug("client time notify, uid: %v, time: %v", userId, clientTime)
|
||||
player.ClientTime = clientTime
|
||||
}
|
||||
|
||||
func (g *GameManager) ClientRttNotify(userId uint32, clientRtt uint32) {
|
||||
player := g.userManager.GetOnlineUser(userId)
|
||||
if player == nil {
|
||||
logger.LOG.Error("player is nil, uid: %v", userId)
|
||||
return
|
||||
}
|
||||
logger.LOG.Debug("client rtt notify, uid: %v, rtt: %v", userId, clientRtt)
|
||||
player.ClientRTT = clientRtt
|
||||
}
|
||||
|
||||
func (g *GameManager) ServerAnnounceNotify(announceId uint32, announceMsg string) {
|
||||
for _, onlinePlayer := range g.userManager.GetAllOnlineUserList() {
|
||||
serverAnnounceNotify := new(proto.ServerAnnounceNotify)
|
||||
now := uint32(time.Now().Unix())
|
||||
serverAnnounceNotify.AnnounceDataList = []*proto.AnnounceData{{
|
||||
ConfigId: announceId,
|
||||
BeginTime: now + 1,
|
||||
EndTime: now + 2,
|
||||
CenterSystemText: announceMsg,
|
||||
CenterSystemFrequency: 1,
|
||||
}}
|
||||
g.SendMsg(cmd.ServerAnnounceNotify, onlinePlayer.PlayerID, 0, serverAnnounceNotify)
|
||||
}
|
||||
}
|
||||
|
||||
func (g *GameManager) ServerAnnounceRevokeNotify(announceId uint32) {
|
||||
for _, onlinePlayer := range g.userManager.GetAllOnlineUserList() {
|
||||
serverAnnounceRevokeNotify := new(proto.ServerAnnounceRevokeNotify)
|
||||
serverAnnounceRevokeNotify.ConfigIdList = []uint32{announceId}
|
||||
g.SendMsg(cmd.ServerAnnounceRevokeNotify, onlinePlayer.PlayerID, 0, serverAnnounceRevokeNotify)
|
||||
}
|
||||
}
|
||||
116
gs/game/route_manager.go
Normal file
116
gs/game/route_manager.go
Normal file
@@ -0,0 +1,116 @@
|
||||
package game
|
||||
|
||||
import (
|
||||
pb "google.golang.org/protobuf/proto"
|
||||
"hk4e/gs/model"
|
||||
"hk4e/logger"
|
||||
"hk4e/protocol/cmd"
|
||||
)
|
||||
|
||||
type HandlerFunc func(player *model.Player, payloadMsg pb.Message)
|
||||
|
||||
type RouteManager struct {
|
||||
gameManager *GameManager
|
||||
// k:cmdId v:HandlerFunc
|
||||
handlerFuncRouteMap map[uint16]HandlerFunc
|
||||
}
|
||||
|
||||
func NewRouteManager(gameManager *GameManager) (r *RouteManager) {
|
||||
r = new(RouteManager)
|
||||
r.gameManager = gameManager
|
||||
r.handlerFuncRouteMap = make(map[uint16]HandlerFunc)
|
||||
return r
|
||||
}
|
||||
|
||||
func (r *RouteManager) registerRouter(cmdId uint16, handlerFunc HandlerFunc) {
|
||||
r.handlerFuncRouteMap[cmdId] = handlerFunc
|
||||
}
|
||||
|
||||
func (r *RouteManager) doRoute(cmdId uint16, userId uint32, clientSeq uint32, payloadMsg pb.Message) {
|
||||
handlerFunc, ok := r.handlerFuncRouteMap[cmdId]
|
||||
if !ok {
|
||||
logger.LOG.Error("no route for msg, cmdId: %v", cmdId)
|
||||
return
|
||||
}
|
||||
player := r.gameManager.userManager.GetOnlineUser(userId)
|
||||
if player == nil {
|
||||
logger.LOG.Error("player is nil, uid: %v", userId)
|
||||
return
|
||||
}
|
||||
player.ClientSeq = clientSeq
|
||||
handlerFunc(player, payloadMsg)
|
||||
}
|
||||
|
||||
func (r *RouteManager) InitRoute() {
|
||||
r.registerRouter(cmd.PlayerSetPauseReq, r.gameManager.PlayerSetPauseReq)
|
||||
r.registerRouter(cmd.EnterSceneReadyReq, r.gameManager.EnterSceneReadyReq)
|
||||
r.registerRouter(cmd.PathfindingEnterSceneReq, r.gameManager.PathfindingEnterSceneReq)
|
||||
r.registerRouter(cmd.GetScenePointReq, r.gameManager.GetScenePointReq)
|
||||
r.registerRouter(cmd.GetSceneAreaReq, r.gameManager.GetSceneAreaReq)
|
||||
r.registerRouter(cmd.SceneInitFinishReq, r.gameManager.SceneInitFinishReq)
|
||||
r.registerRouter(cmd.EnterSceneDoneReq, r.gameManager.EnterSceneDoneReq)
|
||||
r.registerRouter(cmd.EnterWorldAreaReq, r.gameManager.EnterWorldAreaReq)
|
||||
r.registerRouter(cmd.PostEnterSceneReq, r.gameManager.PostEnterSceneReq)
|
||||
r.registerRouter(cmd.TowerAllDataReq, r.gameManager.TowerAllDataReq)
|
||||
r.registerRouter(cmd.SceneTransToPointReq, r.gameManager.SceneTransToPointReq)
|
||||
r.registerRouter(cmd.MarkMapReq, r.gameManager.MarkMapReq)
|
||||
r.registerRouter(cmd.ChangeAvatarReq, r.gameManager.ChangeAvatarReq)
|
||||
r.registerRouter(cmd.SetUpAvatarTeamReq, r.gameManager.SetUpAvatarTeamReq)
|
||||
r.registerRouter(cmd.ChooseCurAvatarTeamReq, r.gameManager.ChooseCurAvatarTeamReq)
|
||||
r.registerRouter(cmd.GetGachaInfoReq, r.gameManager.GetGachaInfoReq)
|
||||
r.registerRouter(cmd.DoGachaReq, r.gameManager.DoGachaReq)
|
||||
r.registerRouter(cmd.QueryPathReq, r.gameManager.QueryPathReq)
|
||||
r.registerRouter(cmd.CombatInvocationsNotify, r.gameManager.CombatInvocationsNotify)
|
||||
r.registerRouter(cmd.AbilityInvocationsNotify, r.gameManager.AbilityInvocationsNotify)
|
||||
r.registerRouter(cmd.ClientAbilityInitFinishNotify, r.gameManager.ClientAbilityInitFinishNotify)
|
||||
r.registerRouter(cmd.EntityAiSyncNotify, r.gameManager.EntityAiSyncNotify)
|
||||
r.registerRouter(cmd.WearEquipReq, r.gameManager.WearEquipReq)
|
||||
r.registerRouter(cmd.ChangeGameTimeReq, r.gameManager.ChangeGameTimeReq)
|
||||
r.registerRouter(cmd.GetPlayerSocialDetailReq, r.gameManager.GetPlayerSocialDetailReq)
|
||||
r.registerRouter(cmd.SetPlayerBirthdayReq, r.gameManager.SetPlayerBirthdayReq)
|
||||
r.registerRouter(cmd.SetNameCardReq, r.gameManager.SetNameCardReq)
|
||||
r.registerRouter(cmd.SetPlayerSignatureReq, r.gameManager.SetPlayerSignatureReq)
|
||||
r.registerRouter(cmd.SetPlayerNameReq, r.gameManager.SetPlayerNameReq)
|
||||
r.registerRouter(cmd.SetPlayerHeadImageReq, r.gameManager.SetPlayerHeadImageReq)
|
||||
r.registerRouter(cmd.GetAllUnlockNameCardReq, r.gameManager.GetAllUnlockNameCardReq)
|
||||
r.registerRouter(cmd.GetPlayerFriendListReq, r.gameManager.GetPlayerFriendListReq)
|
||||
r.registerRouter(cmd.GetPlayerAskFriendListReq, r.gameManager.GetPlayerAskFriendListReq)
|
||||
r.registerRouter(cmd.AskAddFriendReq, r.gameManager.AskAddFriendReq)
|
||||
r.registerRouter(cmd.DealAddFriendReq, r.gameManager.DealAddFriendReq)
|
||||
r.registerRouter(cmd.GetOnlinePlayerListReq, r.gameManager.GetOnlinePlayerListReq)
|
||||
r.registerRouter(cmd.PlayerApplyEnterMpReq, r.gameManager.PlayerApplyEnterMpReq)
|
||||
r.registerRouter(cmd.PlayerApplyEnterMpResultReq, r.gameManager.PlayerApplyEnterMpResultReq)
|
||||
r.registerRouter(cmd.PlayerGetForceQuitBanInfoReq, r.gameManager.PlayerGetForceQuitBanInfoReq)
|
||||
r.registerRouter(cmd.GetShopmallDataReq, r.gameManager.GetShopmallDataReq)
|
||||
r.registerRouter(cmd.GetShopReq, r.gameManager.GetShopReq)
|
||||
r.registerRouter(cmd.BuyGoodsReq, r.gameManager.BuyGoodsReq)
|
||||
r.registerRouter(cmd.McoinExchangeHcoinReq, r.gameManager.McoinExchangeHcoinReq)
|
||||
r.registerRouter(cmd.AvatarChangeCostumeReq, r.gameManager.AvatarChangeCostumeReq)
|
||||
r.registerRouter(cmd.AvatarWearFlycloakReq, r.gameManager.AvatarWearFlycloakReq)
|
||||
r.registerRouter(cmd.PullRecentChatReq, r.gameManager.PullRecentChatReq)
|
||||
r.registerRouter(cmd.PullPrivateChatReq, r.gameManager.PullPrivateChatReq)
|
||||
r.registerRouter(cmd.PrivateChatReq, r.gameManager.PrivateChatReq)
|
||||
r.registerRouter(cmd.ReadPrivateChatReq, r.gameManager.ReadPrivateChatReq)
|
||||
r.registerRouter(cmd.PlayerChatReq, r.gameManager.PlayerChatReq)
|
||||
r.registerRouter(cmd.BackMyWorldReq, r.gameManager.BackMyWorldReq)
|
||||
r.registerRouter(cmd.ChangeWorldToSingleModeReq, r.gameManager.ChangeWorldToSingleModeReq)
|
||||
r.registerRouter(cmd.SceneKickPlayerReq, r.gameManager.SceneKickPlayerReq)
|
||||
r.registerRouter(cmd.ChangeMpTeamAvatarReq, r.gameManager.ChangeMpTeamAvatarReq)
|
||||
}
|
||||
|
||||
func (r *RouteManager) RouteHandle(netMsg *cmd.NetMsg) {
|
||||
switch netMsg.EventId {
|
||||
case cmd.NormalMsg:
|
||||
r.doRoute(netMsg.CmdId, netMsg.UserId, netMsg.ClientSeq, netMsg.PayloadMessage)
|
||||
case cmd.UserRegNotify:
|
||||
r.gameManager.OnReg(netMsg.UserId, netMsg.ClientSeq, netMsg.PayloadMessage)
|
||||
case cmd.UserLoginNotify:
|
||||
r.gameManager.OnLogin(netMsg.UserId, netMsg.ClientSeq)
|
||||
case cmd.UserOfflineNotify:
|
||||
r.gameManager.OnUserOffline(netMsg.UserId)
|
||||
case cmd.ClientRttNotify:
|
||||
r.gameManager.ClientRttNotify(netMsg.UserId, netMsg.ClientRtt)
|
||||
case cmd.ClientTimeNotify:
|
||||
r.gameManager.ClientTimeNotify(netMsg.UserId, netMsg.ClientTime)
|
||||
}
|
||||
}
|
||||
311
gs/game/tick_manager.go
Normal file
311
gs/game/tick_manager.go
Normal file
@@ -0,0 +1,311 @@
|
||||
package game
|
||||
|
||||
import (
|
||||
"hk4e/common/utils/random"
|
||||
"hk4e/gs/constant"
|
||||
"hk4e/gs/model"
|
||||
"hk4e/logger"
|
||||
"hk4e/protocol/cmd"
|
||||
"hk4e/protocol/proto"
|
||||
"time"
|
||||
)
|
||||
|
||||
type TickManager struct {
|
||||
ticker *time.Ticker
|
||||
tickCount uint64
|
||||
gameManager *GameManager
|
||||
}
|
||||
|
||||
func NewTickManager(gameManager *GameManager) (r *TickManager) {
|
||||
r = new(TickManager)
|
||||
r.ticker = time.NewTicker(time.Millisecond * 100)
|
||||
logger.LOG.Info("game server tick start at: %v", time.Now().UnixMilli())
|
||||
r.gameManager = gameManager
|
||||
return r
|
||||
}
|
||||
|
||||
func (t *TickManager) OnGameServerTick() {
|
||||
t.tickCount++
|
||||
now := time.Now().UnixMilli()
|
||||
t.onTick100MilliSecond(now)
|
||||
if t.tickCount%(10*1) == 0 {
|
||||
t.onTickSecond(now)
|
||||
}
|
||||
if t.tickCount%(10*5) == 0 {
|
||||
t.onTick5Second(now)
|
||||
}
|
||||
if t.tickCount%(10*10) == 0 {
|
||||
t.onTick10Second(now)
|
||||
}
|
||||
if t.tickCount%(10*60) == 0 {
|
||||
t.onTickMinute(now)
|
||||
}
|
||||
if t.tickCount%(10*60*10) == 0 {
|
||||
t.onTick10Minute(now)
|
||||
}
|
||||
if t.tickCount%(10*3600) == 0 {
|
||||
t.onTickHour(now)
|
||||
}
|
||||
if t.tickCount%(10*3600*24) == 0 {
|
||||
t.onTickDay(now)
|
||||
}
|
||||
if t.tickCount%(10*3600*24*7) == 0 {
|
||||
t.onTickWeek(now)
|
||||
}
|
||||
}
|
||||
|
||||
func (t *TickManager) onTickWeek(now int64) {
|
||||
logger.LOG.Info("on tick week, time: %v", now)
|
||||
}
|
||||
|
||||
func (t *TickManager) onTickDay(now int64) {
|
||||
logger.LOG.Info("on tick day, time: %v", now)
|
||||
}
|
||||
|
||||
func (t *TickManager) onTickHour(now int64) {
|
||||
logger.LOG.Info("on tick hour, time: %v", now)
|
||||
}
|
||||
|
||||
func (t *TickManager) onTick10Minute(now int64) {
|
||||
for _, world := range t.gameManager.worldManager.worldMap {
|
||||
for _, player := range world.playerMap {
|
||||
// 蓝球粉球
|
||||
t.gameManager.AddUserItem(player.PlayerID, []*UserItem{{ItemId: 223, ChangeCount: 1}}, true, 0)
|
||||
t.gameManager.AddUserItem(player.PlayerID, []*UserItem{{ItemId: 224, ChangeCount: 1}}, true, 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (t *TickManager) onTickMinute(now int64) {
|
||||
t.gameManager.ServerAnnounceNotify(100, "test123")
|
||||
for _, world := range t.gameManager.worldManager.worldMap {
|
||||
for _, player := range world.playerMap {
|
||||
// 随机物品
|
||||
allItemDataConfig := t.gameManager.GetAllItemDataConfig()
|
||||
count := random.GetRandomInt32(0, 4)
|
||||
i := int32(0)
|
||||
for itemId := range allItemDataConfig {
|
||||
itemDataConfig := allItemDataConfig[itemId]
|
||||
// TODO 3.0.0REL版本中 发送某些无效家具 可能会导致客户端背包家具界面卡死
|
||||
if itemDataConfig.ItemEnumType == constant.ItemTypeConst.ITEM_FURNITURE {
|
||||
continue
|
||||
}
|
||||
num := random.GetRandomInt32(1, 9)
|
||||
t.gameManager.AddUserItem(player.PlayerID, []*UserItem{{ItemId: uint32(itemId), ChangeCount: uint32(num)}}, true, 0)
|
||||
i++
|
||||
if i > count {
|
||||
break
|
||||
}
|
||||
}
|
||||
t.gameManager.AddUserItem(player.PlayerID, []*UserItem{{ItemId: 102, ChangeCount: 30}}, true, 0)
|
||||
t.gameManager.AddUserItem(player.PlayerID, []*UserItem{{ItemId: 201, ChangeCount: 10}}, true, 0)
|
||||
t.gameManager.AddUserItem(player.PlayerID, []*UserItem{{ItemId: 202, ChangeCount: 100}}, true, 0)
|
||||
t.gameManager.AddUserItem(player.PlayerID, []*UserItem{{ItemId: 203, ChangeCount: 10}}, true, 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (t *TickManager) onTick10Second(now int64) {
|
||||
for _, world := range t.gameManager.worldManager.worldMap {
|
||||
if !world.IsBigWorld() && (world.multiplayer || !world.owner.Pause) {
|
||||
// 刷怪
|
||||
scene := world.GetSceneById(3)
|
||||
monsterEntityCount := 0
|
||||
for _, entity := range scene.entityMap {
|
||||
if entity.entityType == uint32(proto.ProtEntityType_PROT_ENTITY_TYPE_MONSTER) {
|
||||
monsterEntityCount++
|
||||
}
|
||||
}
|
||||
if monsterEntityCount < 30 {
|
||||
monsterEntityId := t.createMonster(scene)
|
||||
bigWorldOwner := t.gameManager.userManager.GetOnlineUser(1)
|
||||
t.gameManager.AddSceneEntityNotify(bigWorldOwner, proto.VisionType_VISION_TYPE_BORN, []uint32{monsterEntityId}, true)
|
||||
}
|
||||
}
|
||||
for _, player := range world.playerMap {
|
||||
if world.multiplayer || !world.owner.Pause {
|
||||
// 改面板
|
||||
team := player.TeamConfig.GetActiveTeam()
|
||||
for _, avatarId := range team.AvatarIdList {
|
||||
if avatarId == 0 {
|
||||
break
|
||||
}
|
||||
avatar := player.AvatarMap[avatarId]
|
||||
avatar.FightPropMap[uint32(constant.FightPropertyConst.FIGHT_PROP_CUR_ATTACK)] = 1000000
|
||||
avatar.FightPropMap[uint32(constant.FightPropertyConst.FIGHT_PROP_CRITICAL)] = 1.0
|
||||
t.gameManager.UpdateUserAvatarFightProp(player.PlayerID, avatarId)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (t *TickManager) onTick5Second(now int64) {
|
||||
for _, world := range t.gameManager.worldManager.worldMap {
|
||||
if world.IsBigWorld() {
|
||||
for applyUid := range world.owner.CoopApplyMap {
|
||||
t.gameManager.UserDealEnterWorld(world.owner, applyUid, true)
|
||||
}
|
||||
}
|
||||
for _, player := range world.playerMap {
|
||||
if world.multiplayer {
|
||||
// PacketWorldPlayerLocationNotify
|
||||
worldPlayerLocationNotify := new(proto.WorldPlayerLocationNotify)
|
||||
for _, worldPlayer := range world.playerMap {
|
||||
playerWorldLocationInfo := &proto.PlayerWorldLocationInfo{
|
||||
SceneId: worldPlayer.SceneId,
|
||||
PlayerLoc: &proto.PlayerLocationInfo{
|
||||
Uid: worldPlayer.PlayerID,
|
||||
Pos: &proto.Vector{
|
||||
X: float32(worldPlayer.Pos.X),
|
||||
Y: float32(worldPlayer.Pos.Y),
|
||||
Z: float32(worldPlayer.Pos.Z),
|
||||
},
|
||||
Rot: &proto.Vector{
|
||||
X: float32(worldPlayer.Rot.X),
|
||||
Y: float32(worldPlayer.Rot.Y),
|
||||
Z: float32(worldPlayer.Rot.Z),
|
||||
},
|
||||
},
|
||||
}
|
||||
worldPlayerLocationNotify.PlayerWorldLocList = append(worldPlayerLocationNotify.PlayerWorldLocList, playerWorldLocationInfo)
|
||||
}
|
||||
t.gameManager.SendMsg(cmd.WorldPlayerLocationNotify, player.PlayerID, 0, worldPlayerLocationNotify)
|
||||
|
||||
// PacketScenePlayerLocationNotify
|
||||
scene := world.GetSceneById(player.SceneId)
|
||||
scenePlayerLocationNotify := new(proto.ScenePlayerLocationNotify)
|
||||
scenePlayerLocationNotify.SceneId = player.SceneId
|
||||
for _, scenePlayer := range scene.playerMap {
|
||||
playerLocationInfo := &proto.PlayerLocationInfo{
|
||||
Uid: scenePlayer.PlayerID,
|
||||
Pos: &proto.Vector{
|
||||
X: float32(scenePlayer.Pos.X),
|
||||
Y: float32(scenePlayer.Pos.Y),
|
||||
Z: float32(scenePlayer.Pos.Z),
|
||||
},
|
||||
Rot: &proto.Vector{
|
||||
X: float32(scenePlayer.Rot.X),
|
||||
Y: float32(scenePlayer.Rot.Y),
|
||||
Z: float32(scenePlayer.Rot.Z),
|
||||
},
|
||||
}
|
||||
scenePlayerLocationNotify.PlayerLocList = append(scenePlayerLocationNotify.PlayerLocList, playerLocationInfo)
|
||||
}
|
||||
t.gameManager.SendMsg(cmd.ScenePlayerLocationNotify, player.PlayerID, 0, scenePlayerLocationNotify)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (t *TickManager) onTickSecond(now int64) {
|
||||
for _, world := range t.gameManager.worldManager.worldMap {
|
||||
for _, player := range world.playerMap {
|
||||
// PacketWorldPlayerRTTNotify
|
||||
worldPlayerRTTNotify := new(proto.WorldPlayerRTTNotify)
|
||||
worldPlayerRTTNotify.PlayerRttList = make([]*proto.PlayerRTTInfo, 0)
|
||||
for _, worldPlayer := range world.playerMap {
|
||||
playerRTTInfo := &proto.PlayerRTTInfo{Uid: worldPlayer.PlayerID, Rtt: worldPlayer.ClientRTT}
|
||||
worldPlayerRTTNotify.PlayerRttList = append(worldPlayerRTTNotify.PlayerRttList, playerRTTInfo)
|
||||
}
|
||||
t.gameManager.SendMsg(cmd.WorldPlayerRTTNotify, player.PlayerID, 0, worldPlayerRTTNotify)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (t *TickManager) onTick100MilliSecond(now int64) {
|
||||
// AttackHandler
|
||||
for _, world := range t.gameManager.worldManager.worldMap {
|
||||
for _, scene := range world.sceneMap {
|
||||
scene.AttackHandler(t.gameManager)
|
||||
}
|
||||
}
|
||||
|
||||
//bigWorldOwner := t.gameManager.userManager.GetOnlineUser(1)
|
||||
//bigWorld := t.gameManager.worldManager.GetBigWorld()
|
||||
//bigWorldScene := bigWorld.GetSceneById(3)
|
||||
//
|
||||
//if len(bigWorldScene.playerMap) < 2 {
|
||||
// return
|
||||
//}
|
||||
//if t.gameManager.worldManager.worldStatic.aiMoveCurrIndex >= len(t.gameManager.worldManager.worldStatic.aiMoveVectorList)-1 {
|
||||
// return
|
||||
//}
|
||||
//t.gameManager.worldManager.worldStatic.aiMoveCurrIndex++
|
||||
//
|
||||
//entityMoveInfo := new(proto.EntityMoveInfo)
|
||||
//activeAvatarId := bigWorldOwner.TeamConfig.GetActiveAvatarId()
|
||||
//playerTeamEntity := bigWorldScene.GetPlayerTeamEntity(bigWorldOwner.PlayerID)
|
||||
//entityMoveInfo.EntityId = playerTeamEntity.avatarEntityMap[activeAvatarId]
|
||||
//entityMoveInfo.SceneTime = uint32(bigWorldScene.GetSceneTime())
|
||||
//entityMoveInfo.ReliableSeq = uint32(bigWorldScene.GetSceneTime() / 100 * 100)
|
||||
//entityMoveInfo.IsReliable = true
|
||||
//oldPos := model.Vector{
|
||||
// X: bigWorldOwner.Pos.X,
|
||||
// Y: bigWorldOwner.Pos.Y,
|
||||
// Z: bigWorldOwner.Pos.Z,
|
||||
//}
|
||||
//newPos := t.gameManager.worldManager.worldStatic.aiMoveVectorList[t.gameManager.worldManager.worldStatic.aiMoveCurrIndex]
|
||||
//rotY := math.Atan2(newPos.X-oldPos.X, newPos.Z-oldPos.Z) / math.Pi * 180.0
|
||||
//if rotY < 0.0 {
|
||||
// rotY += 360.0
|
||||
//}
|
||||
//entityMoveInfo.MotionInfo = &proto.MotionInfo{
|
||||
// Pos: &proto.Vector{
|
||||
// X: float32(newPos.X),
|
||||
// Y: float32(newPos.Y),
|
||||
// Z: float32(newPos.Z),
|
||||
// },
|
||||
// Rot: &proto.Vector{
|
||||
// X: 0.0,
|
||||
// Y: float32(rotY),
|
||||
// Z: 0.0,
|
||||
// },
|
||||
// Speed: &proto.Vector{
|
||||
// X: float32((newPos.X - oldPos.X) * 10.0),
|
||||
// Y: float32((newPos.Y - oldPos.Y) * 10.0),
|
||||
// Z: float32((newPos.Z - oldPos.Z) * 10.0),
|
||||
// },
|
||||
// State: proto.MotionState_MOTION_STATE_RUN,
|
||||
// RefPos: new(proto.Vector),
|
||||
//}
|
||||
//data, err := pb.Marshal(entityMoveInfo)
|
||||
//if err != nil {
|
||||
// logger.LOG.Error("build combat invocations entity move info error: %v", err)
|
||||
// return
|
||||
//}
|
||||
//combatInvocationsNotify := new(proto.CombatInvocationsNotify)
|
||||
//combatInvocationsNotify.InvokeList = []*proto.CombatInvokeEntry{{
|
||||
// CombatData: data,
|
||||
// ForwardType: proto.ForwardType_FORWARD_TYPE_TO_ALL_EXCEPT_CUR,
|
||||
// ArgumentType: proto.CombatTypeArgument_COMBAT_TYPE_ARGUMENT_ENTITY_MOVE,
|
||||
//}}
|
||||
//t.gameManager.CombatInvocationsNotify(bigWorldOwner.PlayerID, bigWorldOwner, 0, combatInvocationsNotify)
|
||||
}
|
||||
|
||||
func (t *TickManager) createMonster(scene *Scene) uint32 {
|
||||
pos := &model.Vector{
|
||||
X: 2747,
|
||||
Y: 194,
|
||||
Z: -1719,
|
||||
}
|
||||
fpm := map[uint32]float32{
|
||||
uint32(constant.FightPropertyConst.FIGHT_PROP_CUR_HP): float32(72.91699),
|
||||
uint32(constant.FightPropertyConst.FIGHT_PROP_PHYSICAL_SUB_HURT): float32(0.1),
|
||||
uint32(constant.FightPropertyConst.FIGHT_PROP_CUR_DEFENSE): float32(505.0),
|
||||
uint32(constant.FightPropertyConst.FIGHT_PROP_CUR_ATTACK): float32(45.679916),
|
||||
uint32(constant.FightPropertyConst.FIGHT_PROP_ICE_SUB_HURT): float32(0.1),
|
||||
uint32(constant.FightPropertyConst.FIGHT_PROP_BASE_ATTACK): float32(45.679916),
|
||||
uint32(constant.FightPropertyConst.FIGHT_PROP_MAX_HP): float32(72.91699),
|
||||
uint32(constant.FightPropertyConst.FIGHT_PROP_FIRE_SUB_HURT): float32(0.1),
|
||||
uint32(constant.FightPropertyConst.FIGHT_PROP_ELEC_SUB_HURT): float32(0.1),
|
||||
uint32(constant.FightPropertyConst.FIGHT_PROP_WIND_SUB_HURT): float32(0.1),
|
||||
uint32(constant.FightPropertyConst.FIGHT_PROP_ROCK_SUB_HURT): float32(0.1),
|
||||
uint32(constant.FightPropertyConst.FIGHT_PROP_GRASS_SUB_HURT): float32(0.1),
|
||||
uint32(constant.FightPropertyConst.FIGHT_PROP_WATER_SUB_HURT): float32(0.1),
|
||||
uint32(constant.FightPropertyConst.FIGHT_PROP_BASE_HP): float32(72.91699),
|
||||
uint32(constant.FightPropertyConst.FIGHT_PROP_BASE_DEFENSE): float32(505.0),
|
||||
}
|
||||
entityId := scene.CreateEntityMonster(pos, 1, fpm)
|
||||
return entityId
|
||||
}
|
||||
323
gs/game/user_avatar.go
Normal file
323
gs/game/user_avatar.go
Normal file
@@ -0,0 +1,323 @@
|
||||
package game
|
||||
|
||||
import (
|
||||
pb "google.golang.org/protobuf/proto"
|
||||
"hk4e/common/utils/object"
|
||||
gdc "hk4e/gs/config"
|
||||
"hk4e/gs/constant"
|
||||
"hk4e/gs/model"
|
||||
"hk4e/logger"
|
||||
"hk4e/protocol/cmd"
|
||||
"hk4e/protocol/proto"
|
||||
)
|
||||
|
||||
func (g *GameManager) GetAllAvatarDataConfig() map[int32]*gdc.AvatarData {
|
||||
allAvatarDataConfig := make(map[int32]*gdc.AvatarData)
|
||||
for avatarId, avatarData := range gdc.CONF.AvatarDataMap {
|
||||
if avatarId < 10000002 || avatarId >= 11000000 {
|
||||
// 跳过无效角色
|
||||
continue
|
||||
}
|
||||
if avatarId == 10000005 || avatarId == 10000007 {
|
||||
// 跳过主角
|
||||
continue
|
||||
}
|
||||
allAvatarDataConfig[avatarId] = avatarData
|
||||
}
|
||||
return allAvatarDataConfig
|
||||
}
|
||||
|
||||
func (g *GameManager) AddUserAvatar(userId uint32, avatarId uint32) {
|
||||
player := g.userManager.GetOnlineUser(userId)
|
||||
if player == nil {
|
||||
logger.LOG.Error("player is nil, uid: %v", userId)
|
||||
return
|
||||
}
|
||||
player.AddAvatar(avatarId)
|
||||
|
||||
// 添加初始武器
|
||||
avatarDataConfig := gdc.CONF.AvatarDataMap[int32(avatarId)]
|
||||
weaponId := g.AddUserWeapon(player.PlayerID, uint32(avatarDataConfig.InitialWeapon))
|
||||
|
||||
// 角色装上初始武器
|
||||
g.WearUserAvatarEquip(player.PlayerID, avatarId, weaponId)
|
||||
|
||||
// TODO 真的有必要存在吗
|
||||
g.UpdateUserAvatarFightProp(player.PlayerID, avatarId)
|
||||
|
||||
// PacketAvatarAddNotify
|
||||
avatar := player.AvatarMap[avatarId]
|
||||
avatarAddNotify := new(proto.AvatarAddNotify)
|
||||
avatarAddNotify.Avatar = g.PacketAvatarInfo(avatar)
|
||||
avatarAddNotify.IsInTeam = false
|
||||
g.SendMsg(cmd.AvatarAddNotify, userId, player.ClientSeq, avatarAddNotify)
|
||||
}
|
||||
|
||||
func (g *GameManager) WearEquipReq(player *model.Player, payloadMsg pb.Message) {
|
||||
logger.LOG.Debug("user wear equip, uid: %v", player.PlayerID)
|
||||
req := payloadMsg.(*proto.WearEquipReq)
|
||||
avatarGuid := req.AvatarGuid
|
||||
equipGuid := req.EquipGuid
|
||||
avatar := player.GameObjectGuidMap[avatarGuid].(*model.Avatar)
|
||||
weapon := player.GameObjectGuidMap[equipGuid].(*model.Weapon)
|
||||
g.WearUserAvatarEquip(player.PlayerID, avatar.AvatarId, weapon.WeaponId)
|
||||
|
||||
// PacketWearEquipRsp
|
||||
wearEquipRsp := new(proto.WearEquipRsp)
|
||||
wearEquipRsp.AvatarGuid = avatarGuid
|
||||
wearEquipRsp.EquipGuid = equipGuid
|
||||
g.SendMsg(cmd.WearEquipRsp, player.PlayerID, player.ClientSeq, wearEquipRsp)
|
||||
}
|
||||
|
||||
func (g *GameManager) WearUserAvatarEquip(userId uint32, avatarId uint32, weaponId uint64) {
|
||||
player := g.userManager.GetOnlineUser(userId)
|
||||
if player == nil {
|
||||
logger.LOG.Error("player is nil, uid: %v", userId)
|
||||
return
|
||||
}
|
||||
avatar := player.AvatarMap[avatarId]
|
||||
weapon := player.WeaponMap[weaponId]
|
||||
|
||||
world := g.worldManager.GetWorldByID(player.WorldId)
|
||||
scene := world.GetSceneById(player.SceneId)
|
||||
playerTeamEntity := scene.GetPlayerTeamEntity(player.PlayerID)
|
||||
team := player.TeamConfig.GetActiveTeam()
|
||||
|
||||
if weapon.AvatarId != 0 {
|
||||
// 武器在别的角色身上
|
||||
weakAvatarId := weapon.AvatarId
|
||||
weakWeaponId := weaponId
|
||||
strongAvatarId := avatarId
|
||||
strongWeaponId := avatar.EquipWeapon.WeaponId
|
||||
player.TakeOffWeapon(weakAvatarId, weakWeaponId)
|
||||
player.TakeOffWeapon(strongAvatarId, strongWeaponId)
|
||||
player.WearWeapon(weakAvatarId, strongWeaponId)
|
||||
player.WearWeapon(strongAvatarId, weakWeaponId)
|
||||
|
||||
weakAvatar := player.AvatarMap[weakAvatarId]
|
||||
weakWeapon := player.WeaponMap[weakAvatar.EquipWeapon.WeaponId]
|
||||
|
||||
for _, aid := range team.AvatarIdList {
|
||||
if aid == 0 {
|
||||
break
|
||||
}
|
||||
if aid == weakAvatar.AvatarId {
|
||||
playerTeamEntity.weaponEntityMap[weakWeapon.WeaponId] = scene.CreateEntityWeapon()
|
||||
}
|
||||
}
|
||||
|
||||
// PacketAvatarEquipChangeNotify
|
||||
avatarEquipChangeNotify := g.PacketAvatarEquipChangeNotify(weakAvatar, weakWeapon, playerTeamEntity.weaponEntityMap[weakWeapon.WeaponId])
|
||||
g.SendMsg(cmd.AvatarEquipChangeNotify, userId, player.ClientSeq, avatarEquipChangeNotify)
|
||||
} else if avatar.EquipWeapon != nil {
|
||||
// 角色当前有武器
|
||||
player.TakeOffWeapon(avatarId, avatar.EquipWeapon.WeaponId)
|
||||
player.WearWeapon(avatarId, weaponId)
|
||||
} else {
|
||||
// 是新角色还没有武器
|
||||
player.WearWeapon(avatarId, weaponId)
|
||||
}
|
||||
|
||||
for _, aid := range team.AvatarIdList {
|
||||
if aid == 0 {
|
||||
break
|
||||
}
|
||||
if aid == avatarId {
|
||||
playerTeamEntity.weaponEntityMap[weaponId] = scene.CreateEntityWeapon()
|
||||
}
|
||||
}
|
||||
|
||||
// PacketAvatarEquipChangeNotify
|
||||
avatarEquipChangeNotify := g.PacketAvatarEquipChangeNotify(avatar, weapon, playerTeamEntity.weaponEntityMap[weaponId])
|
||||
g.SendMsg(cmd.AvatarEquipChangeNotify, userId, player.ClientSeq, avatarEquipChangeNotify)
|
||||
}
|
||||
|
||||
func (g *GameManager) AvatarChangeCostumeReq(player *model.Player, payloadMsg pb.Message) {
|
||||
logger.LOG.Debug("user change avatar costume, uid: %v", player.PlayerID)
|
||||
req := payloadMsg.(*proto.AvatarChangeCostumeReq)
|
||||
avatarGuid := req.AvatarGuid
|
||||
costumeId := req.CostumeId
|
||||
|
||||
exist := false
|
||||
for _, v := range player.CostumeList {
|
||||
if v == costumeId {
|
||||
exist = true
|
||||
}
|
||||
}
|
||||
if costumeId == 0 {
|
||||
exist = true
|
||||
}
|
||||
if !exist {
|
||||
return
|
||||
}
|
||||
|
||||
avatar := player.GameObjectGuidMap[avatarGuid].(*model.Avatar)
|
||||
avatar.Costume = req.CostumeId
|
||||
|
||||
world := g.worldManager.GetWorldByID(player.WorldId)
|
||||
scene := world.GetSceneById(player.SceneId)
|
||||
|
||||
// PacketAvatarChangeCostumeNotify
|
||||
avatarChangeCostumeNotify := new(proto.AvatarChangeCostumeNotify)
|
||||
avatarChangeCostumeNotify.EntityInfo = g.PacketSceneEntityInfoAvatar(scene, player, avatar.AvatarId)
|
||||
for _, scenePlayer := range scene.playerMap {
|
||||
g.SendMsg(cmd.AvatarChangeCostumeNotify, scenePlayer.PlayerID, scenePlayer.ClientSeq, avatarChangeCostumeNotify)
|
||||
}
|
||||
|
||||
// PacketAvatarChangeCostumeRsp
|
||||
avatarChangeCostumeRsp := new(proto.AvatarChangeCostumeRsp)
|
||||
avatarChangeCostumeRsp.AvatarGuid = req.AvatarGuid
|
||||
avatarChangeCostumeRsp.CostumeId = req.CostumeId
|
||||
g.SendMsg(cmd.AvatarChangeCostumeRsp, player.PlayerID, player.ClientSeq, avatarChangeCostumeRsp)
|
||||
}
|
||||
|
||||
func (g *GameManager) AvatarWearFlycloakReq(player *model.Player, payloadMsg pb.Message) {
|
||||
logger.LOG.Debug("user change avatar fly cloak, uid: %v", player.PlayerID)
|
||||
req := payloadMsg.(*proto.AvatarWearFlycloakReq)
|
||||
avatarGuid := req.AvatarGuid
|
||||
flycloakId := req.FlycloakId
|
||||
|
||||
exist := false
|
||||
for _, v := range player.FlyCloakList {
|
||||
if v == flycloakId {
|
||||
exist = true
|
||||
}
|
||||
}
|
||||
if !exist {
|
||||
return
|
||||
}
|
||||
|
||||
avatar := player.GameObjectGuidMap[avatarGuid].(*model.Avatar)
|
||||
avatar.FlyCloak = req.FlycloakId
|
||||
|
||||
world := g.worldManager.GetWorldByID(player.WorldId)
|
||||
scene := world.GetSceneById(player.SceneId)
|
||||
|
||||
// PacketAvatarFlycloakChangeNotify
|
||||
avatarFlycloakChangeNotify := new(proto.AvatarFlycloakChangeNotify)
|
||||
avatarFlycloakChangeNotify.AvatarGuid = avatarGuid
|
||||
avatarFlycloakChangeNotify.FlycloakId = flycloakId
|
||||
for _, scenePlayer := range scene.playerMap {
|
||||
g.SendMsg(cmd.AvatarFlycloakChangeNotify, scenePlayer.PlayerID, scenePlayer.ClientSeq, avatarFlycloakChangeNotify)
|
||||
}
|
||||
|
||||
// PacketAvatarWearFlycloakRsp
|
||||
avatarWearFlycloakRsp := new(proto.AvatarWearFlycloakRsp)
|
||||
avatarWearFlycloakRsp.AvatarGuid = req.AvatarGuid
|
||||
avatarWearFlycloakRsp.FlycloakId = req.FlycloakId
|
||||
g.SendMsg(cmd.AvatarWearFlycloakRsp, player.PlayerID, player.ClientSeq, avatarWearFlycloakRsp)
|
||||
}
|
||||
|
||||
func (g *GameManager) PacketAvatarEquipChangeNotify(avatar *model.Avatar, weapon *model.Weapon, entityId uint32) *proto.AvatarEquipChangeNotify {
|
||||
itemDataConfig := gdc.CONF.ItemDataMap[int32(weapon.ItemId)]
|
||||
avatarEquipChangeNotify := new(proto.AvatarEquipChangeNotify)
|
||||
avatarEquipChangeNotify.AvatarGuid = avatar.Guid
|
||||
avatarEquipChangeNotify.EquipType = uint32(itemDataConfig.EquipEnumType)
|
||||
avatarEquipChangeNotify.ItemId = weapon.ItemId
|
||||
avatarEquipChangeNotify.EquipGuid = weapon.Guid
|
||||
avatarEquipChangeNotify.Weapon = &proto.SceneWeaponInfo{
|
||||
EntityId: entityId,
|
||||
GadgetId: uint32(gdc.CONF.ItemDataMap[int32(weapon.ItemId)].GadgetId),
|
||||
ItemId: weapon.ItemId,
|
||||
Guid: weapon.Guid,
|
||||
Level: uint32(weapon.Level),
|
||||
AbilityInfo: new(proto.AbilitySyncStateInfo),
|
||||
}
|
||||
return avatarEquipChangeNotify
|
||||
}
|
||||
|
||||
func (g *GameManager) PacketAvatarEquipTakeOffNotify(avatar *model.Avatar, weapon *model.Weapon) *proto.AvatarEquipChangeNotify {
|
||||
itemDataConfig := gdc.CONF.ItemDataMap[int32(weapon.ItemId)]
|
||||
avatarEquipChangeNotify := new(proto.AvatarEquipChangeNotify)
|
||||
avatarEquipChangeNotify.AvatarGuid = avatar.Guid
|
||||
avatarEquipChangeNotify.EquipType = uint32(itemDataConfig.EquipEnumType)
|
||||
return avatarEquipChangeNotify
|
||||
}
|
||||
|
||||
func (g *GameManager) UpdateUserAvatarFightProp(userId uint32, avatarId uint32) {
|
||||
player := g.userManager.GetOnlineUser(userId)
|
||||
if player == nil {
|
||||
logger.LOG.Error("player is nil, uid: %v", userId)
|
||||
return
|
||||
}
|
||||
avatarFightPropNotify := new(proto.AvatarFightPropNotify)
|
||||
avatar := player.AvatarMap[avatarId]
|
||||
avatarFightPropNotify.AvatarGuid = avatar.Guid
|
||||
avatarFightPropNotify.FightPropMap = avatar.FightPropMap
|
||||
g.SendMsg(cmd.AvatarFightPropNotify, userId, player.ClientSeq, avatarFightPropNotify)
|
||||
}
|
||||
|
||||
func (g *GameManager) PacketAvatarInfo(avatar *model.Avatar) *proto.AvatarInfo {
|
||||
isFocus := false
|
||||
//if avatar.AvatarId == 10000005 || avatar.AvatarId == 10000007 {
|
||||
// isFocus = true
|
||||
//}
|
||||
pbAvatar := &proto.AvatarInfo{
|
||||
IsFocus: isFocus,
|
||||
AvatarId: avatar.AvatarId,
|
||||
Guid: avatar.Guid,
|
||||
PropMap: map[uint32]*proto.PropValue{
|
||||
uint32(constant.PlayerPropertyConst.PROP_LEVEL): {
|
||||
Type: uint32(constant.PlayerPropertyConst.PROP_LEVEL),
|
||||
Val: int64(avatar.Level),
|
||||
Value: &proto.PropValue_Ival{Ival: int64(avatar.Level)},
|
||||
},
|
||||
uint32(constant.PlayerPropertyConst.PROP_EXP): {
|
||||
Type: uint32(constant.PlayerPropertyConst.PROP_EXP),
|
||||
Val: int64(avatar.Exp),
|
||||
Value: &proto.PropValue_Ival{Ival: int64(avatar.Exp)},
|
||||
},
|
||||
uint32(constant.PlayerPropertyConst.PROP_BREAK_LEVEL): {
|
||||
Type: uint32(constant.PlayerPropertyConst.PROP_BREAK_LEVEL),
|
||||
Val: int64(avatar.Promote),
|
||||
Value: &proto.PropValue_Ival{Ival: int64(avatar.Promote)},
|
||||
},
|
||||
uint32(constant.PlayerPropertyConst.PROP_SATIATION_VAL): {
|
||||
Type: uint32(constant.PlayerPropertyConst.PROP_SATIATION_VAL),
|
||||
Val: 0,
|
||||
Value: &proto.PropValue_Ival{Ival: 0},
|
||||
},
|
||||
uint32(constant.PlayerPropertyConst.PROP_SATIATION_PENALTY_TIME): {
|
||||
Type: uint32(constant.PlayerPropertyConst.PROP_SATIATION_PENALTY_TIME),
|
||||
Val: 0,
|
||||
Value: &proto.PropValue_Ival{Ival: 0},
|
||||
},
|
||||
},
|
||||
LifeState: 1,
|
||||
EquipGuidList: object.ConvMapToList(avatar.EquipGuidList),
|
||||
FightPropMap: nil,
|
||||
SkillDepotId: avatar.SkillDepotId,
|
||||
FetterInfo: &proto.AvatarFetterInfo{
|
||||
ExpLevel: uint32(avatar.FetterLevel),
|
||||
ExpNumber: avatar.FetterExp,
|
||||
// FetterList 不知道是啥 该角色在配置表里的所有FetterId
|
||||
// TODO 资料解锁条目
|
||||
FetterList: nil,
|
||||
RewardedFetterLevelList: []uint32{10},
|
||||
},
|
||||
SkillLevelMap: nil,
|
||||
AvatarType: 1,
|
||||
WearingFlycloakId: avatar.FlyCloak,
|
||||
CostumeId: avatar.Costume,
|
||||
BornTime: uint32(avatar.BornTime),
|
||||
}
|
||||
pbAvatar.FightPropMap = avatar.FightPropMap
|
||||
for _, v := range avatar.FetterList {
|
||||
pbAvatar.FetterInfo.FetterList = append(pbAvatar.FetterInfo.FetterList, &proto.FetterData{
|
||||
FetterId: v,
|
||||
FetterState: uint32(constant.FetterStateConst.FINISH),
|
||||
})
|
||||
}
|
||||
// 解锁全部资料
|
||||
for _, v := range gdc.CONF.AvatarFetterDataMap[int32(avatar.AvatarId)] {
|
||||
pbAvatar.FetterInfo.FetterList = append(pbAvatar.FetterInfo.FetterList, &proto.FetterData{
|
||||
FetterId: uint32(v),
|
||||
FetterState: uint32(constant.FetterStateConst.FINISH),
|
||||
})
|
||||
}
|
||||
pbAvatar.SkillLevelMap = make(map[uint32]uint32)
|
||||
for k, v := range avatar.SkillLevelMap {
|
||||
pbAvatar.SkillLevelMap[k] = v
|
||||
}
|
||||
return pbAvatar
|
||||
}
|
||||
255
gs/game/user_chat.go
Normal file
255
gs/game/user_chat.go
Normal file
@@ -0,0 +1,255 @@
|
||||
package game
|
||||
|
||||
import (
|
||||
pb "google.golang.org/protobuf/proto"
|
||||
"hk4e/gs/model"
|
||||
"hk4e/logger"
|
||||
"hk4e/protocol/cmd"
|
||||
"hk4e/protocol/proto"
|
||||
"time"
|
||||
)
|
||||
|
||||
func (g *GameManager) PullRecentChatReq(player *model.Player, payloadMsg pb.Message) {
|
||||
logger.LOG.Debug("user pull recent chat, uid: %v", player.PlayerID)
|
||||
req := payloadMsg.(*proto.PullRecentChatReq)
|
||||
// 经研究发现 原神现网环境 客户端仅拉取最新的5条未读聊天消息 所以人太多的话小姐姐不回你消息是有原因的
|
||||
// 因此 阿米你这样做真的合适吗 不过现在代码到了我手上我想怎么写就怎么写 我才不会重蹈覆辙
|
||||
_ = req.PullNum
|
||||
|
||||
retMsgList := make([]*proto.ChatInfo, 0)
|
||||
for _, msgList := range player.ChatMsgMap {
|
||||
for _, chatMsg := range msgList {
|
||||
// 反手就是一个遍历
|
||||
if chatMsg.IsRead {
|
||||
continue
|
||||
}
|
||||
retMsgList = append(retMsgList, g.ConvChatMsgToChatInfo(chatMsg))
|
||||
}
|
||||
}
|
||||
|
||||
world := g.worldManager.GetWorldByID(player.WorldId)
|
||||
if world.multiplayer {
|
||||
chatList := world.GetChatList()
|
||||
count := len(chatList)
|
||||
if count > 10 {
|
||||
count = 10
|
||||
}
|
||||
for i := len(chatList) - count; i < len(chatList); i++ {
|
||||
// PacketPlayerChatNotify
|
||||
playerChatNotify := new(proto.PlayerChatNotify)
|
||||
playerChatNotify.ChannelId = 0
|
||||
playerChatNotify.ChatInfo = chatList[i]
|
||||
g.SendMsg(cmd.PlayerChatNotify, player.PlayerID, 0, playerChatNotify)
|
||||
}
|
||||
}
|
||||
|
||||
// PacketPullRecentChatRsp
|
||||
pullRecentChatRsp := new(proto.PullRecentChatRsp)
|
||||
pullRecentChatRsp.ChatInfo = retMsgList
|
||||
g.SendMsg(cmd.PullRecentChatRsp, player.PlayerID, 0, pullRecentChatRsp)
|
||||
}
|
||||
|
||||
func (g *GameManager) PullPrivateChatReq(player *model.Player, payloadMsg pb.Message) {
|
||||
logger.LOG.Debug("user pull private chat, uid: %v", player.PlayerID)
|
||||
req := payloadMsg.(*proto.PullPrivateChatReq)
|
||||
targetUid := req.TargetUid
|
||||
pullNum := req.PullNum
|
||||
fromSequence := req.FromSequence
|
||||
|
||||
msgList, exist := player.ChatMsgMap[targetUid]
|
||||
if !exist {
|
||||
return
|
||||
}
|
||||
if pullNum+fromSequence > uint32(len(msgList)) {
|
||||
pullNum = uint32(len(msgList)) - fromSequence
|
||||
}
|
||||
recentMsgList := msgList[fromSequence : fromSequence+pullNum]
|
||||
retMsgList := make([]*proto.ChatInfo, 0)
|
||||
for _, chatMsg := range recentMsgList {
|
||||
retMsgList = append(retMsgList, g.ConvChatMsgToChatInfo(chatMsg))
|
||||
}
|
||||
|
||||
// PacketPullPrivateChatRsp
|
||||
pullPrivateChatRsp := new(proto.PullPrivateChatRsp)
|
||||
pullPrivateChatRsp.ChatInfo = retMsgList
|
||||
g.SendMsg(cmd.PullPrivateChatRsp, player.PlayerID, 0, pullPrivateChatRsp)
|
||||
}
|
||||
|
||||
func (g *GameManager) PrivateChatReq(player *model.Player, payloadMsg pb.Message) {
|
||||
logger.LOG.Debug("user send private chat, uid: %v", player.PlayerID)
|
||||
req := payloadMsg.(*proto.PrivateChatReq)
|
||||
targetUid := req.TargetUid
|
||||
content := req.Content
|
||||
|
||||
// TODO 同步阻塞待优化
|
||||
targetPlayer := g.userManager.LoadTempOfflineUserSync(targetUid)
|
||||
if targetPlayer == nil {
|
||||
return
|
||||
}
|
||||
chatInfo := &proto.ChatInfo{
|
||||
Time: uint32(time.Now().Unix()),
|
||||
Sequence: 101,
|
||||
ToUid: targetPlayer.PlayerID,
|
||||
Uid: player.PlayerID,
|
||||
IsRead: false,
|
||||
Content: nil,
|
||||
}
|
||||
switch content.(type) {
|
||||
case *proto.PrivateChatReq_Text:
|
||||
text := content.(*proto.PrivateChatReq_Text).Text
|
||||
if len(text) == 0 {
|
||||
return
|
||||
}
|
||||
chatInfo.Content = &proto.ChatInfo_Text{
|
||||
Text: text,
|
||||
}
|
||||
case *proto.PrivateChatReq_Icon:
|
||||
icon := content.(*proto.PrivateChatReq_Icon).Icon
|
||||
chatInfo.Content = &proto.ChatInfo_Icon{
|
||||
Icon: icon,
|
||||
}
|
||||
default:
|
||||
return
|
||||
}
|
||||
|
||||
// 消息加入自己的队列
|
||||
msgList, exist := player.ChatMsgMap[targetPlayer.PlayerID]
|
||||
if !exist {
|
||||
msgList = make([]*model.ChatMsg, 0)
|
||||
}
|
||||
msgList = append(msgList, g.ConvChatInfoToChatMsg(chatInfo))
|
||||
player.ChatMsgMap[targetPlayer.PlayerID] = msgList
|
||||
// 消息加入目标玩家的队列
|
||||
msgList, exist = targetPlayer.ChatMsgMap[player.PlayerID]
|
||||
if !exist {
|
||||
msgList = make([]*model.ChatMsg, 0)
|
||||
}
|
||||
msgList = append(msgList, g.ConvChatInfoToChatMsg(chatInfo))
|
||||
targetPlayer.ChatMsgMap[player.PlayerID] = msgList
|
||||
|
||||
if targetPlayer.Online {
|
||||
// PacketPrivateChatNotify
|
||||
privateChatNotify := new(proto.PrivateChatNotify)
|
||||
privateChatNotify.ChatInfo = chatInfo
|
||||
g.SendMsg(cmd.PrivateChatNotify, targetPlayer.PlayerID, 0, privateChatNotify)
|
||||
}
|
||||
|
||||
// PacketPrivateChatNotify
|
||||
privateChatNotify := new(proto.PrivateChatNotify)
|
||||
privateChatNotify.ChatInfo = chatInfo
|
||||
g.SendMsg(cmd.PrivateChatNotify, player.PlayerID, 0, privateChatNotify)
|
||||
|
||||
// PacketPrivateChatRsp
|
||||
privateChatRsp := new(proto.PrivateChatRsp)
|
||||
g.SendMsg(cmd.PrivateChatRsp, player.PlayerID, 0, privateChatRsp)
|
||||
}
|
||||
|
||||
func (g *GameManager) ReadPrivateChatReq(player *model.Player, payloadMsg pb.Message) {
|
||||
logger.LOG.Debug("user read private chat, uid: %v", player.PlayerID)
|
||||
req := payloadMsg.(*proto.ReadPrivateChatReq)
|
||||
targetUid := req.TargetUid
|
||||
|
||||
msgList, exist := player.ChatMsgMap[targetUid]
|
||||
if !exist {
|
||||
return
|
||||
}
|
||||
for index, chatMsg := range msgList {
|
||||
chatMsg.IsRead = true
|
||||
msgList[index] = chatMsg
|
||||
}
|
||||
player.ChatMsgMap[targetUid] = msgList
|
||||
|
||||
// PacketReadPrivateChatRsp
|
||||
readPrivateChatRsp := new(proto.ReadPrivateChatRsp)
|
||||
g.SendMsg(cmd.ReadPrivateChatRsp, player.PlayerID, 0, readPrivateChatRsp)
|
||||
}
|
||||
|
||||
func (g *GameManager) PlayerChatReq(player *model.Player, payloadMsg pb.Message) {
|
||||
logger.LOG.Debug("user multiplayer chat, uid: %v", player.PlayerID)
|
||||
req := payloadMsg.(*proto.PlayerChatReq)
|
||||
channelId := req.ChannelId
|
||||
chatInfo := req.ChatInfo
|
||||
|
||||
sendChatInfo := &proto.ChatInfo{
|
||||
Time: uint32(time.Now().Unix()),
|
||||
Uid: player.PlayerID,
|
||||
Content: nil,
|
||||
}
|
||||
switch chatInfo.Content.(type) {
|
||||
case *proto.ChatInfo_Text:
|
||||
text := chatInfo.Content.(*proto.ChatInfo_Text).Text
|
||||
if len(text) == 0 {
|
||||
return
|
||||
}
|
||||
sendChatInfo.Content = &proto.ChatInfo_Text{
|
||||
Text: text,
|
||||
}
|
||||
case *proto.ChatInfo_Icon:
|
||||
icon := chatInfo.Content.(*proto.ChatInfo_Icon).Icon
|
||||
sendChatInfo.Content = &proto.ChatInfo_Icon{
|
||||
Icon: icon,
|
||||
}
|
||||
default:
|
||||
return
|
||||
}
|
||||
|
||||
world := g.worldManager.GetWorldByID(player.WorldId)
|
||||
world.AddChat(sendChatInfo)
|
||||
|
||||
// PacketPlayerChatNotify
|
||||
playerChatNotify := new(proto.PlayerChatNotify)
|
||||
playerChatNotify.ChannelId = channelId
|
||||
playerChatNotify.ChatInfo = sendChatInfo
|
||||
for _, worldPlayer := range world.playerMap {
|
||||
g.SendMsg(cmd.PlayerChatNotify, worldPlayer.PlayerID, 0, playerChatNotify)
|
||||
}
|
||||
|
||||
// PacketPlayerChatRsp
|
||||
playerChatRsp := new(proto.PlayerChatRsp)
|
||||
g.SendMsg(cmd.PlayerChatRsp, player.PlayerID, 0, playerChatRsp)
|
||||
}
|
||||
|
||||
func (g *GameManager) ConvChatInfoToChatMsg(chatInfo *proto.ChatInfo) (chatMsg *model.ChatMsg) {
|
||||
chatMsg = &model.ChatMsg{
|
||||
Time: chatInfo.Time,
|
||||
ToUid: chatInfo.ToUid,
|
||||
Uid: chatInfo.Uid,
|
||||
IsRead: chatInfo.IsRead,
|
||||
MsgType: 0,
|
||||
Text: "",
|
||||
Icon: 0,
|
||||
}
|
||||
switch chatInfo.Content.(type) {
|
||||
case *proto.ChatInfo_Text:
|
||||
chatMsg.MsgType = model.ChatMsgTypeText
|
||||
chatMsg.Text = chatInfo.Content.(*proto.ChatInfo_Text).Text
|
||||
case *proto.ChatInfo_Icon:
|
||||
chatMsg.MsgType = model.ChatMsgTypeIcon
|
||||
chatMsg.Icon = chatInfo.Content.(*proto.ChatInfo_Icon).Icon
|
||||
default:
|
||||
}
|
||||
return chatMsg
|
||||
}
|
||||
|
||||
func (g *GameManager) ConvChatMsgToChatInfo(chatMsg *model.ChatMsg) (chatInfo *proto.ChatInfo) {
|
||||
chatInfo = &proto.ChatInfo{
|
||||
Time: chatMsg.Time,
|
||||
Sequence: 0,
|
||||
ToUid: chatMsg.ToUid,
|
||||
Uid: chatMsg.Uid,
|
||||
IsRead: chatMsg.IsRead,
|
||||
Content: nil,
|
||||
}
|
||||
switch chatMsg.MsgType {
|
||||
case model.ChatMsgTypeText:
|
||||
chatInfo.Content = &proto.ChatInfo_Text{
|
||||
Text: chatMsg.Text,
|
||||
}
|
||||
case model.ChatMsgTypeIcon:
|
||||
chatInfo.Content = &proto.ChatInfo_Icon{
|
||||
Icon: chatMsg.Icon,
|
||||
}
|
||||
default:
|
||||
}
|
||||
return chatInfo
|
||||
}
|
||||
403
gs/game/user_combat.go
Normal file
403
gs/game/user_combat.go
Normal file
@@ -0,0 +1,403 @@
|
||||
package game
|
||||
|
||||
import (
|
||||
pb "google.golang.org/protobuf/proto"
|
||||
"hk4e/gs/model"
|
||||
"hk4e/logger"
|
||||
"hk4e/protocol/cmd"
|
||||
"hk4e/protocol/proto"
|
||||
)
|
||||
|
||||
func (g *GameManager) CombatInvocationsNotify(player *model.Player, payloadMsg pb.Message) {
|
||||
//logger.LOG.Debug("user combat invocations, uid: %v", player.PlayerID)
|
||||
req := payloadMsg.(*proto.CombatInvocationsNotify)
|
||||
world := g.worldManager.GetWorldByID(player.WorldId)
|
||||
if world == nil {
|
||||
return
|
||||
}
|
||||
scene := world.GetSceneById(player.SceneId)
|
||||
invokeHandler := NewInvokeHandler[proto.CombatInvokeEntry]()
|
||||
for _, entry := range req.InvokeList {
|
||||
//logger.LOG.Debug("AT: %v, FT: %v, UID: %v", entry.ArgumentType, entry.ForwardType, player.PlayerID)
|
||||
switch entry.ArgumentType {
|
||||
case proto.CombatTypeArgument_COMBAT_TYPE_ARGUMENT_EVT_BEING_HIT:
|
||||
scene.AddAttack(&Attack{
|
||||
combatInvokeEntry: entry,
|
||||
uid: player.PlayerID,
|
||||
})
|
||||
case proto.CombatTypeArgument_COMBAT_TYPE_ARGUMENT_ENTITY_MOVE:
|
||||
entityMoveInfo := new(proto.EntityMoveInfo)
|
||||
err := pb.Unmarshal(entry.CombatData, entityMoveInfo)
|
||||
if err != nil {
|
||||
logger.LOG.Error("parse combat invocations entity move info error: %v", err)
|
||||
continue
|
||||
}
|
||||
motionInfo := entityMoveInfo.MotionInfo
|
||||
if motionInfo.Pos == nil || motionInfo.Rot == nil {
|
||||
continue
|
||||
}
|
||||
activeAvatarId := player.TeamConfig.GetActiveAvatarId()
|
||||
playerTeamEntity := scene.GetPlayerTeamEntity(player.PlayerID)
|
||||
playerActiveAvatarEntityId := playerTeamEntity.avatarEntityMap[activeAvatarId]
|
||||
if entityMoveInfo.EntityId == playerActiveAvatarEntityId {
|
||||
// 玩家在移动
|
||||
ok := world.aoiManager.IsValidAoiPos(motionInfo.Pos.X, motionInfo.Pos.Y, motionInfo.Pos.Z)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
// aoi
|
||||
oldGid := world.aoiManager.GetGidByPos(float32(player.Pos.X), float32(player.Pos.Y), float32(player.Pos.Z))
|
||||
newGid := world.aoiManager.GetGidByPos(motionInfo.Pos.X, motionInfo.Pos.Y, motionInfo.Pos.Z)
|
||||
if oldGid != newGid {
|
||||
// 跨越了格子
|
||||
oldGridList := world.aoiManager.GetSurrGridListByGid(oldGid)
|
||||
oldEntityIdMap := make(map[uint32]bool)
|
||||
for _, grid := range oldGridList {
|
||||
tmp := grid.GetEntityIdList()
|
||||
for _, v := range tmp {
|
||||
oldEntityIdMap[v] = true
|
||||
}
|
||||
}
|
||||
newGridList := world.aoiManager.GetSurrGridListByGid(newGid)
|
||||
newEntityIdMap := make(map[uint32]bool)
|
||||
for _, grid := range newGridList {
|
||||
tmp := grid.GetEntityIdList()
|
||||
for _, v := range tmp {
|
||||
newEntityIdMap[v] = true
|
||||
}
|
||||
}
|
||||
delEntityIdList := make([]uint32, 0)
|
||||
delUidList := make([]uint32, 0)
|
||||
for oldEntityId := range oldEntityIdMap {
|
||||
_, exist := newEntityIdMap[oldEntityId]
|
||||
if exist {
|
||||
continue
|
||||
}
|
||||
delEntityIdList = append(delEntityIdList, oldEntityId)
|
||||
entity := scene.GetEntity(oldEntityId)
|
||||
if entity == nil {
|
||||
continue
|
||||
}
|
||||
if entity.avatarEntity != nil {
|
||||
delUidList = append(delUidList, entity.avatarEntity.uid)
|
||||
}
|
||||
}
|
||||
addEntityIdList := make([]uint32, 0)
|
||||
addUidList := make([]uint32, 0)
|
||||
for newEntityId := range newEntityIdMap {
|
||||
_, exist := oldEntityIdMap[newEntityId]
|
||||
if exist {
|
||||
continue
|
||||
}
|
||||
addEntityIdList = append(addEntityIdList, newEntityId)
|
||||
entity := scene.GetEntity(newEntityId)
|
||||
if entity == nil {
|
||||
continue
|
||||
}
|
||||
if entity.avatarEntity != nil {
|
||||
addUidList = append(addUidList, entity.avatarEntity.uid)
|
||||
}
|
||||
}
|
||||
// 发送已消失格子里的实体消失通知
|
||||
g.RemoveSceneEntityNotifyToPlayer(player, delEntityIdList)
|
||||
// 发送新出现格子里的实体出现通知
|
||||
g.AddSceneEntityNotify(player, proto.VisionType_VISION_TYPE_BORN, addEntityIdList, false)
|
||||
// 更新玩家的位置信息
|
||||
player.Pos.X = float64(motionInfo.Pos.X)
|
||||
player.Pos.Y = float64(motionInfo.Pos.Y)
|
||||
player.Pos.Z = float64(motionInfo.Pos.Z)
|
||||
// 更新玩家所在格子
|
||||
world.aoiManager.RemoveEntityIdFromGrid(playerActiveAvatarEntityId, oldGid)
|
||||
world.aoiManager.AddEntityIdToGrid(playerActiveAvatarEntityId, newGid)
|
||||
// 其他玩家
|
||||
for _, uid := range delUidList {
|
||||
otherPlayer := g.userManager.GetOnlineUser(uid)
|
||||
g.RemoveSceneEntityNotifyToPlayer(otherPlayer, []uint32{playerActiveAvatarEntityId})
|
||||
}
|
||||
for _, uid := range addUidList {
|
||||
otherPlayer := g.userManager.GetOnlineUser(uid)
|
||||
g.AddSceneEntityNotify(otherPlayer, proto.VisionType_VISION_TYPE_BORN, []uint32{playerActiveAvatarEntityId}, false)
|
||||
}
|
||||
}
|
||||
// 把队伍中的其他非活跃角色也同步进行移动
|
||||
team := player.TeamConfig.GetActiveTeam()
|
||||
for _, avatarId := range team.AvatarIdList {
|
||||
// 跳过当前的活跃角色
|
||||
if avatarId == activeAvatarId {
|
||||
continue
|
||||
}
|
||||
entityId := playerTeamEntity.avatarEntityMap[avatarId]
|
||||
entity := scene.GetEntity(entityId)
|
||||
if entity == nil {
|
||||
continue
|
||||
}
|
||||
entity.pos.X = float64(motionInfo.Pos.X)
|
||||
entity.pos.Y = float64(motionInfo.Pos.Y)
|
||||
entity.pos.Z = float64(motionInfo.Pos.Z)
|
||||
entity.rot.X = float64(motionInfo.Rot.X)
|
||||
entity.rot.Y = float64(motionInfo.Rot.Y)
|
||||
entity.rot.Z = float64(motionInfo.Rot.Z)
|
||||
}
|
||||
// 更新玩家的位置信息
|
||||
player.Pos.X = float64(motionInfo.Pos.X)
|
||||
player.Pos.Y = float64(motionInfo.Pos.Y)
|
||||
player.Pos.Z = float64(motionInfo.Pos.Z)
|
||||
player.Rot.X = float64(motionInfo.Rot.X)
|
||||
player.Rot.Y = float64(motionInfo.Rot.Y)
|
||||
player.Rot.Z = float64(motionInfo.Rot.Z)
|
||||
// TODO 采集大地图地形数据
|
||||
if world.IsBigWorld() && scene.id == 3 && player.PlayerID != 1 {
|
||||
if motionInfo.State == proto.MotionState_MOTION_STATE_WALK ||
|
||||
motionInfo.State == proto.MotionState_MOTION_STATE_RUN ||
|
||||
motionInfo.State == proto.MotionState_MOTION_STATE_DASH ||
|
||||
motionInfo.State == proto.MotionState_MOTION_STATE_CLIMB {
|
||||
logger.LOG.Debug("set terr motionInfo: %v", motionInfo)
|
||||
exist := g.worldManager.worldStatic.GetTerrain(int16(motionInfo.Pos.X), int16(motionInfo.Pos.Y), int16(motionInfo.Pos.Z))
|
||||
g.worldManager.worldStatic.SetTerrain(int16(motionInfo.Pos.X), int16(motionInfo.Pos.Y), int16(motionInfo.Pos.Z))
|
||||
if !exist {
|
||||
// TODO 薄荷标记
|
||||
// 只给附近aoi区域的玩家广播消息
|
||||
surrPlayerList := make([]*model.Player, 0)
|
||||
entityIdList := world.aoiManager.GetEntityIdListByPos(float32(player.Pos.X), float32(player.Pos.Y), float32(player.Pos.Z))
|
||||
for _, entityId := range entityIdList {
|
||||
entity := scene.GetEntity(entityId)
|
||||
if entity == nil {
|
||||
continue
|
||||
}
|
||||
if entity.avatarEntity != nil {
|
||||
otherPlayer := g.userManager.GetOnlineUser(entity.avatarEntity.uid)
|
||||
surrPlayerList = append(surrPlayerList, otherPlayer)
|
||||
}
|
||||
}
|
||||
pos := &model.Vector{
|
||||
X: float64(int16(motionInfo.Pos.X)),
|
||||
Y: float64(int16(motionInfo.Pos.Y)),
|
||||
Z: float64(int16(motionInfo.Pos.Z)),
|
||||
}
|
||||
gadgetEntityId := scene.CreateEntityGadget(pos, 3003009)
|
||||
for _, otherPlayer := range surrPlayerList {
|
||||
g.AddSceneEntityNotify(otherPlayer, proto.VisionType_VISION_TYPE_BORN, []uint32{gadgetEntityId}, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 更新场景实体的位置信息
|
||||
sceneEntity := scene.GetEntity(entityMoveInfo.EntityId)
|
||||
if sceneEntity != nil {
|
||||
sceneEntity.pos = &model.Vector{
|
||||
X: float64(motionInfo.Pos.X),
|
||||
Y: float64(motionInfo.Pos.Y),
|
||||
Z: float64(motionInfo.Pos.Z),
|
||||
}
|
||||
sceneEntity.rot = &model.Vector{
|
||||
X: float64(motionInfo.Rot.X),
|
||||
Y: float64(motionInfo.Rot.Y),
|
||||
Z: float64(motionInfo.Rot.Z),
|
||||
}
|
||||
sceneEntity.moveState = uint16(motionInfo.State)
|
||||
sceneEntity.lastMoveSceneTimeMs = entityMoveInfo.SceneTime
|
||||
sceneEntity.lastMoveReliableSeq = entityMoveInfo.ReliableSeq
|
||||
//logger.LOG.Debug("entity move, id: %v, pos: %v, uid: %v", sceneEntity.id, sceneEntity.pos, player.PlayerID)
|
||||
}
|
||||
invokeHandler.addEntry(entry.ForwardType, entry)
|
||||
default:
|
||||
invokeHandler.addEntry(entry.ForwardType, entry)
|
||||
}
|
||||
}
|
||||
|
||||
// 只给附近aoi区域的玩家广播消息
|
||||
surrPlayerList := make([]*model.Player, 0)
|
||||
entityIdList := world.aoiManager.GetEntityIdListByPos(float32(player.Pos.X), float32(player.Pos.Y), float32(player.Pos.Z))
|
||||
for _, entityId := range entityIdList {
|
||||
entity := scene.GetEntity(entityId)
|
||||
if entity == nil {
|
||||
continue
|
||||
}
|
||||
if entity.avatarEntity != nil {
|
||||
otherPlayer := g.userManager.GetOnlineUser(entity.avatarEntity.uid)
|
||||
surrPlayerList = append(surrPlayerList, otherPlayer)
|
||||
}
|
||||
}
|
||||
|
||||
// PacketCombatInvocationsNotify
|
||||
if invokeHandler.AllLen() > 0 {
|
||||
combatInvocationsNotify := new(proto.CombatInvocationsNotify)
|
||||
combatInvocationsNotify.InvokeList = invokeHandler.entryListForwardAll
|
||||
for _, v := range surrPlayerList {
|
||||
g.SendMsg(cmd.CombatInvocationsNotify, v.PlayerID, v.ClientSeq, combatInvocationsNotify)
|
||||
}
|
||||
}
|
||||
if invokeHandler.AllExceptCurLen() > 0 {
|
||||
combatInvocationsNotify := new(proto.CombatInvocationsNotify)
|
||||
combatInvocationsNotify.InvokeList = invokeHandler.entryListForwardAllExceptCur
|
||||
for _, v := range surrPlayerList {
|
||||
if player.PlayerID == v.PlayerID {
|
||||
continue
|
||||
}
|
||||
g.SendMsg(cmd.CombatInvocationsNotify, v.PlayerID, v.ClientSeq, combatInvocationsNotify)
|
||||
}
|
||||
}
|
||||
if invokeHandler.HostLen() > 0 {
|
||||
combatInvocationsNotify := new(proto.CombatInvocationsNotify)
|
||||
combatInvocationsNotify.InvokeList = invokeHandler.entryListForwardHost
|
||||
g.SendMsg(cmd.CombatInvocationsNotify, world.owner.PlayerID, world.owner.ClientSeq, combatInvocationsNotify)
|
||||
}
|
||||
}
|
||||
|
||||
func (g *GameManager) AbilityInvocationsNotify(player *model.Player, payloadMsg pb.Message) {
|
||||
//logger.LOG.Debug("user ability invocations, uid: %v", player.PlayerID)
|
||||
req := payloadMsg.(*proto.AbilityInvocationsNotify)
|
||||
world := g.worldManager.GetWorldByID(player.WorldId)
|
||||
if world == nil {
|
||||
return
|
||||
}
|
||||
scene := world.GetSceneById(player.SceneId)
|
||||
invokeHandler := NewInvokeHandler[proto.AbilityInvokeEntry]()
|
||||
for _, entry := range req.Invokes {
|
||||
//logger.LOG.Debug("AT: %v, FT: %v, UID: %v", entry.ArgumentType, entry.ForwardType, player.PlayerID)
|
||||
invokeHandler.addEntry(entry.ForwardType, entry)
|
||||
}
|
||||
|
||||
// 只给附近aoi区域的玩家广播消息
|
||||
surrPlayerList := make([]*model.Player, 0)
|
||||
entityIdList := world.aoiManager.GetEntityIdListByPos(float32(player.Pos.X), float32(player.Pos.Y), float32(player.Pos.Z))
|
||||
for _, entityId := range entityIdList {
|
||||
entity := scene.GetEntity(entityId)
|
||||
if entity == nil {
|
||||
continue
|
||||
}
|
||||
if entity.avatarEntity != nil {
|
||||
otherPlayer := g.userManager.GetOnlineUser(entity.avatarEntity.uid)
|
||||
surrPlayerList = append(surrPlayerList, otherPlayer)
|
||||
}
|
||||
}
|
||||
|
||||
// PacketAbilityInvocationsNotify
|
||||
if invokeHandler.AllLen() > 0 {
|
||||
abilityInvocationsNotify := new(proto.AbilityInvocationsNotify)
|
||||
abilityInvocationsNotify.Invokes = invokeHandler.entryListForwardAll
|
||||
for _, v := range surrPlayerList {
|
||||
g.SendMsg(cmd.AbilityInvocationsNotify, v.PlayerID, v.ClientSeq, abilityInvocationsNotify)
|
||||
}
|
||||
}
|
||||
if invokeHandler.AllExceptCurLen() > 0 {
|
||||
abilityInvocationsNotify := new(proto.AbilityInvocationsNotify)
|
||||
abilityInvocationsNotify.Invokes = invokeHandler.entryListForwardAllExceptCur
|
||||
for _, v := range surrPlayerList {
|
||||
if player.PlayerID == v.PlayerID {
|
||||
continue
|
||||
}
|
||||
g.SendMsg(cmd.AbilityInvocationsNotify, v.PlayerID, v.ClientSeq, abilityInvocationsNotify)
|
||||
}
|
||||
}
|
||||
if invokeHandler.HostLen() > 0 {
|
||||
abilityInvocationsNotify := new(proto.AbilityInvocationsNotify)
|
||||
abilityInvocationsNotify.Invokes = invokeHandler.entryListForwardHost
|
||||
g.SendMsg(cmd.AbilityInvocationsNotify, world.owner.PlayerID, world.owner.ClientSeq, abilityInvocationsNotify)
|
||||
}
|
||||
}
|
||||
|
||||
func (g *GameManager) ClientAbilityInitFinishNotify(player *model.Player, payloadMsg pb.Message) {
|
||||
//logger.LOG.Debug("user client ability ok, uid: %v", player.PlayerID)
|
||||
req := payloadMsg.(*proto.ClientAbilityInitFinishNotify)
|
||||
world := g.worldManager.GetWorldByID(player.WorldId)
|
||||
if world == nil {
|
||||
return
|
||||
}
|
||||
scene := world.GetSceneById(player.SceneId)
|
||||
invokeHandler := NewInvokeHandler[proto.AbilityInvokeEntry]()
|
||||
for _, entry := range req.Invokes {
|
||||
//logger.LOG.Debug("AT: %v, FT: %v, UID: %v", entry.ArgumentType, entry.ForwardType, player.PlayerID)
|
||||
invokeHandler.addEntry(entry.ForwardType, entry)
|
||||
}
|
||||
|
||||
// 只给附近aoi区域的玩家广播消息
|
||||
surrPlayerList := make([]*model.Player, 0)
|
||||
entityIdList := world.aoiManager.GetEntityIdListByPos(float32(player.Pos.X), float32(player.Pos.Y), float32(player.Pos.Z))
|
||||
for _, entityId := range entityIdList {
|
||||
entity := scene.GetEntity(entityId)
|
||||
if entity == nil {
|
||||
continue
|
||||
}
|
||||
if entity.avatarEntity != nil {
|
||||
otherPlayer := g.userManager.GetOnlineUser(entity.avatarEntity.uid)
|
||||
surrPlayerList = append(surrPlayerList, otherPlayer)
|
||||
}
|
||||
}
|
||||
|
||||
// PacketClientAbilityInitFinishNotify
|
||||
if invokeHandler.AllLen() > 0 {
|
||||
clientAbilityInitFinishNotify := new(proto.ClientAbilityInitFinishNotify)
|
||||
clientAbilityInitFinishNotify.Invokes = invokeHandler.entryListForwardAll
|
||||
for _, v := range surrPlayerList {
|
||||
g.SendMsg(cmd.ClientAbilityInitFinishNotify, v.PlayerID, v.ClientSeq, clientAbilityInitFinishNotify)
|
||||
}
|
||||
}
|
||||
if invokeHandler.AllExceptCurLen() > 0 {
|
||||
clientAbilityInitFinishNotify := new(proto.ClientAbilityInitFinishNotify)
|
||||
clientAbilityInitFinishNotify.Invokes = invokeHandler.entryListForwardAllExceptCur
|
||||
for _, v := range surrPlayerList {
|
||||
if player.PlayerID == v.PlayerID {
|
||||
continue
|
||||
}
|
||||
g.SendMsg(cmd.ClientAbilityInitFinishNotify, v.PlayerID, v.ClientSeq, clientAbilityInitFinishNotify)
|
||||
}
|
||||
}
|
||||
if invokeHandler.HostLen() > 0 {
|
||||
clientAbilityInitFinishNotify := new(proto.ClientAbilityInitFinishNotify)
|
||||
clientAbilityInitFinishNotify.Invokes = invokeHandler.entryListForwardHost
|
||||
g.SendMsg(cmd.ClientAbilityInitFinishNotify, world.owner.PlayerID, world.owner.ClientSeq, clientAbilityInitFinishNotify)
|
||||
}
|
||||
}
|
||||
|
||||
type InvokeType interface {
|
||||
proto.AbilityInvokeEntry | proto.CombatInvokeEntry
|
||||
}
|
||||
|
||||
type InvokeHandler[T InvokeType] struct {
|
||||
entryListForwardAll []*T
|
||||
entryListForwardAllExceptCur []*T
|
||||
entryListForwardHost []*T
|
||||
}
|
||||
|
||||
func NewInvokeHandler[T InvokeType]() (r *InvokeHandler[T]) {
|
||||
r = new(InvokeHandler[T])
|
||||
r.InitInvokeHandler()
|
||||
return r
|
||||
}
|
||||
|
||||
func (i *InvokeHandler[T]) InitInvokeHandler() {
|
||||
i.entryListForwardAll = make([]*T, 0)
|
||||
i.entryListForwardAllExceptCur = make([]*T, 0)
|
||||
i.entryListForwardHost = make([]*T, 0)
|
||||
}
|
||||
|
||||
func (i *InvokeHandler[T]) addEntry(forward proto.ForwardType, entry *T) {
|
||||
switch forward {
|
||||
case proto.ForwardType_FORWARD_TYPE_TO_ALL:
|
||||
i.entryListForwardAll = append(i.entryListForwardAll, entry)
|
||||
case proto.ForwardType_FORWARD_TYPE_TO_ALL_EXCEPT_CUR:
|
||||
fallthrough
|
||||
case proto.ForwardType_FORWARD_TYPE_TO_ALL_EXIST_EXCEPT_CUR:
|
||||
i.entryListForwardAllExceptCur = append(i.entryListForwardAllExceptCur, entry)
|
||||
case proto.ForwardType_FORWARD_TYPE_TO_HOST:
|
||||
i.entryListForwardHost = append(i.entryListForwardHost, entry)
|
||||
default:
|
||||
if forward != proto.ForwardType_FORWARD_TYPE_ONLY_SERVER {
|
||||
logger.LOG.Error("forward: %v, entry: %v", forward, entry)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (i *InvokeHandler[T]) AllLen() int {
|
||||
return len(i.entryListForwardAll)
|
||||
}
|
||||
|
||||
func (i *InvokeHandler[T]) AllExceptCurLen() int {
|
||||
return len(i.entryListForwardAllExceptCur)
|
||||
}
|
||||
|
||||
func (i *InvokeHandler[T]) HostLen() int {
|
||||
return len(i.entryListForwardHost)
|
||||
}
|
||||
611
gs/game/user_gacha.go
Normal file
611
gs/game/user_gacha.go
Normal file
@@ -0,0 +1,611 @@
|
||||
package game
|
||||
|
||||
import (
|
||||
"github.com/golang-jwt/jwt/v4"
|
||||
pb "google.golang.org/protobuf/proto"
|
||||
"hk4e/common/config"
|
||||
"hk4e/common/utils/random"
|
||||
gdc "hk4e/gs/config"
|
||||
"hk4e/gs/model"
|
||||
"hk4e/logger"
|
||||
"hk4e/protocol/cmd"
|
||||
"hk4e/protocol/proto"
|
||||
"time"
|
||||
)
|
||||
|
||||
type UserInfo struct {
|
||||
UserId uint32 `json:"userId"`
|
||||
jwt.RegisteredClaims
|
||||
}
|
||||
|
||||
// 获取卡池信息
|
||||
func (g *GameManager) GetGachaInfoReq(player *model.Player, payloadMsg pb.Message) {
|
||||
logger.LOG.Debug("user get gacha info, uid: %v", player.PlayerID)
|
||||
serverAddr := config.CONF.Hk4e.GachaHistoryServer
|
||||
getGachaInfoRsp := new(proto.GetGachaInfoRsp)
|
||||
getGachaInfoRsp.GachaRandom = 12345
|
||||
userInfo := &UserInfo{
|
||||
UserId: player.PlayerID,
|
||||
RegisteredClaims: jwt.RegisteredClaims{
|
||||
ExpiresAt: jwt.NewNumericDate(time.Now().Add(24 * time.Hour * time.Duration(1))),
|
||||
IssuedAt: jwt.NewNumericDate(time.Now()),
|
||||
NotBefore: jwt.NewNumericDate(time.Now()),
|
||||
},
|
||||
}
|
||||
token := jwt.NewWithClaims(jwt.SigningMethodHS512, userInfo)
|
||||
jwtStr, err := token.SignedString([]byte("flswld"))
|
||||
if err != nil {
|
||||
logger.LOG.Error("generate jwt error: %v", err)
|
||||
jwtStr = "default.jwt.token"
|
||||
}
|
||||
getGachaInfoRsp.GachaInfoList = []*proto.GachaInfo{
|
||||
// 温迪
|
||||
{
|
||||
GachaType: 300,
|
||||
ScheduleId: 823,
|
||||
BeginTime: 0,
|
||||
EndTime: 2051193600,
|
||||
GachaSortId: 9998,
|
||||
GachaPrefabPath: "GachaShowPanel_A019",
|
||||
GachaPreviewPrefabPath: "UI_Tab_GachaShowPanel_A019",
|
||||
TitleTextmap: "UI_GACHA_SHOW_PANEL_A019_TITLE",
|
||||
LeftGachaTimes: 2147483647,
|
||||
GachaTimesLimit: 2147483647,
|
||||
CostItemId: 223,
|
||||
CostItemNum: 1,
|
||||
TenCostItemId: 223,
|
||||
TenCostItemNum: 10,
|
||||
GachaRecordUrl: serverAddr + "/gm/gacha?gachaType=300&jwt=" + jwtStr,
|
||||
GachaRecordUrlOversea: serverAddr + "/gm/gacha?gachaType=300&jwt=" + jwtStr,
|
||||
GachaProbUrl: serverAddr + "/gm/gacha/details?scheduleId=823&jwt=" + jwtStr,
|
||||
GachaProbUrlOversea: serverAddr + "/gm/gacha/details?scheduleId=823&jwt=" + jwtStr,
|
||||
GachaUpInfoList: []*proto.GachaUpInfo{
|
||||
{
|
||||
ItemParentType: 1,
|
||||
ItemIdList: []uint32{1022},
|
||||
},
|
||||
{
|
||||
ItemParentType: 2,
|
||||
ItemIdList: []uint32{1023, 1031, 1014},
|
||||
},
|
||||
},
|
||||
DisplayUp4ItemList: []uint32{1023},
|
||||
DisplayUp5ItemList: []uint32{1022},
|
||||
WishItemId: 0,
|
||||
WishProgress: 0,
|
||||
WishMaxProgress: 0,
|
||||
IsNewWish: false,
|
||||
},
|
||||
// 可莉
|
||||
{
|
||||
GachaType: 400,
|
||||
ScheduleId: 833,
|
||||
BeginTime: 0,
|
||||
EndTime: 2051193600,
|
||||
GachaSortId: 9998,
|
||||
GachaPrefabPath: "GachaShowPanel_A018",
|
||||
GachaPreviewPrefabPath: "UI_Tab_GachaShowPanel_A018",
|
||||
TitleTextmap: "UI_GACHA_SHOW_PANEL_A018_TITLE",
|
||||
LeftGachaTimes: 2147483647,
|
||||
GachaTimesLimit: 2147483647,
|
||||
CostItemId: 223,
|
||||
CostItemNum: 1,
|
||||
TenCostItemId: 223,
|
||||
TenCostItemNum: 10,
|
||||
GachaRecordUrl: serverAddr + "/gm/gacha?gachaType=400&jwt=" + jwtStr,
|
||||
GachaRecordUrlOversea: serverAddr + "/gm/gacha?gachaType=400&jwt=" + jwtStr,
|
||||
GachaProbUrl: serverAddr + "/gm/gacha/details?scheduleId=833&jwt=" + jwtStr,
|
||||
GachaProbUrlOversea: serverAddr + "/gm/gacha/details?scheduleId=833&jwt=" + jwtStr,
|
||||
GachaUpInfoList: []*proto.GachaUpInfo{
|
||||
{
|
||||
ItemParentType: 1,
|
||||
ItemIdList: []uint32{1029},
|
||||
},
|
||||
{
|
||||
ItemParentType: 2,
|
||||
ItemIdList: []uint32{1025, 1034, 1043},
|
||||
},
|
||||
},
|
||||
DisplayUp4ItemList: []uint32{1025},
|
||||
DisplayUp5ItemList: []uint32{1029},
|
||||
WishItemId: 0,
|
||||
WishProgress: 0,
|
||||
WishMaxProgress: 0,
|
||||
IsNewWish: false,
|
||||
},
|
||||
// 阿莫斯之弓&天空之傲
|
||||
{
|
||||
GachaType: 431,
|
||||
ScheduleId: 1143,
|
||||
BeginTime: 0,
|
||||
EndTime: 2051193600,
|
||||
GachaSortId: 9997,
|
||||
GachaPrefabPath: "GachaShowPanel_A030",
|
||||
GachaPreviewPrefabPath: "UI_Tab_GachaShowPanel_A030",
|
||||
TitleTextmap: "UI_GACHA_SHOW_PANEL_A030_TITLE",
|
||||
LeftGachaTimes: 2147483647,
|
||||
GachaTimesLimit: 2147483647,
|
||||
CostItemId: 223,
|
||||
CostItemNum: 1,
|
||||
TenCostItemId: 223,
|
||||
TenCostItemNum: 10,
|
||||
GachaRecordUrl: serverAddr + "/gm/gacha?gachaType=431&jwt=" + jwtStr,
|
||||
GachaRecordUrlOversea: serverAddr + "/gm/gacha?gachaType=431&jwt=" + jwtStr,
|
||||
GachaProbUrl: serverAddr + "/gm/gacha/details?scheduleId=1143&jwt=" + jwtStr,
|
||||
GachaProbUrlOversea: serverAddr + "/gm/gacha/details?scheduleId=1143&jwt=" + jwtStr,
|
||||
GachaUpInfoList: []*proto.GachaUpInfo{
|
||||
{
|
||||
ItemParentType: 1,
|
||||
ItemIdList: []uint32{15502, 12501},
|
||||
},
|
||||
{
|
||||
ItemParentType: 2,
|
||||
ItemIdList: []uint32{11403, 12402, 13401, 14409, 15401},
|
||||
},
|
||||
},
|
||||
DisplayUp4ItemList: []uint32{11403},
|
||||
DisplayUp5ItemList: []uint32{15502, 12501},
|
||||
WishItemId: 0,
|
||||
WishProgress: 0,
|
||||
WishMaxProgress: 0,
|
||||
IsNewWish: false,
|
||||
},
|
||||
// 常驻
|
||||
{
|
||||
GachaType: 201,
|
||||
ScheduleId: 813,
|
||||
BeginTime: 0,
|
||||
EndTime: 2051193600,
|
||||
GachaSortId: 1000,
|
||||
GachaPrefabPath: "GachaShowPanel_A017",
|
||||
GachaPreviewPrefabPath: "UI_Tab_GachaShowPanel_A017",
|
||||
TitleTextmap: "UI_GACHA_SHOW_PANEL_A017_TITLE",
|
||||
LeftGachaTimes: 2147483647,
|
||||
GachaTimesLimit: 2147483647,
|
||||
CostItemId: 224,
|
||||
CostItemNum: 1,
|
||||
TenCostItemId: 224,
|
||||
TenCostItemNum: 10,
|
||||
GachaRecordUrl: serverAddr + "/gm/gacha?gachaType=201&jwt=" + jwtStr,
|
||||
GachaRecordUrlOversea: serverAddr + "/gm/gacha?gachaType=201&jwt=" + jwtStr,
|
||||
GachaProbUrl: serverAddr + "/gm/gacha/details?scheduleId=813&jwt=" + jwtStr,
|
||||
GachaProbUrlOversea: serverAddr + "/gm/gacha/details?scheduleId=813&jwt=" + jwtStr,
|
||||
GachaUpInfoList: []*proto.GachaUpInfo{
|
||||
{
|
||||
ItemParentType: 1,
|
||||
ItemIdList: []uint32{1003, 1016},
|
||||
},
|
||||
{
|
||||
ItemParentType: 2,
|
||||
ItemIdList: []uint32{1021, 1006, 1015},
|
||||
},
|
||||
},
|
||||
DisplayUp4ItemList: []uint32{1021},
|
||||
DisplayUp5ItemList: []uint32{1003, 1016},
|
||||
WishItemId: 0,
|
||||
WishProgress: 0,
|
||||
WishMaxProgress: 0,
|
||||
IsNewWish: false,
|
||||
},
|
||||
}
|
||||
|
||||
g.SendMsg(cmd.GetGachaInfoRsp, player.PlayerID, player.ClientSeq, getGachaInfoRsp)
|
||||
}
|
||||
|
||||
func (g *GameManager) DoGachaReq(player *model.Player, payloadMsg pb.Message) {
|
||||
logger.LOG.Debug("user do gacha, uid: %v", player.PlayerID)
|
||||
req := payloadMsg.(*proto.DoGachaReq)
|
||||
gachaScheduleId := req.GachaScheduleId
|
||||
gachaTimes := req.GachaTimes
|
||||
|
||||
gachaType := uint32(0)
|
||||
costItemId := uint32(0)
|
||||
switch gachaScheduleId {
|
||||
case 823:
|
||||
// 温迪
|
||||
gachaType = 300
|
||||
costItemId = 223
|
||||
case 833:
|
||||
// 可莉
|
||||
gachaType = 400
|
||||
costItemId = 223
|
||||
case 1143:
|
||||
// 阿莫斯之弓&天空之傲
|
||||
gachaType = 431
|
||||
costItemId = 223
|
||||
case 813:
|
||||
// 常驻
|
||||
gachaType = 201
|
||||
costItemId = 224
|
||||
}
|
||||
|
||||
// PacketDoGachaRsp
|
||||
doGachaRsp := new(proto.DoGachaRsp)
|
||||
doGachaRsp.GachaType = gachaType
|
||||
doGachaRsp.GachaScheduleId = gachaScheduleId
|
||||
doGachaRsp.GachaTimes = gachaTimes
|
||||
doGachaRsp.NewGachaRandom = 12345
|
||||
doGachaRsp.LeftGachaTimes = 2147483647
|
||||
doGachaRsp.GachaTimesLimit = 2147483647
|
||||
doGachaRsp.CostItemId = costItemId
|
||||
doGachaRsp.CostItemNum = 1
|
||||
doGachaRsp.TenCostItemId = costItemId
|
||||
doGachaRsp.TenCostItemNum = 10
|
||||
|
||||
// 先扣掉粉球或蓝球再进行抽卡
|
||||
g.CostUserItem(player.PlayerID, []*UserItem{
|
||||
{
|
||||
ItemId: costItemId,
|
||||
ChangeCount: gachaTimes,
|
||||
},
|
||||
})
|
||||
|
||||
doGachaRsp.GachaItemList = make([]*proto.GachaItem, 0)
|
||||
for i := uint32(0); i < gachaTimes; i++ {
|
||||
var ok bool
|
||||
var itemId uint32
|
||||
if gachaType == 400 {
|
||||
// 可莉
|
||||
ok, itemId = g.doGachaKlee()
|
||||
} else if gachaType == 300 {
|
||||
// 角色UP池
|
||||
ok, itemId = g.doGachaOnce(player.PlayerID, gachaType, true, false)
|
||||
} else if gachaType == 431 {
|
||||
// 武器UP池
|
||||
ok, itemId = g.doGachaOnce(player.PlayerID, gachaType, true, true)
|
||||
} else if gachaType == 201 {
|
||||
// 常驻
|
||||
ok, itemId = g.doGachaOnce(player.PlayerID, gachaType, false, false)
|
||||
} else {
|
||||
ok, itemId = false, 0
|
||||
}
|
||||
if !ok {
|
||||
itemId = 11301
|
||||
}
|
||||
|
||||
// 添加抽卡获得的道具
|
||||
if itemId > 1000 && itemId < 2000 {
|
||||
avatarId := (itemId % 1000) + 10000000
|
||||
_, exist := player.AvatarMap[avatarId]
|
||||
if !exist {
|
||||
g.AddUserAvatar(player.PlayerID, avatarId)
|
||||
} else {
|
||||
constellationItemId := itemId + 100
|
||||
if player.GetItemCount(constellationItemId) < 6 {
|
||||
g.AddUserItem(player.PlayerID, []*UserItem{{ItemId: constellationItemId, ChangeCount: 1}}, false, 0)
|
||||
}
|
||||
}
|
||||
} else if itemId > 10000 && itemId < 20000 {
|
||||
g.AddUserWeapon(player.PlayerID, itemId)
|
||||
} else {
|
||||
g.AddUserItem(player.PlayerID, []*UserItem{{ItemId: itemId, ChangeCount: 1}}, false, 0)
|
||||
}
|
||||
|
||||
// 计算星尘星辉
|
||||
xc := uint32(random.GetRandomInt32(0, 10))
|
||||
xh := uint32(random.GetRandomInt32(0, 10))
|
||||
|
||||
gachaItem := new(proto.GachaItem)
|
||||
gachaItem.GachaItem_ = &proto.ItemParam{
|
||||
ItemId: itemId,
|
||||
Count: 1,
|
||||
}
|
||||
// 星尘
|
||||
if xc != 0 {
|
||||
g.AddUserItem(player.PlayerID, []*UserItem{{
|
||||
ItemId: 222,
|
||||
ChangeCount: xc,
|
||||
}}, false, 0)
|
||||
gachaItem.TokenItemList = []*proto.ItemParam{{
|
||||
ItemId: 222,
|
||||
Count: xc,
|
||||
}}
|
||||
}
|
||||
// 星辉
|
||||
if xh != 0 {
|
||||
g.AddUserItem(player.PlayerID, []*UserItem{{
|
||||
ItemId: 221,
|
||||
ChangeCount: xh,
|
||||
}}, false, 0)
|
||||
gachaItem.TransferItems = []*proto.GachaTransferItem{{
|
||||
Item: &proto.ItemParam{
|
||||
ItemId: 221,
|
||||
Count: xh,
|
||||
},
|
||||
}}
|
||||
}
|
||||
doGachaRsp.GachaItemList = append(doGachaRsp.GachaItemList, gachaItem)
|
||||
}
|
||||
|
||||
//logger.LOG.Debug("doGachaRsp: %v", doGachaRsp.String())
|
||||
g.SendMsg(cmd.DoGachaRsp, player.PlayerID, player.ClientSeq, doGachaRsp)
|
||||
}
|
||||
|
||||
// 扣1给可莉刷烧烤酱
|
||||
func (g *GameManager) doGachaKlee() (bool, uint32) {
|
||||
allAvatarList := make([]uint32, 0)
|
||||
allAvatarDataConfig := g.GetAllAvatarDataConfig()
|
||||
for k, v := range allAvatarDataConfig {
|
||||
if v.QualityType == "QUALITY_ORANGE" || v.QualityType == "QUALITY_PURPLE" {
|
||||
allAvatarList = append(allAvatarList, uint32(k))
|
||||
}
|
||||
}
|
||||
allWeaponList := make([]uint32, 0)
|
||||
allWeaponDataConfig := g.GetAllWeaponDataConfig()
|
||||
for k, v := range allWeaponDataConfig {
|
||||
if v.RankLevel == 5 {
|
||||
allWeaponList = append(allWeaponList, uint32(k))
|
||||
}
|
||||
}
|
||||
allGoodList := make([]uint32, 0)
|
||||
// 全部角色
|
||||
allGoodList = append(allGoodList, allAvatarList...)
|
||||
// 全部5星武器
|
||||
allGoodList = append(allGoodList, allWeaponList...)
|
||||
// 原石 摩拉 粉球 蓝球
|
||||
allGoodList = append(allGoodList, 201, 202, 223, 224)
|
||||
// 苟利国家生死以
|
||||
allGoodList = append(allGoodList, 100081)
|
||||
rn := random.GetRandomInt32(0, int32(len(allGoodList)-1))
|
||||
itemId := allGoodList[rn]
|
||||
if itemId > 10000000 {
|
||||
itemId %= 1000
|
||||
itemId += 1000
|
||||
}
|
||||
return true, itemId
|
||||
}
|
||||
|
||||
const (
|
||||
Orange = iota
|
||||
Purple
|
||||
Blue
|
||||
Avatar
|
||||
Weapon
|
||||
)
|
||||
|
||||
const (
|
||||
StandardOrangeTimesFixThreshold uint32 = 74 // 标准池触发5星概率修正阈值的抽卡次数
|
||||
StandardOrangeTimesFixValue int32 = 600 // 标准池5星概率修正因子
|
||||
StandardPurpleTimesFixThreshold uint32 = 9 // 标准池触发4星概率修正阈值的抽卡次数
|
||||
StandardPurpleTimesFixValue int32 = 5100 // 标准池4星概率修正因子
|
||||
WeaponOrangeTimesFixThreshold uint32 = 63 // 武器池触发5星概率修正阈值的抽卡次数
|
||||
WeaponOrangeTimesFixValue int32 = 700 // 武器池5星概率修正因子
|
||||
WeaponPurpleTimesFixThreshold uint32 = 8 // 武器池触发4星概率修正阈值的抽卡次数
|
||||
WeaponPurpleTimesFixValue int32 = 6000 // 武器池4星概率修正因子
|
||||
)
|
||||
|
||||
// 单抽一次
|
||||
func (g *GameManager) doGachaOnce(userId uint32, gachaType uint32, mustGetUpEnable bool, weaponFix bool) (bool, uint32) {
|
||||
player := g.userManager.GetOnlineUser(userId)
|
||||
if player == nil {
|
||||
logger.LOG.Error("player is nil, uid: %v", userId)
|
||||
return false, 0
|
||||
}
|
||||
|
||||
// 找到卡池对应的掉落组
|
||||
dropGroupDataConfig := gdc.CONF.DropGroupDataMap[int32(gachaType)]
|
||||
if dropGroupDataConfig == nil {
|
||||
logger.LOG.Error("drop group not found, drop id: %v", gachaType)
|
||||
return false, 0
|
||||
}
|
||||
|
||||
// 获取用户的卡池保底信息
|
||||
gachaPoolInfo := player.DropInfo.GachaPoolInfo[gachaType]
|
||||
if gachaPoolInfo == nil {
|
||||
logger.LOG.Error("user gacha pool info not found, gacha type: %v", gachaType)
|
||||
return false, 0
|
||||
}
|
||||
|
||||
// 保底计数+1
|
||||
gachaPoolInfo.OrangeTimes++
|
||||
gachaPoolInfo.PurpleTimes++
|
||||
|
||||
// 4星和5星概率修正
|
||||
OrangeTimesFixThreshold := uint32(0)
|
||||
OrangeTimesFixValue := int32(0)
|
||||
PurpleTimesFixThreshold := uint32(0)
|
||||
PurpleTimesFixValue := int32(0)
|
||||
if !weaponFix {
|
||||
OrangeTimesFixThreshold = StandardOrangeTimesFixThreshold
|
||||
OrangeTimesFixValue = StandardOrangeTimesFixValue
|
||||
PurpleTimesFixThreshold = StandardPurpleTimesFixThreshold
|
||||
PurpleTimesFixValue = StandardPurpleTimesFixValue
|
||||
} else {
|
||||
OrangeTimesFixThreshold = WeaponOrangeTimesFixThreshold
|
||||
OrangeTimesFixValue = WeaponOrangeTimesFixValue
|
||||
PurpleTimesFixThreshold = WeaponPurpleTimesFixThreshold
|
||||
PurpleTimesFixValue = WeaponPurpleTimesFixValue
|
||||
}
|
||||
if gachaPoolInfo.OrangeTimes >= OrangeTimesFixThreshold || gachaPoolInfo.PurpleTimes >= PurpleTimesFixThreshold {
|
||||
fixDropGroupDataConfig := new(gdc.DropGroupData)
|
||||
fixDropGroupDataConfig.DropId = dropGroupDataConfig.DropId
|
||||
fixDropGroupDataConfig.WeightAll = dropGroupDataConfig.WeightAll
|
||||
// 计算4星和5星权重修正值
|
||||
addOrangeWeight := int32(gachaPoolInfo.OrangeTimes-OrangeTimesFixThreshold+1) * OrangeTimesFixValue
|
||||
if addOrangeWeight < 0 {
|
||||
addOrangeWeight = 0
|
||||
}
|
||||
addPurpleWeight := int32(gachaPoolInfo.PurpleTimes-PurpleTimesFixThreshold+1) * PurpleTimesFixValue
|
||||
if addPurpleWeight < 0 {
|
||||
addPurpleWeight = 0
|
||||
}
|
||||
for _, drop := range dropGroupDataConfig.DropConfig {
|
||||
fixDrop := new(gdc.Drop)
|
||||
fixDrop.Result = drop.Result
|
||||
fixDrop.DropId = drop.DropId
|
||||
fixDrop.IsEnd = drop.IsEnd
|
||||
// 找到5/4/3星掉落组id 要求配置表的5/4/3星掉落组id规则固定为(卡池类型*10+1/2/3)
|
||||
orangeDropId := int32(gachaType*10 + 1)
|
||||
purpleDropId := int32(gachaType*10 + 2)
|
||||
blueDropId := int32(gachaType*10 + 3)
|
||||
// 权重修正
|
||||
if drop.Result == orangeDropId {
|
||||
fixDrop.Weight = drop.Weight + addOrangeWeight
|
||||
} else if drop.Result == purpleDropId {
|
||||
fixDrop.Weight = drop.Weight + addPurpleWeight
|
||||
} else if drop.Result == blueDropId {
|
||||
fixDrop.Weight = drop.Weight - addOrangeWeight - addPurpleWeight
|
||||
} else {
|
||||
logger.LOG.Error("invalid drop group id, does not match any case of orange/purple/blue, result group id: %v", drop.Result)
|
||||
fixDrop.Weight = drop.Weight
|
||||
}
|
||||
fixDropGroupDataConfig.DropConfig = append(fixDropGroupDataConfig.DropConfig, fixDrop)
|
||||
}
|
||||
dropGroupDataConfig = fixDropGroupDataConfig
|
||||
}
|
||||
|
||||
// 掉落
|
||||
ok, drop := g.doFullRandDrop(dropGroupDataConfig)
|
||||
if !ok {
|
||||
return false, 0
|
||||
}
|
||||
// 分析本次掉落结果的星级和类型
|
||||
itemColor := 0
|
||||
itemType := 0
|
||||
_ = itemType
|
||||
gachaItemId := uint32(drop.Result)
|
||||
if gachaItemId < 2000 {
|
||||
// 抽到角色
|
||||
itemType = Avatar
|
||||
avatarId := (gachaItemId % 1000) + 10000000
|
||||
allAvatarDataConfig := g.GetAllAvatarDataConfig()
|
||||
avatarDataConfig := allAvatarDataConfig[int32(avatarId)]
|
||||
if avatarDataConfig == nil {
|
||||
logger.LOG.Error("avatar data config not found, avatar id: %v", avatarId)
|
||||
return false, 0
|
||||
}
|
||||
if avatarDataConfig.QualityType == "QUALITY_ORANGE" {
|
||||
itemColor = Orange
|
||||
logger.LOG.Debug("[orange avatar], times: %v, gachaItemId: %v", gachaPoolInfo.OrangeTimes, gachaItemId)
|
||||
if gachaPoolInfo.OrangeTimes > 90 {
|
||||
logger.LOG.Error("[abnormal orange avatar], times: %v, gachaItemId: %v", gachaPoolInfo.OrangeTimes, gachaItemId)
|
||||
}
|
||||
} else if avatarDataConfig.QualityType == "QUALITY_PURPLE" {
|
||||
itemColor = Purple
|
||||
logger.LOG.Debug("[purple avatar], times: %v, gachaItemId: %v", gachaPoolInfo.PurpleTimes, gachaItemId)
|
||||
if gachaPoolInfo.PurpleTimes > 10 {
|
||||
logger.LOG.Error("[abnormal purple avatar], times: %v, gachaItemId: %v", gachaPoolInfo.PurpleTimes, gachaItemId)
|
||||
}
|
||||
} else {
|
||||
itemColor = Blue
|
||||
}
|
||||
} else {
|
||||
// 抽到武器
|
||||
itemType = Weapon
|
||||
allWeaponDataConfig := g.GetAllWeaponDataConfig()
|
||||
weaponDataConfig := allWeaponDataConfig[int32(gachaItemId)]
|
||||
if weaponDataConfig == nil {
|
||||
logger.LOG.Error("weapon item data config not found, item id: %v", gachaItemId)
|
||||
return false, 0
|
||||
}
|
||||
if weaponDataConfig.RankLevel == 5 {
|
||||
itemColor = Orange
|
||||
logger.LOG.Debug("[orange weapon], times: %v, gachaItemId: %v", gachaPoolInfo.OrangeTimes, gachaItemId)
|
||||
if gachaPoolInfo.OrangeTimes > 90 {
|
||||
logger.LOG.Error("[abnormal orange weapon], times: %v, gachaItemId: %v", gachaPoolInfo.OrangeTimes, gachaItemId)
|
||||
}
|
||||
} else if weaponDataConfig.RankLevel == 4 {
|
||||
itemColor = Purple
|
||||
logger.LOG.Debug("[purple weapon], times: %v, gachaItemId: %v", gachaPoolInfo.PurpleTimes, gachaItemId)
|
||||
if gachaPoolInfo.PurpleTimes > 10 {
|
||||
logger.LOG.Error("[abnormal purple weapon], times: %v, gachaItemId: %v", gachaPoolInfo.PurpleTimes, gachaItemId)
|
||||
}
|
||||
} else {
|
||||
itemColor = Blue
|
||||
}
|
||||
}
|
||||
// 后处理
|
||||
switch itemColor {
|
||||
case Orange:
|
||||
// 重置5星保底计数
|
||||
gachaPoolInfo.OrangeTimes = 0
|
||||
if mustGetUpEnable {
|
||||
// 找到UP的5星对应的掉落组id 要求配置表的UP的5星掉落组id规则固定为(卡池类型*100+12)
|
||||
upOrangeDropId := int32(gachaType*100 + 12)
|
||||
// 替换本次结果为5星大保底
|
||||
if gachaPoolInfo.MustGetUpOrange {
|
||||
logger.LOG.Debug("trigger must get up orange, uid: %v", userId)
|
||||
upOrangeDropGroupDataConfig := gdc.CONF.DropGroupDataMap[upOrangeDropId]
|
||||
if upOrangeDropGroupDataConfig == nil {
|
||||
logger.LOG.Error("drop group not found, drop id: %v", upOrangeDropId)
|
||||
return false, 0
|
||||
}
|
||||
upOrangeOk, upOrangeDrop := g.doFullRandDrop(upOrangeDropGroupDataConfig)
|
||||
if !upOrangeOk {
|
||||
return false, 0
|
||||
}
|
||||
gachaPoolInfo.MustGetUpOrange = false
|
||||
upOrangeGachaItemId := uint32(upOrangeDrop.Result)
|
||||
return upOrangeOk, upOrangeGachaItemId
|
||||
}
|
||||
// 触发5星大保底
|
||||
if drop.DropId != upOrangeDropId {
|
||||
gachaPoolInfo.MustGetUpOrange = true
|
||||
}
|
||||
}
|
||||
case Purple:
|
||||
// 重置4星保底计数
|
||||
gachaPoolInfo.PurpleTimes = 0
|
||||
if mustGetUpEnable {
|
||||
// 找到UP的4星对应的掉落组id 要求配置表的UP的4星掉落组id规则固定为(卡池类型*100+22)
|
||||
upPurpleDropId := int32(gachaType*100 + 22)
|
||||
// 替换本次结果为4星大保底
|
||||
if gachaPoolInfo.MustGetUpPurple {
|
||||
logger.LOG.Debug("trigger must get up purple, uid: %v", userId)
|
||||
upPurpleDropGroupDataConfig := gdc.CONF.DropGroupDataMap[upPurpleDropId]
|
||||
if upPurpleDropGroupDataConfig == nil {
|
||||
logger.LOG.Error("drop group not found, drop id: %v", upPurpleDropId)
|
||||
return false, 0
|
||||
}
|
||||
upPurpleOk, upPurpleDrop := g.doFullRandDrop(upPurpleDropGroupDataConfig)
|
||||
if !upPurpleOk {
|
||||
return false, 0
|
||||
}
|
||||
gachaPoolInfo.MustGetUpPurple = false
|
||||
upPurpleGachaItemId := uint32(upPurpleDrop.Result)
|
||||
return upPurpleOk, upPurpleGachaItemId
|
||||
}
|
||||
// 触发4星大保底
|
||||
if drop.DropId != upPurpleDropId {
|
||||
gachaPoolInfo.MustGetUpPurple = true
|
||||
}
|
||||
}
|
||||
default:
|
||||
}
|
||||
return ok, gachaItemId
|
||||
}
|
||||
|
||||
// 走一次完整流程的掉落组
|
||||
func (g *GameManager) doFullRandDrop(dropGroupDataConfig *gdc.DropGroupData) (bool, *gdc.Drop) {
|
||||
for {
|
||||
drop := g.doRandDropOnce(dropGroupDataConfig)
|
||||
if drop == nil {
|
||||
logger.LOG.Error("weight error, drop group config: %v", dropGroupDataConfig)
|
||||
return false, nil
|
||||
}
|
||||
if drop.IsEnd {
|
||||
// 成功抽到物品
|
||||
return true, drop
|
||||
}
|
||||
// 进行下一步掉落流程
|
||||
dropGroupDataConfig = gdc.CONF.DropGroupDataMap[drop.Result]
|
||||
if dropGroupDataConfig == nil {
|
||||
logger.LOG.Error("drop config tab exist error, invalid drop id: %v", drop.Result)
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 进行单次随机掉落
|
||||
func (g *GameManager) doRandDropOnce(dropGroupDataConfig *gdc.DropGroupData) *gdc.Drop {
|
||||
randNum := random.GetRandomInt32(0, dropGroupDataConfig.WeightAll-1)
|
||||
sumWeight := int32(0)
|
||||
// 轮盘选择法
|
||||
for _, drop := range dropGroupDataConfig.DropConfig {
|
||||
sumWeight += drop.Weight
|
||||
if sumWeight > randNum {
|
||||
return drop
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
182
gs/game/user_item.go
Normal file
182
gs/game/user_item.go
Normal file
@@ -0,0 +1,182 @@
|
||||
package game
|
||||
|
||||
import (
|
||||
gdc "hk4e/gs/config"
|
||||
"hk4e/gs/constant"
|
||||
"hk4e/logger"
|
||||
"hk4e/protocol/cmd"
|
||||
"hk4e/protocol/proto"
|
||||
)
|
||||
|
||||
type UserItem struct {
|
||||
ItemId uint32
|
||||
ChangeCount uint32
|
||||
}
|
||||
|
||||
func (g *GameManager) GetAllItemDataConfig() map[int32]*gdc.ItemData {
|
||||
allItemDataConfig := make(map[int32]*gdc.ItemData)
|
||||
for itemId, itemData := range gdc.CONF.ItemDataMap {
|
||||
if itemData.ItemEnumType == constant.ItemTypeConst.ITEM_WEAPON {
|
||||
// 排除武器
|
||||
continue
|
||||
}
|
||||
if itemData.ItemEnumType == constant.ItemTypeConst.ITEM_RELIQUARY {
|
||||
// 排除圣遗物
|
||||
continue
|
||||
}
|
||||
if itemId == 100086 ||
|
||||
itemId == 100087 ||
|
||||
(itemId >= 100100 && itemId <= 101000) ||
|
||||
(itemId >= 101106 && itemId <= 101110) ||
|
||||
itemId == 101306 ||
|
||||
(itemId >= 101500 && itemId <= 104000) ||
|
||||
itemId == 105001 ||
|
||||
itemId == 105004 ||
|
||||
(itemId >= 106000 && itemId <= 107000) ||
|
||||
itemId == 107011 ||
|
||||
itemId == 108000 ||
|
||||
(itemId >= 109000 && itemId <= 110000) ||
|
||||
(itemId >= 115000 && itemId <= 130000) ||
|
||||
(itemId >= 200200 && itemId <= 200899) ||
|
||||
itemId == 220050 ||
|
||||
itemId == 220054 {
|
||||
// 排除无效道具
|
||||
continue
|
||||
}
|
||||
allItemDataConfig[itemId] = itemData
|
||||
}
|
||||
return allItemDataConfig
|
||||
}
|
||||
|
||||
func (g *GameManager) AddUserItem(userId uint32, itemList []*UserItem, isHint bool, hintReason uint16) {
|
||||
player := g.userManager.GetOnlineUser(userId)
|
||||
if player == nil {
|
||||
logger.LOG.Error("player is nil, uid: %v", userId)
|
||||
return
|
||||
}
|
||||
for _, userItem := range itemList {
|
||||
player.AddItem(userItem.ItemId, userItem.ChangeCount)
|
||||
}
|
||||
|
||||
// PacketStoreItemChangeNotify
|
||||
storeItemChangeNotify := new(proto.StoreItemChangeNotify)
|
||||
storeItemChangeNotify.StoreType = proto.StoreType_STORE_TYPE_PACK
|
||||
for _, userItem := range itemList {
|
||||
pbItem := &proto.Item{
|
||||
ItemId: userItem.ItemId,
|
||||
Guid: player.GetItemGuid(userItem.ItemId),
|
||||
Detail: &proto.Item_Material{
|
||||
Material: &proto.Material{
|
||||
Count: player.GetItemCount(userItem.ItemId),
|
||||
},
|
||||
},
|
||||
}
|
||||
storeItemChangeNotify.ItemList = append(storeItemChangeNotify.ItemList, pbItem)
|
||||
}
|
||||
g.SendMsg(cmd.StoreItemChangeNotify, userId, player.ClientSeq, storeItemChangeNotify)
|
||||
|
||||
if isHint {
|
||||
if hintReason == 0 {
|
||||
hintReason = constant.ActionReasonConst.SubfieldDrop
|
||||
}
|
||||
// PacketItemAddHintNotify
|
||||
itemAddHintNotify := new(proto.ItemAddHintNotify)
|
||||
itemAddHintNotify.Reason = uint32(hintReason)
|
||||
for _, userItem := range itemList {
|
||||
itemAddHintNotify.ItemList = append(itemAddHintNotify.ItemList, &proto.ItemHint{
|
||||
ItemId: userItem.ItemId,
|
||||
Count: userItem.ChangeCount,
|
||||
IsNew: false,
|
||||
})
|
||||
}
|
||||
g.SendMsg(cmd.ItemAddHintNotify, userId, player.ClientSeq, itemAddHintNotify)
|
||||
}
|
||||
|
||||
// PacketPlayerPropNotify
|
||||
playerPropNotify := new(proto.PlayerPropNotify)
|
||||
playerPropNotify.PropMap = make(map[uint32]*proto.PropValue)
|
||||
for _, userItem := range itemList {
|
||||
isVirtualItem, prop := player.GetVirtualItemProp(userItem.ItemId)
|
||||
if !isVirtualItem {
|
||||
continue
|
||||
}
|
||||
playerPropNotify.PropMap[uint32(prop)] = &proto.PropValue{
|
||||
Type: uint32(prop),
|
||||
Val: int64(player.PropertiesMap[prop]),
|
||||
Value: &proto.PropValue_Ival{
|
||||
Ival: int64(player.PropertiesMap[prop]),
|
||||
},
|
||||
}
|
||||
}
|
||||
if len(playerPropNotify.PropMap) > 0 {
|
||||
g.SendMsg(cmd.PlayerPropNotify, userId, player.ClientSeq, playerPropNotify)
|
||||
}
|
||||
}
|
||||
|
||||
func (g *GameManager) CostUserItem(userId uint32, itemList []*UserItem) {
|
||||
player := g.userManager.GetOnlineUser(userId)
|
||||
if player == nil {
|
||||
logger.LOG.Error("player is nil, uid: %v", userId)
|
||||
return
|
||||
}
|
||||
for _, userItem := range itemList {
|
||||
player.CostItem(userItem.ItemId, userItem.ChangeCount)
|
||||
}
|
||||
|
||||
// PacketStoreItemChangeNotify
|
||||
storeItemChangeNotify := new(proto.StoreItemChangeNotify)
|
||||
storeItemChangeNotify.StoreType = proto.StoreType_STORE_TYPE_PACK
|
||||
for _, userItem := range itemList {
|
||||
count := player.GetItemCount(userItem.ItemId)
|
||||
if count == 0 {
|
||||
continue
|
||||
}
|
||||
pbItem := &proto.Item{
|
||||
ItemId: userItem.ItemId,
|
||||
Guid: player.GetItemGuid(userItem.ItemId),
|
||||
Detail: &proto.Item_Material{
|
||||
Material: &proto.Material{
|
||||
Count: count,
|
||||
},
|
||||
},
|
||||
}
|
||||
storeItemChangeNotify.ItemList = append(storeItemChangeNotify.ItemList, pbItem)
|
||||
}
|
||||
if len(storeItemChangeNotify.ItemList) > 0 {
|
||||
g.SendMsg(cmd.StoreItemChangeNotify, userId, player.ClientSeq, storeItemChangeNotify)
|
||||
}
|
||||
|
||||
// PacketStoreItemDelNotify
|
||||
storeItemDelNotify := new(proto.StoreItemDelNotify)
|
||||
storeItemDelNotify.StoreType = proto.StoreType_STORE_TYPE_PACK
|
||||
for _, userItem := range itemList {
|
||||
count := player.GetItemCount(userItem.ItemId)
|
||||
if count > 0 {
|
||||
continue
|
||||
}
|
||||
storeItemDelNotify.GuidList = append(storeItemDelNotify.GuidList, player.GetItemGuid(userItem.ItemId))
|
||||
}
|
||||
if len(storeItemDelNotify.GuidList) > 0 {
|
||||
g.SendMsg(cmd.StoreItemDelNotify, userId, player.ClientSeq, storeItemDelNotify)
|
||||
}
|
||||
|
||||
// PacketPlayerPropNotify
|
||||
playerPropNotify := new(proto.PlayerPropNotify)
|
||||
playerPropNotify.PropMap = make(map[uint32]*proto.PropValue)
|
||||
for _, userItem := range itemList {
|
||||
isVirtualItem, prop := player.GetVirtualItemProp(userItem.ItemId)
|
||||
if !isVirtualItem {
|
||||
continue
|
||||
}
|
||||
playerPropNotify.PropMap[uint32(prop)] = &proto.PropValue{
|
||||
Type: uint32(prop),
|
||||
Val: int64(player.PropertiesMap[prop]),
|
||||
Value: &proto.PropValue_Ival{
|
||||
Ival: int64(player.PropertiesMap[prop]),
|
||||
},
|
||||
}
|
||||
}
|
||||
if len(playerPropNotify.PropMap) > 0 {
|
||||
g.SendMsg(cmd.PlayerPropNotify, userId, player.ClientSeq, playerPropNotify)
|
||||
}
|
||||
}
|
||||
376
gs/game/user_login.go
Normal file
376
gs/game/user_login.go
Normal file
@@ -0,0 +1,376 @@
|
||||
package game
|
||||
|
||||
import (
|
||||
pb "google.golang.org/protobuf/proto"
|
||||
"hk4e/common/utils/reflection"
|
||||
gdc "hk4e/gs/config"
|
||||
"hk4e/gs/constant"
|
||||
"hk4e/gs/model"
|
||||
"hk4e/logger"
|
||||
"hk4e/protocol/cmd"
|
||||
"hk4e/protocol/proto"
|
||||
"time"
|
||||
)
|
||||
|
||||
func (g *GameManager) OnLogin(userId uint32, clientSeq uint32) {
|
||||
logger.LOG.Info("user login, uid: %v", userId)
|
||||
player, asyncWait := g.userManager.OnlineUser(userId, clientSeq)
|
||||
if !asyncWait {
|
||||
g.OnLoginOk(userId, player, clientSeq)
|
||||
}
|
||||
}
|
||||
|
||||
func (g *GameManager) OnLoginOk(userId uint32, player *model.Player, clientSeq uint32) {
|
||||
if player == nil {
|
||||
g.SendMsg(cmd.DoSetPlayerBornDataNotify, userId, clientSeq, new(proto.DoSetPlayerBornDataNotify))
|
||||
return
|
||||
}
|
||||
player.OnlineTime = uint32(time.Now().UnixMilli())
|
||||
player.Online = true
|
||||
|
||||
// TODO 3.0.0REL版本 目前存在当前队伍活跃角色非主角时 登录进不去场景的情况 所以暂时先把四号队伍作为仅存在主角的保留队伍
|
||||
team := player.TeamConfig.GetTeamByIndex(3)
|
||||
team.AvatarIdList = []uint32{player.MainCharAvatarId, 0, 0, 0}
|
||||
player.TeamConfig.CurrTeamIndex = 3
|
||||
player.TeamConfig.CurrAvatarIndex = 0
|
||||
|
||||
// 初始化
|
||||
player.InitAll()
|
||||
player.TeamConfig.UpdateTeam()
|
||||
// 创建世界
|
||||
world := g.worldManager.CreateWorld(player, false)
|
||||
world.AddPlayer(player, player.SceneId)
|
||||
player.WorldId = world.id
|
||||
|
||||
// TODO 薄荷标记
|
||||
if world.IsBigWorld() {
|
||||
bigWorld := world.GetSceneById(3)
|
||||
for pos := range g.worldManager.worldStatic.terrain {
|
||||
bigWorld.CreateEntityGadget(&model.Vector{
|
||||
X: float64(pos.X),
|
||||
Y: float64(pos.Y),
|
||||
Z: float64(pos.Z),
|
||||
}, 3003009)
|
||||
}
|
||||
}
|
||||
|
||||
// PacketPlayerDataNotify
|
||||
playerDataNotify := new(proto.PlayerDataNotify)
|
||||
playerDataNotify.NickName = player.NickName
|
||||
playerDataNotify.ServerTime = uint64(time.Now().UnixMilli())
|
||||
playerDataNotify.IsFirstLoginToday = true
|
||||
playerDataNotify.RegionId = player.RegionId
|
||||
playerDataNotify.PropMap = make(map[uint32]*proto.PropValue)
|
||||
for k, v := range player.PropertiesMap {
|
||||
propValue := new(proto.PropValue)
|
||||
propValue.Type = uint32(k)
|
||||
propValue.Value = &proto.PropValue_Ival{Ival: int64(v)}
|
||||
propValue.Val = int64(v)
|
||||
playerDataNotify.PropMap[uint32(k)] = propValue
|
||||
}
|
||||
g.SendMsg(cmd.PlayerDataNotify, userId, clientSeq, playerDataNotify)
|
||||
|
||||
// PacketStoreWeightLimitNotify
|
||||
storeWeightLimitNotify := new(proto.StoreWeightLimitNotify)
|
||||
storeWeightLimitNotify.StoreType = proto.StoreType_STORE_TYPE_PACK
|
||||
// TODO 原神背包容量限制 写到配置文件
|
||||
storeWeightLimitNotify.WeightLimit = 30000
|
||||
storeWeightLimitNotify.WeaponCountLimit = 2000
|
||||
storeWeightLimitNotify.ReliquaryCountLimit = 1500
|
||||
storeWeightLimitNotify.MaterialCountLimit = 2000
|
||||
storeWeightLimitNotify.FurnitureCountLimit = 2000
|
||||
g.SendMsg(cmd.StoreWeightLimitNotify, userId, clientSeq, storeWeightLimitNotify)
|
||||
|
||||
// PacketPlayerStoreNotify
|
||||
playerStoreNotify := new(proto.PlayerStoreNotify)
|
||||
playerStoreNotify.StoreType = proto.StoreType_STORE_TYPE_PACK
|
||||
playerStoreNotify.WeightLimit = 30000
|
||||
itemDataMapConfig := gdc.CONF.ItemDataMap
|
||||
for _, weapon := range player.WeaponMap {
|
||||
pbItem := &proto.Item{
|
||||
ItemId: weapon.ItemId,
|
||||
Guid: weapon.Guid,
|
||||
Detail: nil,
|
||||
}
|
||||
if itemDataMapConfig[int32(weapon.ItemId)].ItemEnumType != constant.ItemTypeConst.ITEM_WEAPON {
|
||||
continue
|
||||
}
|
||||
affixMap := make(map[uint32]uint32)
|
||||
for _, affixId := range weapon.AffixIdList {
|
||||
affixMap[affixId] = uint32(weapon.Refinement)
|
||||
}
|
||||
pbItem.Detail = &proto.Item_Equip{
|
||||
Equip: &proto.Equip{
|
||||
Detail: &proto.Equip_Weapon{
|
||||
Weapon: &proto.Weapon{
|
||||
Level: uint32(weapon.Level),
|
||||
Exp: weapon.Exp,
|
||||
PromoteLevel: uint32(weapon.Promote),
|
||||
AffixMap: affixMap,
|
||||
},
|
||||
},
|
||||
IsLocked: weapon.Lock,
|
||||
},
|
||||
}
|
||||
playerStoreNotify.ItemList = append(playerStoreNotify.ItemList, pbItem)
|
||||
}
|
||||
for _, reliquary := range player.ReliquaryMap {
|
||||
pbItem := &proto.Item{
|
||||
ItemId: reliquary.ItemId,
|
||||
Guid: reliquary.Guid,
|
||||
Detail: nil,
|
||||
}
|
||||
if itemDataMapConfig[int32(reliquary.ItemId)].ItemEnumType != constant.ItemTypeConst.ITEM_RELIQUARY {
|
||||
continue
|
||||
}
|
||||
pbItem.Detail = &proto.Item_Equip{
|
||||
Equip: &proto.Equip{
|
||||
Detail: &proto.Equip_Reliquary{
|
||||
Reliquary: &proto.Reliquary{
|
||||
Level: uint32(reliquary.Level),
|
||||
Exp: reliquary.Exp,
|
||||
PromoteLevel: uint32(reliquary.Promote),
|
||||
MainPropId: reliquary.MainPropId,
|
||||
// TODO 圣遗物副词条
|
||||
AppendPropIdList: nil,
|
||||
},
|
||||
},
|
||||
IsLocked: reliquary.Lock,
|
||||
},
|
||||
}
|
||||
playerStoreNotify.ItemList = append(playerStoreNotify.ItemList, pbItem)
|
||||
}
|
||||
for _, item := range player.ItemMap {
|
||||
pbItem := &proto.Item{
|
||||
ItemId: item.ItemId,
|
||||
Guid: item.Guid,
|
||||
Detail: nil,
|
||||
}
|
||||
itemDataConfig := itemDataMapConfig[int32(item.ItemId)]
|
||||
if itemDataConfig != nil && itemDataConfig.ItemEnumType == constant.ItemTypeConst.ITEM_FURNITURE {
|
||||
pbItem.Detail = &proto.Item_Furniture{
|
||||
Furniture: &proto.Furniture{
|
||||
Count: item.Count,
|
||||
},
|
||||
}
|
||||
} else {
|
||||
pbItem.Detail = &proto.Item_Material{
|
||||
Material: &proto.Material{
|
||||
Count: item.Count,
|
||||
DeleteInfo: nil,
|
||||
},
|
||||
}
|
||||
}
|
||||
playerStoreNotify.ItemList = append(playerStoreNotify.ItemList, pbItem)
|
||||
}
|
||||
g.SendMsg(cmd.PlayerStoreNotify, userId, clientSeq, playerStoreNotify)
|
||||
|
||||
// PacketAvatarDataNotify
|
||||
avatarDataNotify := new(proto.AvatarDataNotify)
|
||||
chooseAvatarId := player.TeamConfig.GetActiveAvatarId()
|
||||
avatarDataNotify.CurAvatarTeamId = uint32(player.TeamConfig.GetActiveTeamId())
|
||||
avatarDataNotify.ChooseAvatarGuid = player.AvatarMap[chooseAvatarId].Guid
|
||||
avatarDataNotify.OwnedFlycloakList = player.FlyCloakList
|
||||
// 角色衣装
|
||||
avatarDataNotify.OwnedCostumeList = player.CostumeList
|
||||
for _, avatar := range player.AvatarMap {
|
||||
pbAvatar := g.PacketAvatarInfo(avatar)
|
||||
avatarDataNotify.AvatarList = append(avatarDataNotify.AvatarList, pbAvatar)
|
||||
}
|
||||
avatarDataNotify.AvatarTeamMap = make(map[uint32]*proto.AvatarTeam)
|
||||
for teamIndex, team := range player.TeamConfig.TeamList {
|
||||
var teamAvatarGuidList []uint64 = nil
|
||||
for _, avatarId := range team.AvatarIdList {
|
||||
if avatarId == 0 {
|
||||
break
|
||||
}
|
||||
teamAvatarGuidList = append(teamAvatarGuidList, player.AvatarMap[avatarId].Guid)
|
||||
}
|
||||
avatarDataNotify.AvatarTeamMap[uint32(teamIndex)+1] = &proto.AvatarTeam{
|
||||
AvatarGuidList: teamAvatarGuidList,
|
||||
TeamName: team.Name,
|
||||
}
|
||||
}
|
||||
g.SendMsg(cmd.AvatarDataNotify, userId, clientSeq, avatarDataNotify)
|
||||
|
||||
player.SceneLoadState = model.SceneNone
|
||||
|
||||
// PacketPlayerEnterSceneNotify
|
||||
playerEnterSceneNotify := g.PacketPlayerEnterSceneNotify(player)
|
||||
g.SendMsg(cmd.PlayerEnterSceneNotify, userId, clientSeq, playerEnterSceneNotify)
|
||||
|
||||
// PacketOpenStateUpdateNotify
|
||||
openStateUpdateNotify := new(proto.OpenStateUpdateNotify)
|
||||
openStateConstMap := reflection.ConvStructToMap(constant.OpenStateConst)
|
||||
openStateUpdateNotify.OpenStateMap = make(map[uint32]uint32)
|
||||
for _, v := range openStateConstMap {
|
||||
openStateUpdateNotify.OpenStateMap[uint32(v.(uint16))] = 1
|
||||
}
|
||||
g.SendMsg(cmd.OpenStateUpdateNotify, userId, clientSeq, openStateUpdateNotify)
|
||||
}
|
||||
|
||||
func (g *GameManager) OnReg(userId uint32, clientSeq uint32, payloadMsg pb.Message) {
|
||||
logger.LOG.Debug("user reg, uid: %v", userId)
|
||||
req := payloadMsg.(*proto.SetPlayerBornDataReq)
|
||||
logger.LOG.Debug("avatar id: %v, nickname: %v", req.AvatarId, req.NickName)
|
||||
|
||||
exist, asyncWait := g.userManager.CheckUserExistOnReg(userId, req, clientSeq)
|
||||
if !asyncWait {
|
||||
g.OnRegOk(exist, req, userId, clientSeq)
|
||||
}
|
||||
}
|
||||
|
||||
func (g *GameManager) OnRegOk(exist bool, req *proto.SetPlayerBornDataReq, userId uint32, clientSeq uint32) {
|
||||
if exist {
|
||||
logger.LOG.Error("recv reg req, but user is already exist, userId: %v", userId)
|
||||
return
|
||||
}
|
||||
|
||||
nickName := req.NickName
|
||||
mainCharAvatarId := req.GetAvatarId()
|
||||
if mainCharAvatarId != 10000005 && mainCharAvatarId != 10000007 {
|
||||
logger.LOG.Error("invalid main char avatar id: %v", mainCharAvatarId)
|
||||
return
|
||||
}
|
||||
|
||||
player := g.CreatePlayer(userId, nickName, mainCharAvatarId)
|
||||
g.userManager.AddUser(player)
|
||||
|
||||
g.SendMsg(cmd.SetPlayerBornDataRsp, userId, clientSeq, new(proto.SetPlayerBornDataRsp))
|
||||
g.OnLogin(userId, clientSeq)
|
||||
}
|
||||
|
||||
func (g *GameManager) OnUserOffline(userId uint32) {
|
||||
logger.LOG.Info("user offline, uid: %v", userId)
|
||||
player := g.userManager.GetOnlineUser(userId)
|
||||
if player == nil {
|
||||
logger.LOG.Error("player is nil, userId: %v", userId)
|
||||
return
|
||||
}
|
||||
world := g.worldManager.GetWorldByID(player.WorldId)
|
||||
if world != nil {
|
||||
g.UserWorldRemovePlayer(world, player)
|
||||
}
|
||||
player.OfflineTime = uint32(time.Now().Unix())
|
||||
player.Online = false
|
||||
player.TotalOnlineTime += uint32(time.Now().UnixMilli()) - player.OnlineTime
|
||||
g.userManager.OfflineUser(player)
|
||||
}
|
||||
|
||||
func (g *GameManager) CreatePlayer(userId uint32, nickName string, mainCharAvatarId uint32) *model.Player {
|
||||
player := new(model.Player)
|
||||
player.PlayerID = userId
|
||||
player.NickName = nickName
|
||||
player.Signature = "惟愿时光记忆,一路繁花千树。"
|
||||
player.MainCharAvatarId = mainCharAvatarId
|
||||
player.HeadImage = mainCharAvatarId
|
||||
player.NameCard = 210001
|
||||
player.NameCardList = make([]uint32, 0)
|
||||
player.NameCardList = append(player.NameCardList, 210001, 210042)
|
||||
|
||||
player.FriendList = make(map[uint32]bool)
|
||||
player.FriendApplyList = make(map[uint32]bool)
|
||||
|
||||
player.RegionId = 1
|
||||
player.SceneId = 3
|
||||
|
||||
player.PropertiesMap = make(map[uint16]uint32)
|
||||
// 初始化所有属性
|
||||
propList := reflection.ConvStructToMap(constant.PlayerPropertyConst)
|
||||
for fieldName, fieldValue := range propList {
|
||||
if fieldName == "PROP_EXP" ||
|
||||
fieldName == "PROP_BREAK_LEVEL" ||
|
||||
fieldName == "PROP_SATIATION_VAL" ||
|
||||
fieldName == "PROP_SATIATION_PENALTY_TIME" ||
|
||||
fieldName == "PROP_LEVEL" {
|
||||
continue
|
||||
}
|
||||
value := fieldValue.(uint16)
|
||||
player.PropertiesMap[value] = 0
|
||||
}
|
||||
player.PropertiesMap[constant.PlayerPropertyConst.PROP_PLAYER_LEVEL] = 1
|
||||
player.PropertiesMap[constant.PlayerPropertyConst.PROP_PLAYER_WORLD_LEVEL] = 0
|
||||
player.PropertiesMap[constant.PlayerPropertyConst.PROP_IS_SPRING_AUTO_USE] = 1
|
||||
player.PropertiesMap[constant.PlayerPropertyConst.PROP_SPRING_AUTO_USE_PERCENT] = 100
|
||||
player.PropertiesMap[constant.PlayerPropertyConst.PROP_IS_FLYABLE] = 1
|
||||
player.PropertiesMap[constant.PlayerPropertyConst.PROP_IS_TRANSFERABLE] = 1
|
||||
player.PropertiesMap[constant.PlayerPropertyConst.PROP_MAX_STAMINA] = 24000
|
||||
player.PropertiesMap[constant.PlayerPropertyConst.PROP_CUR_PERSIST_STAMINA] = 24000
|
||||
player.PropertiesMap[constant.PlayerPropertyConst.PROP_PLAYER_RESIN] = 160
|
||||
player.PropertiesMap[constant.PlayerPropertyConst.PROP_PLAYER_MP_SETTING_TYPE] = 2
|
||||
player.PropertiesMap[constant.PlayerPropertyConst.PROP_IS_MP_MODE_AVAILABLE] = 1
|
||||
|
||||
player.FlyCloakList = make([]uint32, 0)
|
||||
player.FlyCloakList = append(player.FlyCloakList, 140001)
|
||||
player.FlyCloakList = append(player.FlyCloakList, 140002)
|
||||
player.FlyCloakList = append(player.FlyCloakList, 140003)
|
||||
player.FlyCloakList = append(player.FlyCloakList, 140004)
|
||||
player.FlyCloakList = append(player.FlyCloakList, 140005)
|
||||
player.FlyCloakList = append(player.FlyCloakList, 140006)
|
||||
player.FlyCloakList = append(player.FlyCloakList, 140007)
|
||||
player.FlyCloakList = append(player.FlyCloakList, 140008)
|
||||
player.FlyCloakList = append(player.FlyCloakList, 140009)
|
||||
player.FlyCloakList = append(player.FlyCloakList, 140010)
|
||||
|
||||
player.CostumeList = make([]uint32, 0)
|
||||
player.CostumeList = append(player.CostumeList, 200301)
|
||||
player.CostumeList = append(player.CostumeList, 201401)
|
||||
player.CostumeList = append(player.CostumeList, 202701)
|
||||
player.CostumeList = append(player.CostumeList, 204201)
|
||||
player.CostumeList = append(player.CostumeList, 200302)
|
||||
player.CostumeList = append(player.CostumeList, 202101)
|
||||
player.CostumeList = append(player.CostumeList, 204101)
|
||||
player.CostumeList = append(player.CostumeList, 204501)
|
||||
player.CostumeList = append(player.CostumeList, 201601)
|
||||
player.CostumeList = append(player.CostumeList, 203101)
|
||||
|
||||
player.Pos = &model.Vector{X: 2747, Y: 194, Z: -1719}
|
||||
player.Rot = &model.Vector{X: 0, Y: 307, Z: 0}
|
||||
|
||||
player.ItemMap = make(map[uint32]*model.Item)
|
||||
player.WeaponMap = make(map[uint64]*model.Weapon)
|
||||
player.ReliquaryMap = make(map[uint64]*model.Reliquary)
|
||||
player.AvatarMap = make(map[uint32]*model.Avatar)
|
||||
player.GameObjectGuidMap = make(map[uint64]model.GameObject)
|
||||
player.DropInfo = model.NewDropInfo()
|
||||
player.ChatMsgMap = make(map[uint32][]*model.ChatMsg)
|
||||
|
||||
// 选哥哥的福报
|
||||
if mainCharAvatarId == 10000005 {
|
||||
// 添加所有角色
|
||||
allAvatarDataConfig := g.GetAllAvatarDataConfig()
|
||||
for avatarId, avatarDataConfig := range allAvatarDataConfig {
|
||||
player.AddAvatar(uint32(avatarId))
|
||||
// 添加初始武器
|
||||
weaponId := uint64(g.snowflake.GenId())
|
||||
player.AddWeapon(uint32(avatarDataConfig.InitialWeapon), weaponId)
|
||||
// 角色装上初始武器
|
||||
player.WearWeapon(uint32(avatarId), weaponId)
|
||||
}
|
||||
// 添加所有武器
|
||||
allWeaponDataConfig := g.GetAllWeaponDataConfig()
|
||||
for itemId := range allWeaponDataConfig {
|
||||
weaponId := uint64(g.snowflake.GenId())
|
||||
player.AddWeapon(uint32(itemId), weaponId)
|
||||
}
|
||||
// 添加所有道具
|
||||
allItemDataConfig := g.GetAllItemDataConfig()
|
||||
for itemId := range allItemDataConfig {
|
||||
player.AddItem(uint32(itemId), 1)
|
||||
}
|
||||
}
|
||||
|
||||
// 添加选定的主角
|
||||
player.AddAvatar(mainCharAvatarId)
|
||||
// 添加初始武器
|
||||
avatarDataConfig := gdc.CONF.AvatarDataMap[int32(mainCharAvatarId)]
|
||||
weaponId := uint64(g.snowflake.GenId())
|
||||
player.AddWeapon(uint32(avatarDataConfig.InitialWeapon), weaponId)
|
||||
// 角色装上初始武器
|
||||
player.WearWeapon(mainCharAvatarId, weaponId)
|
||||
|
||||
player.TeamConfig = model.NewTeamInfo()
|
||||
player.TeamConfig.AddAvatarToTeam(mainCharAvatarId, 0)
|
||||
|
||||
return player
|
||||
}
|
||||
300
gs/game/user_manager.go
Normal file
300
gs/game/user_manager.go
Normal file
@@ -0,0 +1,300 @@
|
||||
package game
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"hk4e/gs/dao"
|
||||
"hk4e/gs/model"
|
||||
"hk4e/logger"
|
||||
"hk4e/protocol/proto"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type UserManager struct {
|
||||
dao *dao.Dao
|
||||
playerMap map[uint32]*model.Player
|
||||
playerMapLock sync.RWMutex
|
||||
localEventChan chan *LocalEvent
|
||||
}
|
||||
|
||||
func NewUserManager(dao *dao.Dao, localEventChan chan *LocalEvent) (r *UserManager) {
|
||||
r = new(UserManager)
|
||||
r.dao = dao
|
||||
r.playerMap = make(map[uint32]*model.Player)
|
||||
r.localEventChan = localEventChan
|
||||
return r
|
||||
}
|
||||
|
||||
func (u *UserManager) GetUserOnlineState(userId uint32) bool {
|
||||
u.playerMapLock.RLock()
|
||||
player, exist := u.playerMap[userId]
|
||||
u.playerMapLock.RUnlock()
|
||||
if !exist {
|
||||
return false
|
||||
} else {
|
||||
return player.Online
|
||||
}
|
||||
}
|
||||
|
||||
func (u *UserManager) GetOnlineUser(userId uint32) *model.Player {
|
||||
u.playerMapLock.RLock()
|
||||
player, exist := u.playerMap[userId]
|
||||
u.playerMapLock.RUnlock()
|
||||
if !exist {
|
||||
return nil
|
||||
} else {
|
||||
if player.Online {
|
||||
return player
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (u *UserManager) GetAllOnlineUserList() map[uint32]*model.Player {
|
||||
onlinePlayerMap := make(map[uint32]*model.Player)
|
||||
u.playerMapLock.RLock()
|
||||
for userId, player := range u.playerMap {
|
||||
if player.Online == false {
|
||||
continue
|
||||
}
|
||||
onlinePlayerMap[userId] = player
|
||||
}
|
||||
u.playerMapLock.RUnlock()
|
||||
return onlinePlayerMap
|
||||
}
|
||||
|
||||
type PlayerRegInfo struct {
|
||||
Exist bool
|
||||
Req *proto.SetPlayerBornDataReq
|
||||
UserId uint32
|
||||
ClientSeq uint32
|
||||
}
|
||||
|
||||
func (u *UserManager) CheckUserExistOnReg(userId uint32, req *proto.SetPlayerBornDataReq, clientSeq uint32) (exist bool, asyncWait bool) {
|
||||
u.playerMapLock.RLock()
|
||||
_, exist = u.playerMap[userId]
|
||||
u.playerMapLock.RUnlock()
|
||||
if exist {
|
||||
return true, false
|
||||
} else {
|
||||
go func() {
|
||||
player := u.loadUserFromDb(userId)
|
||||
exist = false
|
||||
if player != nil {
|
||||
exist = true
|
||||
}
|
||||
u.localEventChan <- &LocalEvent{
|
||||
EventId: CheckUserExistOnRegFromDbFinish,
|
||||
Msg: &PlayerRegInfo{
|
||||
Exist: exist,
|
||||
Req: req,
|
||||
UserId: userId,
|
||||
ClientSeq: clientSeq,
|
||||
},
|
||||
}
|
||||
}()
|
||||
return false, true
|
||||
}
|
||||
}
|
||||
|
||||
func (u *UserManager) LoadTempOfflineUserSync(userId uint32) *model.Player {
|
||||
u.playerMapLock.RLock()
|
||||
player, exist := u.playerMap[userId]
|
||||
u.playerMapLock.RUnlock()
|
||||
if exist {
|
||||
return player
|
||||
} else {
|
||||
player = u.loadUserFromDb(userId)
|
||||
if player == nil {
|
||||
return nil
|
||||
}
|
||||
player.DbState = model.DbOffline
|
||||
u.playerMapLock.Lock()
|
||||
u.playerMap[player.PlayerID] = player
|
||||
u.playerMapLock.Unlock()
|
||||
return player
|
||||
}
|
||||
}
|
||||
|
||||
func (u *UserManager) loadUserFromDb(userId uint32) *model.Player {
|
||||
player, err := u.dao.QueryPlayerByID(userId)
|
||||
if err != nil {
|
||||
logger.LOG.Error("query player error: %v", err)
|
||||
return nil
|
||||
}
|
||||
return player
|
||||
}
|
||||
|
||||
func (u *UserManager) AddUser(player *model.Player) {
|
||||
if player == nil {
|
||||
return
|
||||
}
|
||||
u.ChangeUserDbState(player, model.DbInsert)
|
||||
u.playerMapLock.Lock()
|
||||
u.playerMap[player.PlayerID] = player
|
||||
u.playerMapLock.Unlock()
|
||||
}
|
||||
|
||||
func (u *UserManager) DeleteUser(player *model.Player) {
|
||||
if player == nil {
|
||||
return
|
||||
}
|
||||
u.ChangeUserDbState(player, model.DbDelete)
|
||||
u.playerMapLock.Lock()
|
||||
u.playerMap[player.PlayerID] = player
|
||||
u.playerMapLock.Unlock()
|
||||
}
|
||||
|
||||
func (u *UserManager) UpdateUser(player *model.Player) {
|
||||
if player == nil {
|
||||
return
|
||||
}
|
||||
u.ChangeUserDbState(player, model.DbUpdate)
|
||||
u.playerMapLock.Lock()
|
||||
u.playerMap[player.PlayerID] = player
|
||||
u.playerMapLock.Unlock()
|
||||
}
|
||||
|
||||
type PlayerLoginInfo struct {
|
||||
UserId uint32
|
||||
Player *model.Player
|
||||
ClientSeq uint32
|
||||
}
|
||||
|
||||
func (u *UserManager) OnlineUser(userId uint32, clientSeq uint32) (*model.Player, bool) {
|
||||
u.playerMapLock.RLock()
|
||||
player, exist := u.playerMap[userId]
|
||||
u.playerMapLock.RUnlock()
|
||||
if exist {
|
||||
u.ChangeUserDbState(player, model.DbNormal)
|
||||
return player, false
|
||||
} else {
|
||||
go func() {
|
||||
player = u.loadUserFromDb(userId)
|
||||
if player != nil {
|
||||
player.DbState = model.DbNormal
|
||||
u.playerMapLock.Lock()
|
||||
u.playerMap[player.PlayerID] = player
|
||||
u.playerMapLock.Unlock()
|
||||
}
|
||||
u.localEventChan <- &LocalEvent{
|
||||
EventId: LoadLoginUserFromDbFinish,
|
||||
Msg: &PlayerLoginInfo{
|
||||
UserId: userId,
|
||||
Player: player,
|
||||
ClientSeq: clientSeq,
|
||||
},
|
||||
}
|
||||
}()
|
||||
return nil, true
|
||||
}
|
||||
}
|
||||
|
||||
func (u *UserManager) OfflineUser(player *model.Player) {
|
||||
if player == nil {
|
||||
return
|
||||
}
|
||||
u.ChangeUserDbState(player, model.DbOffline)
|
||||
u.playerMapLock.Lock()
|
||||
u.playerMap[player.PlayerID] = player
|
||||
u.playerMapLock.Unlock()
|
||||
}
|
||||
|
||||
func (u *UserManager) ChangeUserDbState(player *model.Player, state int) {
|
||||
if player == nil {
|
||||
return
|
||||
}
|
||||
switch player.DbState {
|
||||
case model.DbInsert:
|
||||
if state == model.DbDelete {
|
||||
player.DbState = model.DbDelete
|
||||
}
|
||||
case model.DbDelete:
|
||||
case model.DbUpdate:
|
||||
if state == model.DbDelete {
|
||||
player.DbState = model.DbDelete
|
||||
} else if state == model.DbOffline {
|
||||
player.DbState = model.DbOffline
|
||||
}
|
||||
case model.DbNormal:
|
||||
if state == model.DbDelete {
|
||||
player.DbState = model.DbDelete
|
||||
} else if state == model.DbUpdate {
|
||||
player.DbState = model.DbUpdate
|
||||
} else if state == model.DbOffline {
|
||||
player.DbState = model.DbOffline
|
||||
}
|
||||
case model.DbOffline:
|
||||
if state == model.DbDelete {
|
||||
player.DbState = model.DbDelete
|
||||
} else if state == model.DbUpdate {
|
||||
player.DbState = model.DbUpdate
|
||||
} else if state == model.DbNormal {
|
||||
player.DbState = model.DbNormal
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (u *UserManager) StartAutoSaveUser() {
|
||||
// 用户数据库定时同步协程
|
||||
go func() {
|
||||
ticker := time.NewTicker(time.Minute * 5)
|
||||
for {
|
||||
logger.LOG.Info("auto save user start")
|
||||
playerMapTemp := make(map[uint32]*model.Player)
|
||||
u.playerMapLock.RLock()
|
||||
for k, v := range u.playerMap {
|
||||
playerMapTemp[k] = v
|
||||
}
|
||||
u.playerMapLock.RUnlock()
|
||||
logger.LOG.Info("copy user map finish")
|
||||
insertList := make([]*model.Player, 0)
|
||||
deleteList := make([]uint32, 0)
|
||||
updateList := make([]*model.Player, 0)
|
||||
for k, v := range playerMapTemp {
|
||||
switch v.DbState {
|
||||
case model.DbInsert:
|
||||
insertList = append(insertList, v)
|
||||
playerMapTemp[k].DbState = model.DbNormal
|
||||
case model.DbDelete:
|
||||
deleteList = append(deleteList, v.PlayerID)
|
||||
delete(playerMapTemp, k)
|
||||
case model.DbUpdate:
|
||||
updateList = append(updateList, v)
|
||||
playerMapTemp[k].DbState = model.DbNormal
|
||||
case model.DbNormal:
|
||||
continue
|
||||
case model.DbOffline:
|
||||
updateList = append(updateList, v)
|
||||
delete(playerMapTemp, k)
|
||||
}
|
||||
}
|
||||
insertListJson, err := json.Marshal(insertList)
|
||||
logger.LOG.Debug("insertList: %v", string(insertListJson))
|
||||
deleteListJson, err := json.Marshal(deleteList)
|
||||
logger.LOG.Debug("deleteList: %v", string(deleteListJson))
|
||||
updateListJson, err := json.Marshal(updateList)
|
||||
logger.LOG.Debug("updateList: %v", string(updateListJson))
|
||||
logger.LOG.Info("db state init finish")
|
||||
err = u.dao.InsertPlayerList(insertList)
|
||||
if err != nil {
|
||||
logger.LOG.Error("insert player list error: %v", err)
|
||||
}
|
||||
err = u.dao.DeletePlayerList(deleteList)
|
||||
if err != nil {
|
||||
logger.LOG.Error("delete player error: %v", err)
|
||||
}
|
||||
err = u.dao.UpdatePlayerList(updateList)
|
||||
if err != nil {
|
||||
logger.LOG.Error("update player error: %v", err)
|
||||
}
|
||||
logger.LOG.Info("db write finish")
|
||||
u.playerMapLock.Lock()
|
||||
u.playerMap = playerMapTemp
|
||||
u.playerMapLock.Unlock()
|
||||
logger.LOG.Info("auto save user finish")
|
||||
<-ticker.C
|
||||
}
|
||||
}()
|
||||
}
|
||||
192
gs/game/user_map.go
Normal file
192
gs/game/user_map.go
Normal file
@@ -0,0 +1,192 @@
|
||||
package game
|
||||
|
||||
import (
|
||||
pb "google.golang.org/protobuf/proto"
|
||||
gdc "hk4e/gs/config"
|
||||
"hk4e/gs/constant"
|
||||
"hk4e/gs/model"
|
||||
"hk4e/logger"
|
||||
"hk4e/protocol/cmd"
|
||||
"hk4e/protocol/proto"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func (g *GameManager) SceneTransToPointReq(player *model.Player, payloadMsg pb.Message) {
|
||||
logger.LOG.Debug("user get scene trans to point, uid: %v", player.PlayerID)
|
||||
req := payloadMsg.(*proto.SceneTransToPointReq)
|
||||
|
||||
transPointId := strconv.Itoa(int(req.SceneId)) + "_" + strconv.Itoa(int(req.PointId))
|
||||
transPointConfig, exist := gdc.CONF.ScenePointEntries[transPointId]
|
||||
if !exist {
|
||||
// PacketSceneTransToPointRsp
|
||||
sceneTransToPointRsp := new(proto.SceneTransToPointRsp)
|
||||
sceneTransToPointRsp.Retcode = int32(proto.Retcode_RETCODE_RET_SVR_ERROR)
|
||||
g.SendMsg(cmd.SceneTransToPointRsp, player.PlayerID, player.ClientSeq, sceneTransToPointRsp)
|
||||
return
|
||||
}
|
||||
|
||||
// 传送玩家
|
||||
newSceneId := req.SceneId
|
||||
oldSceneId := player.SceneId
|
||||
oldPos := &model.Vector{
|
||||
X: player.Pos.X,
|
||||
Y: player.Pos.Y,
|
||||
Z: player.Pos.Z,
|
||||
}
|
||||
jumpScene := false
|
||||
if newSceneId != oldSceneId {
|
||||
jumpScene = true
|
||||
}
|
||||
world := g.worldManager.GetWorldByID(player.WorldId)
|
||||
oldScene := world.GetSceneById(oldSceneId)
|
||||
activeAvatarId := player.TeamConfig.GetActiveAvatarId()
|
||||
playerTeamEntity := oldScene.GetPlayerTeamEntity(player.PlayerID)
|
||||
g.RemoveSceneEntityNotifyBroadcast(oldScene, []uint32{playerTeamEntity.avatarEntityMap[activeAvatarId]})
|
||||
if jumpScene {
|
||||
// PacketDelTeamEntityNotify
|
||||
delTeamEntityNotify := g.PacketDelTeamEntityNotify(oldScene, player)
|
||||
g.SendMsg(cmd.DelTeamEntityNotify, player.PlayerID, player.ClientSeq, delTeamEntityNotify)
|
||||
|
||||
oldScene.RemovePlayer(player)
|
||||
newScene := world.GetSceneById(newSceneId)
|
||||
newScene.AddPlayer(player)
|
||||
} else {
|
||||
oldScene.UpdatePlayerTeamEntity(player)
|
||||
}
|
||||
player.Pos.X = transPointConfig.PointData.TranPos.X
|
||||
player.Pos.Y = transPointConfig.PointData.TranPos.Y
|
||||
player.Pos.Z = transPointConfig.PointData.TranPos.Z
|
||||
player.SceneId = newSceneId
|
||||
player.SceneLoadState = model.SceneNone
|
||||
|
||||
// PacketPlayerEnterSceneNotify
|
||||
var enterType proto.EnterType
|
||||
if jumpScene {
|
||||
logger.LOG.Debug("player jump scene, scene: %v, pos: %v", player.SceneId, player.Pos)
|
||||
enterType = proto.EnterType_ENTER_TYPE_JUMP
|
||||
} else {
|
||||
logger.LOG.Debug("player goto scene, scene: %v, pos: %v", player.SceneId, player.Pos)
|
||||
enterType = proto.EnterType_ENTER_TYPE_GOTO
|
||||
}
|
||||
playerEnterSceneNotify := g.PacketPlayerEnterSceneNotifyTp(player, enterType, uint32(constant.EnterReasonConst.TransPoint), oldSceneId, oldPos)
|
||||
g.SendMsg(cmd.PlayerEnterSceneNotify, player.PlayerID, player.ClientSeq, playerEnterSceneNotify)
|
||||
|
||||
// PacketSceneTransToPointRsp
|
||||
sceneTransToPointRsp := new(proto.SceneTransToPointRsp)
|
||||
sceneTransToPointRsp.Retcode = 0
|
||||
sceneTransToPointRsp.PointId = req.PointId
|
||||
sceneTransToPointRsp.SceneId = req.SceneId
|
||||
g.SendMsg(cmd.SceneTransToPointRsp, player.PlayerID, player.ClientSeq, sceneTransToPointRsp)
|
||||
}
|
||||
|
||||
func (g *GameManager) MarkMapReq(player *model.Player, payloadMsg pb.Message) {
|
||||
logger.LOG.Debug("user mark map, uid: %v", player.PlayerID)
|
||||
req := payloadMsg.(*proto.MarkMapReq)
|
||||
operation := req.Op
|
||||
if operation == proto.MarkMapReq_OPERATION_ADD {
|
||||
logger.LOG.Debug("user mark type: %v", req.Mark.PointType)
|
||||
if req.Mark.PointType == proto.MapMarkPointType_MAP_MARK_POINT_TYPE_NPC {
|
||||
posYInt, err := strconv.ParseInt(req.Mark.Name, 10, 64)
|
||||
if err != nil {
|
||||
logger.LOG.Error("parse pos y error: %v", err)
|
||||
posYInt = 0
|
||||
}
|
||||
|
||||
// 传送玩家
|
||||
newSceneId := req.Mark.SceneId
|
||||
oldSceneId := player.SceneId
|
||||
oldPos := &model.Vector{
|
||||
X: player.Pos.X,
|
||||
Y: player.Pos.Y,
|
||||
Z: player.Pos.Z,
|
||||
}
|
||||
jumpScene := false
|
||||
if newSceneId != oldSceneId {
|
||||
jumpScene = true
|
||||
}
|
||||
world := g.worldManager.GetWorldByID(player.WorldId)
|
||||
oldScene := world.GetSceneById(oldSceneId)
|
||||
activeAvatarId := player.TeamConfig.GetActiveAvatarId()
|
||||
playerTeamEntity := oldScene.GetPlayerTeamEntity(player.PlayerID)
|
||||
g.RemoveSceneEntityNotifyBroadcast(oldScene, []uint32{playerTeamEntity.avatarEntityMap[activeAvatarId]})
|
||||
if jumpScene {
|
||||
// PacketDelTeamEntityNotify
|
||||
delTeamEntityNotify := g.PacketDelTeamEntityNotify(oldScene, player)
|
||||
g.SendMsg(cmd.DelTeamEntityNotify, player.PlayerID, player.ClientSeq, delTeamEntityNotify)
|
||||
|
||||
oldScene.RemovePlayer(player)
|
||||
newScene := world.GetSceneById(newSceneId)
|
||||
newScene.AddPlayer(player)
|
||||
} else {
|
||||
oldScene.UpdatePlayerTeamEntity(player)
|
||||
}
|
||||
player.Pos.X = float64(req.Mark.Pos.X)
|
||||
player.Pos.Y = float64(posYInt)
|
||||
player.Pos.Z = float64(req.Mark.Pos.Z)
|
||||
player.SceneId = newSceneId
|
||||
player.SceneLoadState = model.SceneNone
|
||||
|
||||
// PacketPlayerEnterSceneNotify
|
||||
var enterType proto.EnterType
|
||||
if jumpScene {
|
||||
logger.LOG.Debug("player jump scene, scene: %v, pos: %v", player.SceneId, player.Pos)
|
||||
enterType = proto.EnterType_ENTER_TYPE_JUMP
|
||||
} else {
|
||||
logger.LOG.Debug("player goto scene, scene: %v, pos: %v", player.SceneId, player.Pos)
|
||||
enterType = proto.EnterType_ENTER_TYPE_GOTO
|
||||
}
|
||||
playerEnterSceneNotify := g.PacketPlayerEnterSceneNotifyTp(player, enterType, uint32(constant.EnterReasonConst.TransPoint), oldSceneId, oldPos)
|
||||
g.SendMsg(cmd.PlayerEnterSceneNotify, player.PlayerID, player.ClientSeq, playerEnterSceneNotify)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (g *GameManager) PathfindingEnterSceneReq(player *model.Player, payloadMsg pb.Message) {
|
||||
logger.LOG.Debug("user pathfinding enter scene, uid: %v", player.PlayerID)
|
||||
g.SendMsg(cmd.PathfindingEnterSceneRsp, player.PlayerID, player.ClientSeq, new(proto.PathfindingEnterSceneRsp))
|
||||
}
|
||||
|
||||
func (g *GameManager) QueryPathReq(player *model.Player, payloadMsg pb.Message) {
|
||||
//logger.LOG.Debug("user query path, uid: %v", player.PlayerID)
|
||||
req := payloadMsg.(*proto.QueryPathReq)
|
||||
|
||||
// PacketQueryPathRsp
|
||||
queryPathRsp := new(proto.QueryPathRsp)
|
||||
queryPathRsp.Corners = []*proto.Vector{req.DestinationPos[0]}
|
||||
queryPathRsp.QueryId = req.QueryId
|
||||
queryPathRsp.QueryStatus = proto.QueryPathRsp_PATH_STATUS_TYPE_SUCC
|
||||
g.SendMsg(cmd.QueryPathRsp, player.PlayerID, player.ClientSeq, queryPathRsp)
|
||||
}
|
||||
|
||||
func (g *GameManager) GetScenePointReq(player *model.Player, payloadMsg pb.Message) {
|
||||
logger.LOG.Debug("user get scene point, uid: %v", player.PlayerID)
|
||||
req := payloadMsg.(*proto.GetScenePointReq)
|
||||
|
||||
// PacketGetScenePointRsp
|
||||
getScenePointRsp := new(proto.GetScenePointRsp)
|
||||
getScenePointRsp.SceneId = req.SceneId
|
||||
getScenePointRsp.UnlockedPointList = make([]uint32, 0)
|
||||
for i := uint32(1); i < 1000; i++ {
|
||||
getScenePointRsp.UnlockedPointList = append(getScenePointRsp.UnlockedPointList, i)
|
||||
}
|
||||
getScenePointRsp.UnlockAreaList = make([]uint32, 0)
|
||||
for i := uint32(1); i < 9; i++ {
|
||||
getScenePointRsp.UnlockAreaList = append(getScenePointRsp.UnlockAreaList, i)
|
||||
}
|
||||
g.SendMsg(cmd.GetScenePointRsp, player.PlayerID, player.ClientSeq, getScenePointRsp)
|
||||
}
|
||||
|
||||
func (g *GameManager) GetSceneAreaReq(player *model.Player, payloadMsg pb.Message) {
|
||||
logger.LOG.Debug("user get scene area, uid: %v", player.PlayerID)
|
||||
req := payloadMsg.(*proto.GetSceneAreaReq)
|
||||
|
||||
// PacketGetSceneAreaRsp
|
||||
getSceneAreaRsp := new(proto.GetSceneAreaRsp)
|
||||
getSceneAreaRsp.SceneId = req.SceneId
|
||||
getSceneAreaRsp.AreaIdList = []uint32{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 17, 18, 19, 20, 21, 22, 23, 24, 25, 100, 101, 102, 103, 200, 210, 300, 400, 401, 402, 403}
|
||||
getSceneAreaRsp.CityInfoList = make([]*proto.CityInfo, 0)
|
||||
getSceneAreaRsp.CityInfoList = append(getSceneAreaRsp.CityInfoList, &proto.CityInfo{CityId: 1, Level: 1})
|
||||
getSceneAreaRsp.CityInfoList = append(getSceneAreaRsp.CityInfoList, &proto.CityInfo{CityId: 2, Level: 1})
|
||||
getSceneAreaRsp.CityInfoList = append(getSceneAreaRsp.CityInfoList, &proto.CityInfo{CityId: 3, Level: 1})
|
||||
g.SendMsg(cmd.GetSceneAreaRsp, player.PlayerID, player.ClientSeq, getSceneAreaRsp)
|
||||
}
|
||||
417
gs/game/user_multiplayer.go
Normal file
417
gs/game/user_multiplayer.go
Normal file
@@ -0,0 +1,417 @@
|
||||
package game
|
||||
|
||||
import (
|
||||
pb "google.golang.org/protobuf/proto"
|
||||
"hk4e/gs/constant"
|
||||
"hk4e/gs/model"
|
||||
"hk4e/logger"
|
||||
"hk4e/protocol/cmd"
|
||||
"hk4e/protocol/proto"
|
||||
"time"
|
||||
)
|
||||
|
||||
func (g *GameManager) PlayerApplyEnterMpReq(player *model.Player, payloadMsg pb.Message) {
|
||||
logger.LOG.Debug("user apply enter world, uid: %v", player.PlayerID)
|
||||
req := payloadMsg.(*proto.PlayerApplyEnterMpReq)
|
||||
targetUid := req.TargetUid
|
||||
|
||||
// PacketPlayerApplyEnterMpRsp
|
||||
playerApplyEnterMpRsp := new(proto.PlayerApplyEnterMpRsp)
|
||||
playerApplyEnterMpRsp.TargetUid = targetUid
|
||||
g.SendMsg(cmd.PlayerApplyEnterMpRsp, player.PlayerID, player.ClientSeq, playerApplyEnterMpRsp)
|
||||
|
||||
ok := g.UserApplyEnterWorld(player, targetUid)
|
||||
if !ok {
|
||||
// PacketPlayerApplyEnterMpResultNotify
|
||||
playerApplyEnterMpResultNotify := new(proto.PlayerApplyEnterMpResultNotify)
|
||||
playerApplyEnterMpResultNotify.TargetUid = targetUid
|
||||
playerApplyEnterMpResultNotify.TargetNickname = ""
|
||||
playerApplyEnterMpResultNotify.IsAgreed = false
|
||||
playerApplyEnterMpResultNotify.Reason = proto.PlayerApplyEnterMpResultNotify_REASON_PLAYER_CANNOT_ENTER_MP
|
||||
g.SendMsg(cmd.PlayerApplyEnterMpResultNotify, player.PlayerID, player.ClientSeq, playerApplyEnterMpResultNotify)
|
||||
}
|
||||
}
|
||||
|
||||
func (g *GameManager) PlayerApplyEnterMpResultReq(player *model.Player, payloadMsg pb.Message) {
|
||||
logger.LOG.Debug("user deal world enter apply, uid: %v", player.PlayerID)
|
||||
req := payloadMsg.(*proto.PlayerApplyEnterMpResultReq)
|
||||
applyUid := req.ApplyUid
|
||||
isAgreed := req.IsAgreed
|
||||
|
||||
g.UserDealEnterWorld(player, applyUid, isAgreed)
|
||||
|
||||
// PacketPlayerApplyEnterMpResultRsp
|
||||
playerApplyEnterMpResultRsp := new(proto.PlayerApplyEnterMpResultRsp)
|
||||
playerApplyEnterMpResultRsp.ApplyUid = applyUid
|
||||
playerApplyEnterMpResultRsp.IsAgreed = isAgreed
|
||||
g.SendMsg(cmd.PlayerApplyEnterMpResultRsp, player.PlayerID, player.ClientSeq, playerApplyEnterMpResultRsp)
|
||||
}
|
||||
|
||||
func (g *GameManager) PlayerGetForceQuitBanInfoReq(player *model.Player, payloadMsg pb.Message) {
|
||||
logger.LOG.Debug("user get world exit ban info, uid: %v", player.PlayerID)
|
||||
|
||||
result := true
|
||||
world := g.worldManager.GetWorldByID(player.WorldId)
|
||||
for _, worldPlayer := range world.playerMap {
|
||||
if worldPlayer.SceneLoadState != model.SceneEnterDone {
|
||||
result = false
|
||||
}
|
||||
}
|
||||
|
||||
// PacketPlayerGetForceQuitBanInfoRsp
|
||||
playerGetForceQuitBanInfoRsp := new(proto.PlayerGetForceQuitBanInfoRsp)
|
||||
if result {
|
||||
playerGetForceQuitBanInfoRsp.Retcode = int32(proto.Retcode_RETCODE_RET_SUCC)
|
||||
} else {
|
||||
playerGetForceQuitBanInfoRsp.Retcode = int32(proto.Retcode_RETCODE_RET_MP_TARGET_PLAYER_IN_TRANSFER)
|
||||
}
|
||||
g.SendMsg(cmd.PlayerGetForceQuitBanInfoRsp, player.PlayerID, player.ClientSeq, playerGetForceQuitBanInfoRsp)
|
||||
}
|
||||
|
||||
func (g *GameManager) BackMyWorldReq(player *model.Player, payloadMsg pb.Message) {
|
||||
logger.LOG.Debug("user back world, uid: %v", player.PlayerID)
|
||||
|
||||
// 其他玩家
|
||||
ok := g.UserLeaveWorld(player)
|
||||
|
||||
// PacketBackMyWorldRsp
|
||||
backMyWorldRsp := new(proto.BackMyWorldRsp)
|
||||
if ok {
|
||||
backMyWorldRsp.Retcode = int32(proto.Retcode_RETCODE_RET_SUCC)
|
||||
} else {
|
||||
backMyWorldRsp.Retcode = int32(proto.Retcode_RETCODE_RET_MP_TARGET_PLAYER_IN_TRANSFER)
|
||||
}
|
||||
g.SendMsg(cmd.BackMyWorldRsp, player.PlayerID, player.ClientSeq, backMyWorldRsp)
|
||||
}
|
||||
|
||||
func (g *GameManager) ChangeWorldToSingleModeReq(player *model.Player, payloadMsg pb.Message) {
|
||||
logger.LOG.Debug("user change world to single, uid: %v", player.PlayerID)
|
||||
|
||||
// 房主
|
||||
ok := g.UserLeaveWorld(player)
|
||||
|
||||
// PacketChangeWorldToSingleModeRsp
|
||||
changeWorldToSingleModeRsp := new(proto.ChangeWorldToSingleModeRsp)
|
||||
if ok {
|
||||
changeWorldToSingleModeRsp.Retcode = int32(proto.Retcode_RETCODE_RET_SUCC)
|
||||
} else {
|
||||
changeWorldToSingleModeRsp.Retcode = int32(proto.Retcode_RETCODE_RET_MP_TARGET_PLAYER_IN_TRANSFER)
|
||||
}
|
||||
g.SendMsg(cmd.ChangeWorldToSingleModeRsp, player.PlayerID, player.ClientSeq, changeWorldToSingleModeRsp)
|
||||
}
|
||||
|
||||
func (g *GameManager) SceneKickPlayerReq(player *model.Player, payloadMsg pb.Message) {
|
||||
logger.LOG.Debug("user kick player, uid: %v", player.PlayerID)
|
||||
req := payloadMsg.(*proto.SceneKickPlayerReq)
|
||||
targetUid := req.TargetUid
|
||||
|
||||
targetPlayer := g.userManager.GetOnlineUser(targetUid)
|
||||
ok := g.UserLeaveWorld(targetPlayer)
|
||||
if ok {
|
||||
// PacketSceneKickPlayerNotify
|
||||
sceneKickPlayerNotify := new(proto.SceneKickPlayerNotify)
|
||||
sceneKickPlayerNotify.TargetUid = targetUid
|
||||
sceneKickPlayerNotify.KickerUid = player.PlayerID
|
||||
world := g.worldManager.GetWorldByID(player.WorldId)
|
||||
for _, worldPlayer := range world.playerMap {
|
||||
g.SendMsg(cmd.SceneKickPlayerNotify, worldPlayer.PlayerID, worldPlayer.ClientSeq, sceneKickPlayerNotify)
|
||||
}
|
||||
}
|
||||
|
||||
// PacketSceneKickPlayerRsp
|
||||
sceneKickPlayerRsp := new(proto.SceneKickPlayerRsp)
|
||||
if ok {
|
||||
sceneKickPlayerRsp.TargetUid = targetUid
|
||||
} else {
|
||||
sceneKickPlayerRsp.Retcode = int32(proto.Retcode_RETCODE_RET_MP_TARGET_PLAYER_IN_TRANSFER)
|
||||
}
|
||||
g.SendMsg(cmd.SceneKickPlayerRsp, player.PlayerID, player.ClientSeq, sceneKickPlayerRsp)
|
||||
}
|
||||
|
||||
func (g *GameManager) UserApplyEnterWorld(player *model.Player, targetUid uint32) bool {
|
||||
targetPlayer := g.userManager.GetOnlineUser(targetUid)
|
||||
if targetPlayer == nil {
|
||||
return false
|
||||
}
|
||||
world := g.worldManager.GetWorldByID(player.WorldId)
|
||||
if world.multiplayer {
|
||||
return false
|
||||
}
|
||||
applyTime, exist := targetPlayer.CoopApplyMap[player.PlayerID]
|
||||
if exist && time.Now().UnixNano() < applyTime+int64(10*time.Second) {
|
||||
return false
|
||||
}
|
||||
targetPlayer.CoopApplyMap[player.PlayerID] = time.Now().UnixNano()
|
||||
targetWorld := g.worldManager.GetWorldByID(targetPlayer.WorldId)
|
||||
if targetWorld.multiplayer && targetWorld.owner.PlayerID != targetPlayer.PlayerID {
|
||||
return false
|
||||
}
|
||||
|
||||
// PacketPlayerApplyEnterMpNotify
|
||||
playerApplyEnterMpNotify := new(proto.PlayerApplyEnterMpNotify)
|
||||
playerApplyEnterMpNotify.SrcPlayerInfo = g.PacketOnlinePlayerInfo(player)
|
||||
g.SendMsg(cmd.PlayerApplyEnterMpNotify, targetPlayer.PlayerID, targetPlayer.ClientSeq, playerApplyEnterMpNotify)
|
||||
return true
|
||||
}
|
||||
|
||||
func (g *GameManager) UserDealEnterWorld(hostPlayer *model.Player, otherUid uint32, agree bool) {
|
||||
otherPlayer := g.userManager.GetOnlineUser(otherUid)
|
||||
if otherPlayer == nil {
|
||||
return
|
||||
}
|
||||
applyTime, exist := hostPlayer.CoopApplyMap[otherUid]
|
||||
if !exist || time.Now().UnixNano() > applyTime+int64(10*time.Second) {
|
||||
return
|
||||
}
|
||||
delete(hostPlayer.CoopApplyMap, otherUid)
|
||||
otherPlayerWorld := g.worldManager.GetWorldByID(otherPlayer.WorldId)
|
||||
if otherPlayerWorld.multiplayer {
|
||||
// PacketPlayerApplyEnterMpResultNotify
|
||||
playerApplyEnterMpResultNotify := new(proto.PlayerApplyEnterMpResultNotify)
|
||||
playerApplyEnterMpResultNotify.TargetUid = hostPlayer.PlayerID
|
||||
playerApplyEnterMpResultNotify.TargetNickname = hostPlayer.NickName
|
||||
playerApplyEnterMpResultNotify.IsAgreed = false
|
||||
playerApplyEnterMpResultNotify.Reason = proto.PlayerApplyEnterMpResultNotify_REASON_PLAYER_CANNOT_ENTER_MP
|
||||
g.SendMsg(cmd.PlayerApplyEnterMpResultNotify, otherPlayer.PlayerID, otherPlayer.ClientSeq, playerApplyEnterMpResultNotify)
|
||||
return
|
||||
}
|
||||
|
||||
// PacketPlayerApplyEnterMpResultNotify
|
||||
playerApplyEnterMpResultNotify := new(proto.PlayerApplyEnterMpResultNotify)
|
||||
playerApplyEnterMpResultNotify.TargetUid = hostPlayer.PlayerID
|
||||
playerApplyEnterMpResultNotify.TargetNickname = hostPlayer.NickName
|
||||
playerApplyEnterMpResultNotify.IsAgreed = agree
|
||||
playerApplyEnterMpResultNotify.Reason = proto.PlayerApplyEnterMpResultNotify_REASON_PLAYER_JUDGE
|
||||
g.SendMsg(cmd.PlayerApplyEnterMpResultNotify, otherPlayer.PlayerID, otherPlayer.ClientSeq, playerApplyEnterMpResultNotify)
|
||||
|
||||
if !agree {
|
||||
return
|
||||
}
|
||||
|
||||
hostWorld := g.worldManager.GetWorldByID(hostPlayer.WorldId)
|
||||
if hostWorld.multiplayer == false {
|
||||
g.UserWorldRemovePlayer(hostWorld, hostPlayer)
|
||||
|
||||
hostPlayer.TeamConfig.CurrTeamIndex = 3
|
||||
hostPlayer.TeamConfig.CurrAvatarIndex = 0
|
||||
|
||||
// PacketPlayerEnterSceneNotify
|
||||
hostPlayerEnterSceneNotify := g.PacketPlayerEnterSceneNotifyMp(
|
||||
hostPlayer,
|
||||
hostPlayer,
|
||||
proto.EnterType_ENTER_TYPE_SELF,
|
||||
uint32(constant.EnterReasonConst.HostFromSingleToMp),
|
||||
hostPlayer.SceneId,
|
||||
hostPlayer.Pos,
|
||||
)
|
||||
g.SendMsg(cmd.PlayerEnterSceneNotify, hostPlayer.PlayerID, hostPlayer.ClientSeq, hostPlayerEnterSceneNotify)
|
||||
|
||||
hostWorld = g.worldManager.CreateWorld(hostPlayer, true)
|
||||
g.UserWorldAddPlayer(hostWorld, hostPlayer)
|
||||
hostPlayer.SceneLoadState = model.SceneNone
|
||||
}
|
||||
|
||||
otherWorld := g.worldManager.GetWorldByID(otherPlayer.WorldId)
|
||||
g.UserWorldRemovePlayer(otherWorld, otherPlayer)
|
||||
|
||||
otherPlayerOldSceneId := otherPlayer.SceneId
|
||||
otherPlayerOldPos := &model.Vector{
|
||||
X: otherPlayer.Pos.X,
|
||||
Y: otherPlayer.Pos.Y,
|
||||
Z: otherPlayer.Pos.Z,
|
||||
}
|
||||
|
||||
otherPlayer.Pos = &model.Vector{
|
||||
X: hostPlayer.Pos.X,
|
||||
Y: hostPlayer.Pos.Y + 1,
|
||||
Z: hostPlayer.Pos.Z,
|
||||
}
|
||||
otherPlayer.Rot = &model.Vector{
|
||||
X: hostPlayer.Rot.X,
|
||||
Y: hostPlayer.Rot.Y,
|
||||
Z: hostPlayer.Rot.Z,
|
||||
}
|
||||
otherPlayer.SceneId = hostPlayer.SceneId
|
||||
otherPlayer.TeamConfig.CurrTeamIndex = 3
|
||||
otherPlayer.TeamConfig.CurrAvatarIndex = 0
|
||||
|
||||
// PacketPlayerEnterSceneNotify
|
||||
playerEnterSceneNotify := g.PacketPlayerEnterSceneNotifyMp(
|
||||
otherPlayer,
|
||||
hostPlayer,
|
||||
proto.EnterType_ENTER_TYPE_OTHER,
|
||||
uint32(constant.EnterReasonConst.TeamJoin),
|
||||
otherPlayerOldSceneId,
|
||||
otherPlayerOldPos,
|
||||
)
|
||||
g.SendMsg(cmd.PlayerEnterSceneNotify, otherPlayer.PlayerID, otherPlayer.ClientSeq, playerEnterSceneNotify)
|
||||
|
||||
g.UserWorldAddPlayer(hostWorld, otherPlayer)
|
||||
otherPlayer.SceneLoadState = model.SceneNone
|
||||
}
|
||||
|
||||
func (g *GameManager) UserLeaveWorld(player *model.Player) bool {
|
||||
oldWorld := g.worldManager.GetWorldByID(player.WorldId)
|
||||
if !oldWorld.multiplayer {
|
||||
return false
|
||||
}
|
||||
for _, worldPlayer := range oldWorld.playerMap {
|
||||
if worldPlayer.SceneLoadState != model.SceneEnterDone {
|
||||
return false
|
||||
}
|
||||
}
|
||||
g.UserWorldRemovePlayer(oldWorld, player)
|
||||
//{
|
||||
// newWorld := g.worldManager.CreateWorld(player, false)
|
||||
// g.UserWorldAddPlayer(newWorld, player)
|
||||
// player.SceneLoadState = model.SceneNone
|
||||
//
|
||||
// // PacketPlayerEnterSceneNotify
|
||||
// enterReasonConst := constant.GetEnterReasonConst()
|
||||
// playerEnterSceneNotify := g.PacketPlayerEnterSceneNotifyMp(
|
||||
// player,
|
||||
// player,
|
||||
// proto.EnterType_ENTER_TYPE_SELF,
|
||||
// uint32(enterReasonConst.TeamBack),
|
||||
// player.SceneId,
|
||||
// player.Pos,
|
||||
// )
|
||||
// g.SendMsg(cmd.PlayerEnterSceneNotify, player.PlayerID, player.ClientSeq, playerEnterSceneNotify)
|
||||
//}
|
||||
{
|
||||
// PacketClientReconnectNotify
|
||||
g.SendMsg(cmd.ClientReconnectNotify, player.PlayerID, 0, new(proto.ClientReconnectNotify))
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (g *GameManager) UserWorldAddPlayer(world *World, player *model.Player) {
|
||||
_, exist := world.playerMap[player.PlayerID]
|
||||
if exist {
|
||||
return
|
||||
}
|
||||
world.AddPlayer(player, player.SceneId)
|
||||
player.WorldId = world.id
|
||||
if len(world.playerMap) > 1 {
|
||||
g.UpdateWorldPlayerInfo(world, player)
|
||||
}
|
||||
}
|
||||
|
||||
func (g *GameManager) UserWorldRemovePlayer(world *World, player *model.Player) {
|
||||
if world.multiplayer && player.PlayerID == world.owner.PlayerID {
|
||||
// 多人世界房主离开剔除所有其他玩家
|
||||
for _, worldPlayer := range world.playerMap {
|
||||
if worldPlayer.PlayerID == world.owner.PlayerID {
|
||||
continue
|
||||
}
|
||||
if ok := g.UserLeaveWorld(worldPlayer); !ok {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// PacketDelTeamEntityNotify
|
||||
scene := world.GetSceneById(player.SceneId)
|
||||
delTeamEntityNotify := g.PacketDelTeamEntityNotify(scene, player)
|
||||
g.SendMsg(cmd.DelTeamEntityNotify, player.PlayerID, player.ClientSeq, delTeamEntityNotify)
|
||||
|
||||
if world.multiplayer {
|
||||
// PlayerQuitFromMpNotify
|
||||
playerQuitFromMpNotify := new(proto.PlayerQuitFromMpNotify)
|
||||
playerQuitFromMpNotify.Reason = proto.PlayerQuitFromMpNotify_QUIT_REASON_BACK_TO_MY_WORLD
|
||||
g.SendMsg(cmd.PlayerQuitFromMpNotify, player.PlayerID, player.ClientSeq, playerQuitFromMpNotify)
|
||||
|
||||
activeAvatarId := player.TeamConfig.GetActiveAvatarId()
|
||||
playerTeamEntity := scene.GetPlayerTeamEntity(player.PlayerID)
|
||||
g.RemoveSceneEntityNotifyBroadcast(scene, []uint32{playerTeamEntity.avatarEntityMap[activeAvatarId]})
|
||||
}
|
||||
|
||||
world.RemovePlayer(player)
|
||||
player.WorldId = 0
|
||||
|
||||
if world.multiplayer && len(world.playerMap) > 0 {
|
||||
g.UpdateWorldPlayerInfo(world, player)
|
||||
}
|
||||
|
||||
if world.owner.PlayerID == player.PlayerID {
|
||||
// 房主离开销毁世界
|
||||
g.worldManager.DestroyWorld(world.id)
|
||||
}
|
||||
}
|
||||
|
||||
func (g *GameManager) UpdateWorldPlayerInfo(hostWorld *World, excludePlayer *model.Player) {
|
||||
for _, worldPlayer := range hostWorld.playerMap {
|
||||
if worldPlayer.PlayerID == excludePlayer.PlayerID || worldPlayer.SceneLoadState == model.SceneNone {
|
||||
continue
|
||||
}
|
||||
|
||||
// PacketSceneTeamUpdateNotify
|
||||
sceneTeamUpdateNotify := g.PacketSceneTeamUpdateNotify(hostWorld)
|
||||
g.SendMsg(cmd.SceneTeamUpdateNotify, worldPlayer.PlayerID, worldPlayer.ClientSeq, sceneTeamUpdateNotify)
|
||||
|
||||
// PacketWorldPlayerInfoNotify
|
||||
worldPlayerInfoNotify := new(proto.WorldPlayerInfoNotify)
|
||||
for _, subWorldPlayer := range hostWorld.playerMap {
|
||||
onlinePlayerInfo := new(proto.OnlinePlayerInfo)
|
||||
onlinePlayerInfo.Uid = subWorldPlayer.PlayerID
|
||||
onlinePlayerInfo.Nickname = subWorldPlayer.NickName
|
||||
onlinePlayerInfo.PlayerLevel = subWorldPlayer.PropertiesMap[constant.PlayerPropertyConst.PROP_PLAYER_LEVEL]
|
||||
onlinePlayerInfo.MpSettingType = proto.MpSettingType(subWorldPlayer.PropertiesMap[constant.PlayerPropertyConst.PROP_PLAYER_MP_SETTING_TYPE])
|
||||
onlinePlayerInfo.NameCardId = subWorldPlayer.NameCard
|
||||
onlinePlayerInfo.Signature = subWorldPlayer.Signature
|
||||
onlinePlayerInfo.ProfilePicture = &proto.ProfilePicture{AvatarId: subWorldPlayer.HeadImage}
|
||||
onlinePlayerInfo.CurPlayerNumInWorld = uint32(len(hostWorld.playerMap))
|
||||
worldPlayerInfoNotify.PlayerInfoList = append(worldPlayerInfoNotify.PlayerInfoList, onlinePlayerInfo)
|
||||
worldPlayerInfoNotify.PlayerUidList = append(worldPlayerInfoNotify.PlayerUidList, subWorldPlayer.PlayerID)
|
||||
}
|
||||
g.SendMsg(cmd.WorldPlayerInfoNotify, worldPlayer.PlayerID, worldPlayer.ClientSeq, worldPlayerInfoNotify)
|
||||
|
||||
// PacketScenePlayerInfoNotify
|
||||
scenePlayerInfoNotify := new(proto.ScenePlayerInfoNotify)
|
||||
for _, subWorldPlayer := range hostWorld.playerMap {
|
||||
onlinePlayerInfo := new(proto.OnlinePlayerInfo)
|
||||
onlinePlayerInfo.Uid = subWorldPlayer.PlayerID
|
||||
onlinePlayerInfo.Nickname = subWorldPlayer.NickName
|
||||
onlinePlayerInfo.PlayerLevel = subWorldPlayer.PropertiesMap[constant.PlayerPropertyConst.PROP_PLAYER_LEVEL]
|
||||
onlinePlayerInfo.MpSettingType = proto.MpSettingType(subWorldPlayer.PropertiesMap[constant.PlayerPropertyConst.PROP_PLAYER_MP_SETTING_TYPE])
|
||||
onlinePlayerInfo.NameCardId = subWorldPlayer.NameCard
|
||||
onlinePlayerInfo.Signature = subWorldPlayer.Signature
|
||||
onlinePlayerInfo.ProfilePicture = &proto.ProfilePicture{AvatarId: subWorldPlayer.HeadImage}
|
||||
onlinePlayerInfo.CurPlayerNumInWorld = uint32(len(hostWorld.playerMap))
|
||||
scenePlayerInfoNotify.PlayerInfoList = append(scenePlayerInfoNotify.PlayerInfoList, &proto.ScenePlayerInfo{
|
||||
Uid: subWorldPlayer.PlayerID,
|
||||
PeerId: subWorldPlayer.PeerId,
|
||||
Name: subWorldPlayer.NickName,
|
||||
SceneId: subWorldPlayer.SceneId,
|
||||
OnlinePlayerInfo: onlinePlayerInfo,
|
||||
})
|
||||
}
|
||||
g.SendMsg(cmd.ScenePlayerInfoNotify, worldPlayer.PlayerID, worldPlayer.ClientSeq, scenePlayerInfoNotify)
|
||||
|
||||
// PacketSyncTeamEntityNotify
|
||||
syncTeamEntityNotify := new(proto.SyncTeamEntityNotify)
|
||||
syncTeamEntityNotify.SceneId = worldPlayer.SceneId
|
||||
syncTeamEntityNotify.TeamEntityInfoList = make([]*proto.TeamEntityInfo, 0)
|
||||
if hostWorld.multiplayer {
|
||||
for _, subWorldPlayer := range hostWorld.playerMap {
|
||||
if subWorldPlayer.PlayerID == worldPlayer.PlayerID {
|
||||
continue
|
||||
}
|
||||
subWorldPlayerScene := hostWorld.GetSceneById(subWorldPlayer.SceneId)
|
||||
subWorldPlayerTeamEntity := subWorldPlayerScene.GetPlayerTeamEntity(subWorldPlayer.PlayerID)
|
||||
teamEntityInfo := &proto.TeamEntityInfo{
|
||||
TeamEntityId: subWorldPlayerTeamEntity.teamEntityId,
|
||||
AuthorityPeerId: subWorldPlayer.PeerId,
|
||||
TeamAbilityInfo: new(proto.AbilitySyncStateInfo),
|
||||
}
|
||||
syncTeamEntityNotify.TeamEntityInfoList = append(syncTeamEntityNotify.TeamEntityInfoList, teamEntityInfo)
|
||||
}
|
||||
}
|
||||
g.SendMsg(cmd.SyncTeamEntityNotify, worldPlayer.PlayerID, worldPlayer.ClientSeq, syncTeamEntityNotify)
|
||||
|
||||
// PacketSyncScenePlayTeamEntityNotify
|
||||
syncScenePlayTeamEntityNotify := new(proto.SyncScenePlayTeamEntityNotify)
|
||||
syncScenePlayTeamEntityNotify.SceneId = worldPlayer.SceneId
|
||||
g.SendMsg(cmd.SyncScenePlayTeamEntityNotify, worldPlayer.PlayerID, worldPlayer.ClientSeq, syncScenePlayTeamEntityNotify)
|
||||
}
|
||||
}
|
||||
711
gs/game/user_scene.go
Normal file
711
gs/game/user_scene.go
Normal file
@@ -0,0 +1,711 @@
|
||||
package game
|
||||
|
||||
import (
|
||||
pb "google.golang.org/protobuf/proto"
|
||||
"hk4e/common/utils/object"
|
||||
"hk4e/common/utils/random"
|
||||
gdc "hk4e/gs/config"
|
||||
"hk4e/gs/constant"
|
||||
"hk4e/gs/model"
|
||||
"hk4e/logger"
|
||||
"hk4e/protocol/cmd"
|
||||
"hk4e/protocol/proto"
|
||||
"strconv"
|
||||
"time"
|
||||
)
|
||||
|
||||
func (g *GameManager) EnterSceneReadyReq(player *model.Player, payloadMsg pb.Message) {
|
||||
logger.LOG.Debug("user enter scene ready, uid: %v", player.PlayerID)
|
||||
|
||||
// PacketEnterScenePeerNotify
|
||||
enterScenePeerNotify := new(proto.EnterScenePeerNotify)
|
||||
enterScenePeerNotify.DestSceneId = player.SceneId
|
||||
world := g.worldManager.GetWorldByID(player.WorldId)
|
||||
enterScenePeerNotify.PeerId = player.PeerId
|
||||
enterScenePeerNotify.HostPeerId = world.owner.PeerId
|
||||
enterScenePeerNotify.EnterSceneToken = player.EnterSceneToken
|
||||
g.SendMsg(cmd.EnterScenePeerNotify, player.PlayerID, player.ClientSeq, enterScenePeerNotify)
|
||||
|
||||
// PacketEnterSceneReadyRsp
|
||||
enterSceneReadyRsp := new(proto.EnterSceneReadyRsp)
|
||||
enterSceneReadyRsp.EnterSceneToken = player.EnterSceneToken
|
||||
g.SendMsg(cmd.EnterSceneReadyRsp, player.PlayerID, player.ClientSeq, enterSceneReadyRsp)
|
||||
}
|
||||
|
||||
func (g *GameManager) SceneInitFinishReq(player *model.Player, payloadMsg pb.Message) {
|
||||
logger.LOG.Debug("user scene init finish, uid: %v", player.PlayerID)
|
||||
|
||||
// PacketServerTimeNotify
|
||||
serverTimeNotify := new(proto.ServerTimeNotify)
|
||||
serverTimeNotify.ServerTime = uint64(time.Now().UnixMilli())
|
||||
g.SendMsg(cmd.ServerTimeNotify, player.PlayerID, player.ClientSeq, serverTimeNotify)
|
||||
|
||||
// PacketWorldPlayerInfoNotify
|
||||
worldPlayerInfoNotify := new(proto.WorldPlayerInfoNotify)
|
||||
world := g.worldManager.GetWorldByID(player.WorldId)
|
||||
scene := world.GetSceneById(player.SceneId)
|
||||
for _, worldPlayer := range world.playerMap {
|
||||
onlinePlayerInfo := new(proto.OnlinePlayerInfo)
|
||||
onlinePlayerInfo.Uid = worldPlayer.PlayerID
|
||||
onlinePlayerInfo.Nickname = worldPlayer.NickName
|
||||
onlinePlayerInfo.PlayerLevel = worldPlayer.PropertiesMap[constant.PlayerPropertyConst.PROP_PLAYER_LEVEL]
|
||||
onlinePlayerInfo.MpSettingType = proto.MpSettingType(worldPlayer.PropertiesMap[constant.PlayerPropertyConst.PROP_PLAYER_MP_SETTING_TYPE])
|
||||
onlinePlayerInfo.NameCardId = worldPlayer.NameCard
|
||||
onlinePlayerInfo.Signature = worldPlayer.Signature
|
||||
onlinePlayerInfo.ProfilePicture = &proto.ProfilePicture{AvatarId: worldPlayer.HeadImage}
|
||||
onlinePlayerInfo.CurPlayerNumInWorld = uint32(len(world.playerMap))
|
||||
worldPlayerInfoNotify.PlayerInfoList = append(worldPlayerInfoNotify.PlayerInfoList, onlinePlayerInfo)
|
||||
worldPlayerInfoNotify.PlayerUidList = append(worldPlayerInfoNotify.PlayerUidList, worldPlayer.PlayerID)
|
||||
}
|
||||
g.SendMsg(cmd.WorldPlayerInfoNotify, player.PlayerID, player.ClientSeq, worldPlayerInfoNotify)
|
||||
|
||||
// PacketWorldDataNotify
|
||||
worldDataNotify := new(proto.WorldDataNotify)
|
||||
worldDataNotify.WorldPropMap = make(map[uint32]*proto.PropValue)
|
||||
// 世界等级
|
||||
worldDataNotify.WorldPropMap[1] = &proto.PropValue{
|
||||
Type: 1,
|
||||
Val: int64(world.worldLevel),
|
||||
Value: &proto.PropValue_Ival{Ival: int64(world.worldLevel)},
|
||||
}
|
||||
// 是否多人游戏
|
||||
worldDataNotify.WorldPropMap[2] = &proto.PropValue{
|
||||
Type: 2,
|
||||
Val: object.ConvBoolToInt64(world.multiplayer),
|
||||
Value: &proto.PropValue_Ival{Ival: object.ConvBoolToInt64(world.multiplayer)},
|
||||
}
|
||||
g.SendMsg(cmd.WorldDataNotify, player.PlayerID, player.ClientSeq, worldDataNotify)
|
||||
|
||||
// PacketPlayerWorldSceneInfoListNotify
|
||||
playerWorldSceneInfoListNotify := new(proto.PlayerWorldSceneInfoListNotify)
|
||||
playerWorldSceneInfoListNotify.InfoList = []*proto.PlayerWorldSceneInfo{
|
||||
{SceneId: 1, IsLocked: false, SceneTagIdList: []uint32{}},
|
||||
{SceneId: 3, IsLocked: false, SceneTagIdList: []uint32{102, 113, 117}},
|
||||
{SceneId: 4, IsLocked: false, SceneTagIdList: []uint32{106, 109, 117}},
|
||||
{SceneId: 5, IsLocked: false, SceneTagIdList: []uint32{}},
|
||||
{SceneId: 6, IsLocked: false, SceneTagIdList: []uint32{}},
|
||||
{SceneId: 7, IsLocked: false, SceneTagIdList: []uint32{}},
|
||||
}
|
||||
xumi := &proto.PlayerWorldSceneInfo{
|
||||
SceneId: 9,
|
||||
IsLocked: false,
|
||||
SceneTagIdList: []uint32{},
|
||||
}
|
||||
for i := 0; i < 3000; i++ {
|
||||
xumi.SceneTagIdList = append(xumi.SceneTagIdList, uint32(i))
|
||||
}
|
||||
playerWorldSceneInfoListNotify.InfoList = append(playerWorldSceneInfoListNotify.InfoList, xumi)
|
||||
g.SendMsg(cmd.PlayerWorldSceneInfoListNotify, player.PlayerID, player.ClientSeq, playerWorldSceneInfoListNotify)
|
||||
|
||||
// SceneForceUnlockNotify
|
||||
g.SendMsg(cmd.SceneForceUnlockNotify, player.PlayerID, player.ClientSeq, new(proto.SceneForceUnlockNotify))
|
||||
|
||||
// PacketHostPlayerNotify
|
||||
hostPlayerNotify := new(proto.HostPlayerNotify)
|
||||
hostPlayerNotify.HostUid = world.owner.PlayerID
|
||||
hostPlayerNotify.HostPeerId = world.owner.PeerId
|
||||
g.SendMsg(cmd.HostPlayerNotify, player.PlayerID, player.ClientSeq, hostPlayerNotify)
|
||||
|
||||
// PacketSceneTimeNotify
|
||||
sceneTimeNotify := new(proto.SceneTimeNotify)
|
||||
sceneTimeNotify.SceneId = player.SceneId
|
||||
sceneTimeNotify.SceneTime = uint64(scene.GetSceneTime())
|
||||
g.SendMsg(cmd.SceneTimeNotify, player.PlayerID, player.ClientSeq, sceneTimeNotify)
|
||||
|
||||
// PacketPlayerGameTimeNotify
|
||||
playerGameTimeNotify := new(proto.PlayerGameTimeNotify)
|
||||
playerGameTimeNotify.GameTime = scene.gameTime
|
||||
playerGameTimeNotify.Uid = player.PlayerID
|
||||
g.SendMsg(cmd.PlayerGameTimeNotify, player.PlayerID, player.ClientSeq, playerGameTimeNotify)
|
||||
|
||||
// PacketPlayerEnterSceneInfoNotify
|
||||
empty := new(proto.AbilitySyncStateInfo)
|
||||
playerEnterSceneInfoNotify := new(proto.PlayerEnterSceneInfoNotify)
|
||||
activeAvatarId := player.TeamConfig.GetActiveAvatarId()
|
||||
playerTeamEntity := scene.GetPlayerTeamEntity(player.PlayerID)
|
||||
playerEnterSceneInfoNotify.CurAvatarEntityId = playerTeamEntity.avatarEntityMap[activeAvatarId]
|
||||
playerEnterSceneInfoNotify.EnterSceneToken = player.EnterSceneToken
|
||||
playerEnterSceneInfoNotify.TeamEnterInfo = &proto.TeamEnterSceneInfo{
|
||||
TeamEntityId: playerTeamEntity.teamEntityId,
|
||||
TeamAbilityInfo: empty,
|
||||
AbilityControlBlock: new(proto.AbilityControlBlock),
|
||||
}
|
||||
playerEnterSceneInfoNotify.MpLevelEntityInfo = &proto.MPLevelEntityInfo{
|
||||
EntityId: g.worldManager.GetWorldByID(player.WorldId).mpLevelEntityId,
|
||||
AuthorityPeerId: g.worldManager.GetWorldByID(player.WorldId).owner.PeerId,
|
||||
AbilityInfo: empty,
|
||||
}
|
||||
activeTeam := player.TeamConfig.GetActiveTeam()
|
||||
for _, avatarId := range activeTeam.AvatarIdList {
|
||||
if avatarId == 0 {
|
||||
break
|
||||
}
|
||||
avatar := player.AvatarMap[avatarId]
|
||||
avatarEnterSceneInfo := new(proto.AvatarEnterSceneInfo)
|
||||
avatarEnterSceneInfo.AvatarGuid = avatar.Guid
|
||||
avatarEnterSceneInfo.AvatarEntityId = playerTeamEntity.avatarEntityMap[avatarId]
|
||||
avatarEnterSceneInfo.WeaponGuid = avatar.EquipWeapon.Guid
|
||||
avatarEnterSceneInfo.WeaponEntityId = playerTeamEntity.weaponEntityMap[avatar.EquipWeapon.WeaponId]
|
||||
avatarEnterSceneInfo.AvatarAbilityInfo = empty
|
||||
avatarEnterSceneInfo.WeaponAbilityInfo = empty
|
||||
playerEnterSceneInfoNotify.AvatarEnterInfo = append(playerEnterSceneInfoNotify.AvatarEnterInfo, avatarEnterSceneInfo)
|
||||
}
|
||||
g.SendMsg(cmd.PlayerEnterSceneInfoNotify, player.PlayerID, player.ClientSeq, playerEnterSceneInfoNotify)
|
||||
|
||||
// PacketSceneAreaWeatherNotify
|
||||
sceneAreaWeatherNotify := new(proto.SceneAreaWeatherNotify)
|
||||
sceneAreaWeatherNotify.WeatherAreaId = 0
|
||||
sceneAreaWeatherNotify.ClimateType = uint32(constant.ClimateTypeConst.CLIMATE_SUNNY)
|
||||
g.SendMsg(cmd.SceneAreaWeatherNotify, player.PlayerID, player.ClientSeq, sceneAreaWeatherNotify)
|
||||
|
||||
// PacketScenePlayerInfoNotify
|
||||
scenePlayerInfoNotify := new(proto.ScenePlayerInfoNotify)
|
||||
for _, worldPlayer := range world.playerMap {
|
||||
onlinePlayerInfo := new(proto.OnlinePlayerInfo)
|
||||
onlinePlayerInfo.Uid = worldPlayer.PlayerID
|
||||
onlinePlayerInfo.Nickname = worldPlayer.NickName
|
||||
onlinePlayerInfo.PlayerLevel = worldPlayer.PropertiesMap[constant.PlayerPropertyConst.PROP_PLAYER_LEVEL]
|
||||
onlinePlayerInfo.MpSettingType = proto.MpSettingType(worldPlayer.PropertiesMap[constant.PlayerPropertyConst.PROP_PLAYER_MP_SETTING_TYPE])
|
||||
onlinePlayerInfo.NameCardId = worldPlayer.NameCard
|
||||
onlinePlayerInfo.Signature = worldPlayer.Signature
|
||||
onlinePlayerInfo.ProfilePicture = &proto.ProfilePicture{AvatarId: worldPlayer.HeadImage}
|
||||
onlinePlayerInfo.CurPlayerNumInWorld = uint32(len(world.playerMap))
|
||||
scenePlayerInfoNotify.PlayerInfoList = append(scenePlayerInfoNotify.PlayerInfoList, &proto.ScenePlayerInfo{
|
||||
Uid: worldPlayer.PlayerID,
|
||||
PeerId: worldPlayer.PeerId,
|
||||
Name: worldPlayer.NickName,
|
||||
SceneId: worldPlayer.SceneId,
|
||||
OnlinePlayerInfo: onlinePlayerInfo,
|
||||
})
|
||||
}
|
||||
g.SendMsg(cmd.ScenePlayerInfoNotify, player.PlayerID, player.ClientSeq, scenePlayerInfoNotify)
|
||||
|
||||
// PacketSceneTeamUpdateNotify
|
||||
sceneTeamUpdateNotify := g.PacketSceneTeamUpdateNotify(world)
|
||||
g.SendMsg(cmd.SceneTeamUpdateNotify, player.PlayerID, player.ClientSeq, sceneTeamUpdateNotify)
|
||||
|
||||
// PacketSyncTeamEntityNotify
|
||||
syncTeamEntityNotify := new(proto.SyncTeamEntityNotify)
|
||||
syncTeamEntityNotify.SceneId = player.SceneId
|
||||
syncTeamEntityNotify.TeamEntityInfoList = make([]*proto.TeamEntityInfo, 0)
|
||||
if world.multiplayer {
|
||||
for _, worldPlayer := range world.playerMap {
|
||||
if worldPlayer.PlayerID == player.PlayerID {
|
||||
continue
|
||||
}
|
||||
worldPlayerScene := world.GetSceneById(worldPlayer.SceneId)
|
||||
worldPlayerTeamEntity := worldPlayerScene.GetPlayerTeamEntity(worldPlayer.PlayerID)
|
||||
teamEntityInfo := &proto.TeamEntityInfo{
|
||||
TeamEntityId: worldPlayerTeamEntity.teamEntityId,
|
||||
AuthorityPeerId: worldPlayer.PeerId,
|
||||
TeamAbilityInfo: new(proto.AbilitySyncStateInfo),
|
||||
}
|
||||
syncTeamEntityNotify.TeamEntityInfoList = append(syncTeamEntityNotify.TeamEntityInfoList, teamEntityInfo)
|
||||
}
|
||||
}
|
||||
g.SendMsg(cmd.SyncTeamEntityNotify, player.PlayerID, player.ClientSeq, syncTeamEntityNotify)
|
||||
|
||||
// PacketSyncScenePlayTeamEntityNotify
|
||||
syncScenePlayTeamEntityNotify := new(proto.SyncScenePlayTeamEntityNotify)
|
||||
syncScenePlayTeamEntityNotify.SceneId = player.SceneId
|
||||
g.SendMsg(cmd.SyncScenePlayTeamEntityNotify, player.PlayerID, player.ClientSeq, syncScenePlayTeamEntityNotify)
|
||||
|
||||
// PacketSceneInitFinishRsp
|
||||
SceneInitFinishRsp := new(proto.SceneInitFinishRsp)
|
||||
SceneInitFinishRsp.EnterSceneToken = player.EnterSceneToken
|
||||
g.SendMsg(cmd.SceneInitFinishRsp, player.PlayerID, player.ClientSeq, SceneInitFinishRsp)
|
||||
|
||||
player.SceneLoadState = model.SceneInitFinish
|
||||
}
|
||||
|
||||
func (g *GameManager) EnterSceneDoneReq(player *model.Player, payloadMsg pb.Message) {
|
||||
logger.LOG.Debug("user enter scene done, uid: %v", player.PlayerID)
|
||||
|
||||
// PacketEnterSceneDoneRsp
|
||||
enterSceneDoneRsp := new(proto.EnterSceneDoneRsp)
|
||||
enterSceneDoneRsp.EnterSceneToken = player.EnterSceneToken
|
||||
g.SendMsg(cmd.EnterSceneDoneRsp, player.PlayerID, player.ClientSeq, enterSceneDoneRsp)
|
||||
|
||||
// PacketPlayerTimeNotify
|
||||
playerTimeNotify := new(proto.PlayerTimeNotify)
|
||||
playerTimeNotify.IsPaused = player.Pause
|
||||
playerTimeNotify.PlayerTime = uint64(player.TotalOnlineTime)
|
||||
playerTimeNotify.ServerTime = uint64(time.Now().UnixMilli())
|
||||
g.SendMsg(cmd.PlayerTimeNotify, player.PlayerID, player.ClientSeq, playerTimeNotify)
|
||||
|
||||
player.SceneLoadState = model.SceneEnterDone
|
||||
world := g.worldManager.GetWorldByID(player.WorldId)
|
||||
scene := world.GetSceneById(player.SceneId)
|
||||
|
||||
playerTeamEntity := scene.GetPlayerTeamEntity(player.PlayerID)
|
||||
activeAvatarId := player.TeamConfig.GetActiveAvatarId()
|
||||
g.AddSceneEntityNotify(player, proto.VisionType_VISION_TYPE_BORN, []uint32{playerTeamEntity.avatarEntityMap[activeAvatarId]}, true)
|
||||
|
||||
// 通过aoi获取场景中在自己周围格子里的全部实体id
|
||||
entityIdList := world.aoiManager.GetEntityIdListByPos(float32(player.Pos.X), float32(player.Pos.Y), float32(player.Pos.Z))
|
||||
g.AddSceneEntityNotify(player, proto.VisionType_VISION_TYPE_MEET, entityIdList, false)
|
||||
}
|
||||
|
||||
func (g *GameManager) PostEnterSceneReq(player *model.Player, payloadMsg pb.Message) {
|
||||
logger.LOG.Debug("user post enter scene, uid: %v", player.PlayerID)
|
||||
|
||||
// PacketPostEnterSceneRsp
|
||||
postEnterSceneRsp := new(proto.PostEnterSceneRsp)
|
||||
postEnterSceneRsp.EnterSceneToken = player.EnterSceneToken
|
||||
g.SendMsg(cmd.PostEnterSceneRsp, player.PlayerID, player.ClientSeq, postEnterSceneRsp)
|
||||
}
|
||||
|
||||
func (g *GameManager) EnterWorldAreaReq(player *model.Player, payloadMsg pb.Message) {
|
||||
logger.LOG.Debug("user enter world area, uid: %v", player.PlayerID)
|
||||
req := payloadMsg.(*proto.EnterWorldAreaReq)
|
||||
|
||||
// PacketEnterWorldAreaRsp
|
||||
enterWorldAreaRsp := new(proto.EnterWorldAreaRsp)
|
||||
enterWorldAreaRsp.AreaType = req.AreaType
|
||||
enterWorldAreaRsp.AreaId = req.AreaId
|
||||
g.SendMsg(cmd.EnterWorldAreaRsp, player.PlayerID, player.ClientSeq, enterWorldAreaRsp)
|
||||
}
|
||||
|
||||
func (g *GameManager) ChangeGameTimeReq(player *model.Player, payloadMsg pb.Message) {
|
||||
logger.LOG.Debug("user change game time, uid: %v", player.PlayerID)
|
||||
req := payloadMsg.(*proto.ChangeGameTimeReq)
|
||||
gameTime := req.GameTime
|
||||
world := g.worldManager.GetWorldByID(player.WorldId)
|
||||
scene := world.GetSceneById(player.SceneId)
|
||||
scene.ChangeGameTime(gameTime)
|
||||
|
||||
for _, scenePlayer := range scene.playerMap {
|
||||
// PacketPlayerGameTimeNotify
|
||||
playerGameTimeNotify := new(proto.PlayerGameTimeNotify)
|
||||
playerGameTimeNotify.GameTime = scene.gameTime
|
||||
playerGameTimeNotify.Uid = scenePlayer.PlayerID
|
||||
g.SendMsg(cmd.PlayerGameTimeNotify, scenePlayer.PlayerID, scenePlayer.ClientSeq, playerGameTimeNotify)
|
||||
}
|
||||
|
||||
// PacketChangeGameTimeRsp
|
||||
changeGameTimeRsp := new(proto.ChangeGameTimeRsp)
|
||||
changeGameTimeRsp.CurGameTime = scene.gameTime
|
||||
g.SendMsg(cmd.ChangeGameTimeRsp, player.PlayerID, player.ClientSeq, changeGameTimeRsp)
|
||||
}
|
||||
|
||||
func (g *GameManager) PacketPlayerEnterSceneNotify(player *model.Player) *proto.PlayerEnterSceneNotify {
|
||||
player.EnterSceneToken = uint32(random.GetRandomInt32(1000, 99999))
|
||||
playerEnterSceneNotify := new(proto.PlayerEnterSceneNotify)
|
||||
playerEnterSceneNotify.SceneId = player.SceneId
|
||||
playerEnterSceneNotify.Pos = &proto.Vector{X: float32(player.Pos.X), Y: float32(player.Pos.Y), Z: float32(player.Pos.Z)}
|
||||
playerEnterSceneNotify.SceneBeginTime = uint64(time.Now().UnixMilli())
|
||||
playerEnterSceneNotify.Type = proto.EnterType_ENTER_TYPE_SELF
|
||||
playerEnterSceneNotify.TargetUid = player.PlayerID
|
||||
playerEnterSceneNotify.EnterSceneToken = player.EnterSceneToken
|
||||
playerEnterSceneNotify.WorldLevel = player.PropertiesMap[constant.PlayerPropertyConst.PROP_PLAYER_WORLD_LEVEL]
|
||||
playerEnterSceneNotify.EnterReason = uint32(constant.EnterReasonConst.Login)
|
||||
// 刚登录进入场景的时候才为true
|
||||
playerEnterSceneNotify.IsFirstLoginEnterScene = true
|
||||
playerEnterSceneNotify.WorldType = 1
|
||||
playerEnterSceneNotify.SceneTransaction = strconv.Itoa(int(player.SceneId)) + "-" +
|
||||
strconv.Itoa(int(player.PlayerID)) + "-" +
|
||||
strconv.Itoa(int(time.Now().Unix())) + "-" +
|
||||
"18402"
|
||||
return playerEnterSceneNotify
|
||||
}
|
||||
|
||||
func (g *GameManager) PacketPlayerEnterSceneNotifyTp(
|
||||
player *model.Player,
|
||||
enterType proto.EnterType,
|
||||
enterReason uint32,
|
||||
prevSceneId uint32,
|
||||
prevPos *model.Vector,
|
||||
) *proto.PlayerEnterSceneNotify {
|
||||
return g.PacketPlayerEnterSceneNotifyMp(player, player, enterType, enterReason, prevSceneId, prevPos)
|
||||
}
|
||||
|
||||
func (g *GameManager) PacketPlayerEnterSceneNotifyMp(
|
||||
player *model.Player,
|
||||
targetPlayer *model.Player,
|
||||
enterType proto.EnterType,
|
||||
enterReason uint32,
|
||||
prevSceneId uint32,
|
||||
prevPos *model.Vector,
|
||||
) *proto.PlayerEnterSceneNotify {
|
||||
player.EnterSceneToken = uint32(random.GetRandomInt32(1000, 99999))
|
||||
playerEnterSceneNotify := new(proto.PlayerEnterSceneNotify)
|
||||
playerEnterSceneNotify.PrevSceneId = prevSceneId
|
||||
playerEnterSceneNotify.PrevPos = &proto.Vector{X: float32(prevPos.X), Y: float32(prevPos.Y), Z: float32(prevPos.Z)}
|
||||
playerEnterSceneNotify.SceneId = player.SceneId
|
||||
playerEnterSceneNotify.Pos = &proto.Vector{X: float32(player.Pos.X), Y: float32(player.Pos.Y), Z: float32(player.Pos.Z)}
|
||||
playerEnterSceneNotify.SceneBeginTime = uint64(time.Now().UnixMilli())
|
||||
playerEnterSceneNotify.Type = enterType
|
||||
playerEnterSceneNotify.TargetUid = targetPlayer.PlayerID
|
||||
playerEnterSceneNotify.EnterSceneToken = player.EnterSceneToken
|
||||
playerEnterSceneNotify.WorldLevel = targetPlayer.PropertiesMap[constant.PlayerPropertyConst.PROP_PLAYER_WORLD_LEVEL]
|
||||
playerEnterSceneNotify.EnterReason = enterReason
|
||||
playerEnterSceneNotify.WorldType = 1
|
||||
playerEnterSceneNotify.SceneTransaction = strconv.Itoa(int(player.SceneId)) + "-" +
|
||||
strconv.Itoa(int(targetPlayer.PlayerID)) + "-" +
|
||||
strconv.Itoa(int(time.Now().Unix())) + "-" +
|
||||
"18402"
|
||||
|
||||
//playerEnterSceneNotify.SceneTagIdList = []uint32{102, 107, 109, 113, 117}
|
||||
playerEnterSceneNotify.SceneTagIdList = make([]uint32, 0)
|
||||
for sceneTagId := uint32(0); sceneTagId < 3000; sceneTagId++ {
|
||||
playerEnterSceneNotify.SceneTagIdList = append(playerEnterSceneNotify.SceneTagIdList, sceneTagId)
|
||||
}
|
||||
|
||||
return playerEnterSceneNotify
|
||||
}
|
||||
|
||||
func (g *GameManager) AddSceneEntityNotifyToPlayer(player *model.Player, visionType proto.VisionType, entityList []*proto.SceneEntityInfo) {
|
||||
// PacketSceneEntityAppearNotify
|
||||
sceneEntityAppearNotify := new(proto.SceneEntityAppearNotify)
|
||||
sceneEntityAppearNotify.AppearType = visionType
|
||||
sceneEntityAppearNotify.EntityList = entityList
|
||||
g.SendMsg(cmd.SceneEntityAppearNotify, player.PlayerID, player.ClientSeq, sceneEntityAppearNotify)
|
||||
logger.LOG.Debug("SceneEntityAppearNotify, uid: %v, type: %v, len: %v",
|
||||
player.PlayerID, sceneEntityAppearNotify.AppearType, len(sceneEntityAppearNotify.EntityList))
|
||||
}
|
||||
|
||||
func (g *GameManager) AddSceneEntityNotifyBroadcast(scene *Scene, visionType proto.VisionType, entityList []*proto.SceneEntityInfo) {
|
||||
// PacketSceneEntityAppearNotify
|
||||
sceneEntityAppearNotify := new(proto.SceneEntityAppearNotify)
|
||||
sceneEntityAppearNotify.AppearType = visionType
|
||||
sceneEntityAppearNotify.EntityList = entityList
|
||||
for _, scenePlayer := range scene.playerMap {
|
||||
g.SendMsg(cmd.SceneEntityAppearNotify, scenePlayer.PlayerID, scenePlayer.ClientSeq, sceneEntityAppearNotify)
|
||||
logger.LOG.Debug("SceneEntityAppearNotify, uid: %v, type: %v, len: %v",
|
||||
scenePlayer.PlayerID, sceneEntityAppearNotify.AppearType, len(sceneEntityAppearNotify.EntityList))
|
||||
}
|
||||
}
|
||||
|
||||
func (g *GameManager) RemoveSceneEntityNotifyToPlayer(player *model.Player, entityIdList []uint32) {
|
||||
// PacketSceneEntityDisappearNotify
|
||||
sceneEntityDisappearNotify := new(proto.SceneEntityDisappearNotify)
|
||||
sceneEntityDisappearNotify.EntityList = entityIdList
|
||||
sceneEntityDisappearNotify.DisappearType = proto.VisionType_VISION_TYPE_REMOVE
|
||||
g.SendMsg(cmd.SceneEntityDisappearNotify, player.PlayerID, player.ClientSeq, sceneEntityDisappearNotify)
|
||||
logger.LOG.Debug("SceneEntityDisappearNotify, uid: %v, type: %v, len: %v",
|
||||
player.PlayerID, sceneEntityDisappearNotify.DisappearType, len(sceneEntityDisappearNotify.EntityList))
|
||||
}
|
||||
|
||||
func (g *GameManager) RemoveSceneEntityNotifyBroadcast(scene *Scene, entityIdList []uint32) {
|
||||
// PacketSceneEntityDisappearNotify
|
||||
sceneEntityDisappearNotify := new(proto.SceneEntityDisappearNotify)
|
||||
sceneEntityDisappearNotify.EntityList = entityIdList
|
||||
sceneEntityDisappearNotify.DisappearType = proto.VisionType_VISION_TYPE_REMOVE
|
||||
for _, scenePlayer := range scene.playerMap {
|
||||
g.SendMsg(cmd.SceneEntityDisappearNotify, scenePlayer.PlayerID, scenePlayer.ClientSeq, sceneEntityDisappearNotify)
|
||||
logger.LOG.Debug("SceneEntityDisappearNotify, uid: %v, type: %v, len: %v",
|
||||
scenePlayer.PlayerID, sceneEntityDisappearNotify.DisappearType, len(sceneEntityDisappearNotify.EntityList))
|
||||
}
|
||||
}
|
||||
|
||||
func (g *GameManager) AddSceneEntityNotify(player *model.Player, visionType proto.VisionType, entityIdList []uint32, broadcast bool) {
|
||||
world := g.worldManager.GetWorldByID(player.WorldId)
|
||||
scene := world.GetSceneById(player.SceneId)
|
||||
entityList := make([]*proto.SceneEntityInfo, 0)
|
||||
for _, entityId := range entityIdList {
|
||||
entity := scene.entityMap[entityId]
|
||||
if entity == nil {
|
||||
logger.LOG.Error("get entity is nil, entityId: %v", entityId)
|
||||
continue
|
||||
}
|
||||
switch entity.entityType {
|
||||
case uint32(proto.ProtEntityType_PROT_ENTITY_TYPE_AVATAR):
|
||||
if visionType == proto.VisionType_VISION_TYPE_MEET && entity.avatarEntity.uid == player.PlayerID {
|
||||
continue
|
||||
}
|
||||
scenePlayer := g.userManager.GetOnlineUser(entity.avatarEntity.uid)
|
||||
if scenePlayer == nil {
|
||||
logger.LOG.Error("get scene player is nil, world id: %v, scene id: %v", world.id, scene.id)
|
||||
continue
|
||||
}
|
||||
if scenePlayer.SceneLoadState != model.SceneEnterDone {
|
||||
continue
|
||||
}
|
||||
if entity.avatarEntity.avatarId != scenePlayer.TeamConfig.GetActiveAvatarId() {
|
||||
continue
|
||||
}
|
||||
sceneEntityInfoAvatar := g.PacketSceneEntityInfoAvatar(scene, scenePlayer, scenePlayer.TeamConfig.GetActiveAvatarId())
|
||||
entityList = append(entityList, sceneEntityInfoAvatar)
|
||||
case uint32(proto.ProtEntityType_PROT_ENTITY_TYPE_WEAPON):
|
||||
case uint32(proto.ProtEntityType_PROT_ENTITY_TYPE_MONSTER):
|
||||
sceneEntityInfoMonster := g.PacketSceneEntityInfoMonster(scene, entity.id)
|
||||
entityList = append(entityList, sceneEntityInfoMonster)
|
||||
case uint32(proto.ProtEntityType_PROT_ENTITY_TYPE_GADGET):
|
||||
sceneEntityInfoGadget := g.PacketSceneEntityInfoGadget(scene, entity.id)
|
||||
entityList = append(entityList, sceneEntityInfoGadget)
|
||||
}
|
||||
}
|
||||
if broadcast {
|
||||
g.AddSceneEntityNotifyBroadcast(scene, visionType, entityList)
|
||||
} else {
|
||||
g.AddSceneEntityNotifyToPlayer(player, visionType, entityList)
|
||||
}
|
||||
}
|
||||
|
||||
func (g *GameManager) PacketFightPropMapToPbFightPropList(fightPropMap map[uint32]float32) []*proto.FightPropPair {
|
||||
fightPropList := []*proto.FightPropPair{
|
||||
{
|
||||
PropType: uint32(constant.FightPropertyConst.FIGHT_PROP_BASE_HP),
|
||||
PropValue: fightPropMap[uint32(constant.FightPropertyConst.FIGHT_PROP_BASE_HP)],
|
||||
},
|
||||
{
|
||||
PropType: uint32(constant.FightPropertyConst.FIGHT_PROP_BASE_ATTACK),
|
||||
PropValue: fightPropMap[uint32(constant.FightPropertyConst.FIGHT_PROP_BASE_ATTACK)],
|
||||
},
|
||||
{
|
||||
PropType: uint32(constant.FightPropertyConst.FIGHT_PROP_BASE_DEFENSE),
|
||||
PropValue: fightPropMap[uint32(constant.FightPropertyConst.FIGHT_PROP_BASE_DEFENSE)],
|
||||
},
|
||||
{
|
||||
PropType: uint32(constant.FightPropertyConst.FIGHT_PROP_CRITICAL),
|
||||
PropValue: fightPropMap[uint32(constant.FightPropertyConst.FIGHT_PROP_CRITICAL)],
|
||||
},
|
||||
{
|
||||
PropType: uint32(constant.FightPropertyConst.FIGHT_PROP_CRITICAL_HURT),
|
||||
PropValue: fightPropMap[uint32(constant.FightPropertyConst.FIGHT_PROP_CRITICAL_HURT)],
|
||||
},
|
||||
{
|
||||
PropType: uint32(constant.FightPropertyConst.FIGHT_PROP_CHARGE_EFFICIENCY),
|
||||
PropValue: fightPropMap[uint32(constant.FightPropertyConst.FIGHT_PROP_CHARGE_EFFICIENCY)],
|
||||
},
|
||||
{
|
||||
PropType: uint32(constant.FightPropertyConst.FIGHT_PROP_CUR_HP),
|
||||
PropValue: fightPropMap[uint32(constant.FightPropertyConst.FIGHT_PROP_CUR_HP)],
|
||||
},
|
||||
{
|
||||
PropType: uint32(constant.FightPropertyConst.FIGHT_PROP_MAX_HP),
|
||||
PropValue: fightPropMap[uint32(constant.FightPropertyConst.FIGHT_PROP_MAX_HP)],
|
||||
},
|
||||
{
|
||||
PropType: uint32(constant.FightPropertyConst.FIGHT_PROP_CUR_ATTACK),
|
||||
PropValue: fightPropMap[uint32(constant.FightPropertyConst.FIGHT_PROP_CUR_ATTACK)],
|
||||
},
|
||||
{
|
||||
PropType: uint32(constant.FightPropertyConst.FIGHT_PROP_CUR_DEFENSE),
|
||||
PropValue: fightPropMap[uint32(constant.FightPropertyConst.FIGHT_PROP_CUR_DEFENSE)],
|
||||
},
|
||||
}
|
||||
return fightPropList
|
||||
}
|
||||
|
||||
func (g *GameManager) PacketSceneEntityInfoAvatar(scene *Scene, player *model.Player, avatarId uint32) *proto.SceneEntityInfo {
|
||||
playerTeamEntity := scene.GetPlayerTeamEntity(player.PlayerID)
|
||||
entity := scene.GetEntity(playerTeamEntity.avatarEntityMap[avatarId])
|
||||
if entity == nil {
|
||||
return new(proto.SceneEntityInfo)
|
||||
}
|
||||
sceneEntityInfo := &proto.SceneEntityInfo{
|
||||
EntityType: proto.ProtEntityType_PROT_ENTITY_TYPE_AVATAR,
|
||||
EntityId: entity.id,
|
||||
MotionInfo: &proto.MotionInfo{
|
||||
Pos: &proto.Vector{
|
||||
X: float32(entity.pos.X),
|
||||
Y: float32(entity.pos.Y),
|
||||
Z: float32(entity.pos.Z),
|
||||
},
|
||||
Rot: &proto.Vector{
|
||||
X: float32(entity.rot.X),
|
||||
Y: float32(entity.rot.Y),
|
||||
Z: float32(entity.rot.Z),
|
||||
},
|
||||
Speed: &proto.Vector{},
|
||||
State: proto.MotionState(entity.moveState),
|
||||
},
|
||||
PropList: []*proto.PropPair{{Type: uint32(constant.PlayerPropertyConst.PROP_LEVEL), PropValue: &proto.PropValue{
|
||||
Type: uint32(constant.PlayerPropertyConst.PROP_LEVEL),
|
||||
Value: &proto.PropValue_Ival{Ival: int64(entity.level)},
|
||||
Val: int64(entity.level),
|
||||
}}},
|
||||
FightPropList: g.PacketFightPropMapToPbFightPropList(entity.fightProp),
|
||||
LifeState: 1,
|
||||
AnimatorParaList: make([]*proto.AnimatorParameterValueInfoPair, 0),
|
||||
Entity: &proto.SceneEntityInfo_Avatar{
|
||||
Avatar: g.PacketSceneAvatarInfo(scene, player, avatarId),
|
||||
},
|
||||
EntityClientData: new(proto.EntityClientData),
|
||||
EntityAuthorityInfo: &proto.EntityAuthorityInfo{
|
||||
AbilityInfo: new(proto.AbilitySyncStateInfo),
|
||||
RendererChangedInfo: new(proto.EntityRendererChangedInfo),
|
||||
AiInfo: &proto.SceneEntityAiInfo{
|
||||
IsAiOpen: true,
|
||||
BornPos: new(proto.Vector),
|
||||
},
|
||||
BornPos: new(proto.Vector),
|
||||
},
|
||||
LastMoveSceneTimeMs: entity.lastMoveSceneTimeMs,
|
||||
LastMoveReliableSeq: entity.lastMoveReliableSeq,
|
||||
}
|
||||
return sceneEntityInfo
|
||||
}
|
||||
|
||||
func (g *GameManager) PacketSceneEntityInfoMonster(scene *Scene, entityId uint32) *proto.SceneEntityInfo {
|
||||
entity := scene.GetEntity(entityId)
|
||||
if entity == nil {
|
||||
return new(proto.SceneEntityInfo)
|
||||
}
|
||||
pos := &proto.Vector{
|
||||
X: float32(entity.pos.X),
|
||||
Y: float32(entity.pos.Y),
|
||||
Z: float32(entity.pos.Z),
|
||||
}
|
||||
sceneEntityInfo := &proto.SceneEntityInfo{
|
||||
EntityType: proto.ProtEntityType_PROT_ENTITY_TYPE_MONSTER,
|
||||
EntityId: entity.id,
|
||||
MotionInfo: &proto.MotionInfo{
|
||||
Pos: pos,
|
||||
Rot: &proto.Vector{
|
||||
X: float32(entity.rot.X),
|
||||
Y: float32(entity.rot.Y),
|
||||
Z: float32(entity.rot.Z),
|
||||
},
|
||||
Speed: &proto.Vector{},
|
||||
State: proto.MotionState(entity.moveState),
|
||||
},
|
||||
PropList: []*proto.PropPair{{Type: uint32(constant.PlayerPropertyConst.PROP_LEVEL), PropValue: &proto.PropValue{
|
||||
Type: uint32(constant.PlayerPropertyConst.PROP_LEVEL),
|
||||
Value: &proto.PropValue_Ival{Ival: int64(entity.level)},
|
||||
Val: int64(entity.level),
|
||||
}}},
|
||||
FightPropList: g.PacketFightPropMapToPbFightPropList(entity.fightProp),
|
||||
LifeState: 1,
|
||||
AnimatorParaList: make([]*proto.AnimatorParameterValueInfoPair, 0),
|
||||
Entity: &proto.SceneEntityInfo_Monster{
|
||||
Monster: g.PacketSceneMonsterInfo(),
|
||||
},
|
||||
EntityClientData: new(proto.EntityClientData),
|
||||
EntityAuthorityInfo: &proto.EntityAuthorityInfo{
|
||||
AbilityInfo: new(proto.AbilitySyncStateInfo),
|
||||
RendererChangedInfo: new(proto.EntityRendererChangedInfo),
|
||||
AiInfo: &proto.SceneEntityAiInfo{
|
||||
IsAiOpen: true,
|
||||
BornPos: pos,
|
||||
},
|
||||
BornPos: pos,
|
||||
},
|
||||
}
|
||||
return sceneEntityInfo
|
||||
}
|
||||
|
||||
func (g *GameManager) PacketSceneEntityInfoGadget(scene *Scene, entityId uint32) *proto.SceneEntityInfo {
|
||||
entity := scene.GetEntity(entityId)
|
||||
if entity == nil {
|
||||
return new(proto.SceneEntityInfo)
|
||||
}
|
||||
sceneEntityInfo := &proto.SceneEntityInfo{
|
||||
EntityType: proto.ProtEntityType_PROT_ENTITY_TYPE_GADGET,
|
||||
EntityId: entity.id,
|
||||
MotionInfo: &proto.MotionInfo{
|
||||
Pos: &proto.Vector{
|
||||
X: float32(entity.pos.X),
|
||||
Y: float32(entity.pos.Y),
|
||||
Z: float32(entity.pos.Z),
|
||||
},
|
||||
Rot: &proto.Vector{
|
||||
X: float32(entity.rot.X),
|
||||
Y: float32(entity.rot.Y),
|
||||
Z: float32(entity.rot.Z),
|
||||
},
|
||||
Speed: &proto.Vector{},
|
||||
State: proto.MotionState(entity.moveState),
|
||||
},
|
||||
PropList: []*proto.PropPair{{Type: uint32(constant.PlayerPropertyConst.PROP_LEVEL), PropValue: &proto.PropValue{
|
||||
Type: uint32(constant.PlayerPropertyConst.PROP_LEVEL),
|
||||
Value: &proto.PropValue_Ival{Ival: int64(1)},
|
||||
Val: int64(1),
|
||||
}}},
|
||||
FightPropList: g.PacketFightPropMapToPbFightPropList(entity.fightProp),
|
||||
LifeState: 1,
|
||||
AnimatorParaList: make([]*proto.AnimatorParameterValueInfoPair, 0),
|
||||
Entity: &proto.SceneEntityInfo_Gadget{
|
||||
Gadget: g.PacketSceneGadgetInfo(entity.gadgetEntity.gatherId),
|
||||
},
|
||||
EntityClientData: new(proto.EntityClientData),
|
||||
EntityAuthorityInfo: &proto.EntityAuthorityInfo{
|
||||
AbilityInfo: new(proto.AbilitySyncStateInfo),
|
||||
RendererChangedInfo: new(proto.EntityRendererChangedInfo),
|
||||
AiInfo: &proto.SceneEntityAiInfo{
|
||||
IsAiOpen: true,
|
||||
BornPos: new(proto.Vector),
|
||||
},
|
||||
BornPos: new(proto.Vector),
|
||||
},
|
||||
}
|
||||
return sceneEntityInfo
|
||||
}
|
||||
|
||||
func (g *GameManager) PacketSceneAvatarInfo(scene *Scene, player *model.Player, avatarId uint32) *proto.SceneAvatarInfo {
|
||||
activeAvatarId := player.TeamConfig.GetActiveAvatarId()
|
||||
activeAvatar := player.AvatarMap[activeAvatarId]
|
||||
playerTeamEntity := scene.GetPlayerTeamEntity(player.PlayerID)
|
||||
equipIdList := make([]uint32, 0)
|
||||
weapon := player.AvatarMap[avatarId].EquipWeapon
|
||||
equipIdList = append(equipIdList, weapon.ItemId)
|
||||
for _, reliquary := range player.AvatarMap[avatarId].EquipReliquaryList {
|
||||
equipIdList = append(equipIdList, reliquary.ItemId)
|
||||
}
|
||||
sceneAvatarInfo := &proto.SceneAvatarInfo{
|
||||
Uid: player.PlayerID,
|
||||
AvatarId: avatarId,
|
||||
Guid: player.AvatarMap[avatarId].Guid,
|
||||
PeerId: player.PeerId,
|
||||
EquipIdList: equipIdList,
|
||||
SkillDepotId: player.AvatarMap[avatarId].SkillDepotId,
|
||||
Weapon: &proto.SceneWeaponInfo{
|
||||
EntityId: playerTeamEntity.weaponEntityMap[activeAvatar.EquipWeapon.WeaponId],
|
||||
GadgetId: uint32(gdc.CONF.ItemDataMap[int32(weapon.ItemId)].GadgetId),
|
||||
ItemId: weapon.ItemId,
|
||||
Guid: weapon.Guid,
|
||||
Level: uint32(weapon.Level),
|
||||
AbilityInfo: new(proto.AbilitySyncStateInfo),
|
||||
},
|
||||
ReliquaryList: nil,
|
||||
SkillLevelMap: player.AvatarMap[avatarId].SkillLevelMap,
|
||||
WearingFlycloakId: player.AvatarMap[avatarId].FlyCloak,
|
||||
CostumeId: player.AvatarMap[avatarId].Costume,
|
||||
BornTime: uint32(player.AvatarMap[avatarId].BornTime),
|
||||
TeamResonanceList: make([]uint32, 0),
|
||||
}
|
||||
for id := range player.TeamConfig.TeamResonances {
|
||||
sceneAvatarInfo.TeamResonanceList = append(sceneAvatarInfo.TeamResonanceList, uint32(id))
|
||||
}
|
||||
return sceneAvatarInfo
|
||||
}
|
||||
|
||||
func (g *GameManager) PacketSceneMonsterInfo() *proto.SceneMonsterInfo {
|
||||
sceneMonsterInfo := &proto.SceneMonsterInfo{
|
||||
MonsterId: 20011301,
|
||||
AuthorityPeerId: 1,
|
||||
BornType: proto.MonsterBornType_MONSTER_BORN_TYPE_DEFAULT,
|
||||
BlockId: 3001,
|
||||
TitleId: 3001,
|
||||
SpecialNameId: 40,
|
||||
}
|
||||
return sceneMonsterInfo
|
||||
}
|
||||
|
||||
func (g *GameManager) PacketSceneGadgetInfo(gatherId uint32) *proto.SceneGadgetInfo {
|
||||
gather := gdc.CONF.GatherDataMap[int32(gatherId)]
|
||||
sceneGadgetInfo := &proto.SceneGadgetInfo{
|
||||
GadgetId: uint32(gather.GadgetId),
|
||||
//GroupId: 133003011,
|
||||
//ConfigId: 11001,
|
||||
GadgetState: 0,
|
||||
IsEnableInteract: false,
|
||||
AuthorityPeerId: 1,
|
||||
Content: &proto.SceneGadgetInfo_GatherGadget{
|
||||
GatherGadget: &proto.GatherGadgetInfo{
|
||||
ItemId: uint32(gather.ItemId),
|
||||
IsForbidGuest: false,
|
||||
},
|
||||
},
|
||||
}
|
||||
return sceneGadgetInfo
|
||||
}
|
||||
|
||||
func (g *GameManager) PacketDelTeamEntityNotify(scene *Scene, player *model.Player) *proto.DelTeamEntityNotify {
|
||||
delTeamEntityNotify := new(proto.DelTeamEntityNotify)
|
||||
delTeamEntityNotify.SceneId = player.SceneId
|
||||
playerTeamEntity := scene.GetPlayerTeamEntity(player.PlayerID)
|
||||
delTeamEntityNotify.DelEntityIdList = []uint32{playerTeamEntity.teamEntityId}
|
||||
return delTeamEntityNotify
|
||||
}
|
||||
129
gs/game/user_shop.go
Normal file
129
gs/game/user_shop.go
Normal file
@@ -0,0 +1,129 @@
|
||||
package game
|
||||
|
||||
import (
|
||||
pb "google.golang.org/protobuf/proto"
|
||||
"hk4e/gs/constant"
|
||||
"hk4e/gs/model"
|
||||
"hk4e/logger"
|
||||
"hk4e/protocol/cmd"
|
||||
"hk4e/protocol/proto"
|
||||
"time"
|
||||
)
|
||||
|
||||
func (g *GameManager) GetShopmallDataReq(player *model.Player, payloadMsg pb.Message) {
|
||||
logger.LOG.Debug("user get shop mall, uid: %v", player.PlayerID)
|
||||
|
||||
// PacketGetShopmallDataRsp
|
||||
getShopmallDataRsp := new(proto.GetShopmallDataRsp)
|
||||
getShopmallDataRsp.ShopTypeList = []uint32{900, 1052, 902, 1001, 903}
|
||||
g.SendMsg(cmd.GetShopmallDataRsp, player.PlayerID, player.ClientSeq, getShopmallDataRsp)
|
||||
}
|
||||
|
||||
func (g *GameManager) GetShopReq(player *model.Player, payloadMsg pb.Message) {
|
||||
logger.LOG.Debug("user get shop, uid: %v", player.PlayerID)
|
||||
req := payloadMsg.(*proto.GetShopReq)
|
||||
shopType := req.ShopType
|
||||
|
||||
if shopType != 1001 {
|
||||
return
|
||||
}
|
||||
|
||||
nextRefreshTime := uint32(time.Now().Add(time.Hour * 24 * 30).Unix())
|
||||
|
||||
// PacketGetShopRsp
|
||||
getShopRsp := new(proto.GetShopRsp)
|
||||
getShopRsp.Shop = &proto.Shop{
|
||||
GoodsList: []*proto.ShopGoods{
|
||||
{
|
||||
MinLevel: 1,
|
||||
EndTime: 2051193600,
|
||||
Hcoin: 160,
|
||||
GoodsId: 102001,
|
||||
NextRefreshTime: nextRefreshTime,
|
||||
MaxLevel: 99,
|
||||
BeginTime: 1575129600,
|
||||
GoodsItem: &proto.ItemParam{
|
||||
ItemId: 223,
|
||||
Count: 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
MinLevel: 1,
|
||||
EndTime: 2051193600,
|
||||
Hcoin: 160,
|
||||
GoodsId: 102002,
|
||||
NextRefreshTime: nextRefreshTime,
|
||||
MaxLevel: 99,
|
||||
BeginTime: 1575129600,
|
||||
GoodsItem: &proto.ItemParam{
|
||||
ItemId: 224,
|
||||
Count: 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
NextRefreshTime: nextRefreshTime,
|
||||
ShopType: 1001,
|
||||
}
|
||||
g.SendMsg(cmd.GetShopRsp, player.PlayerID, player.ClientSeq, getShopRsp)
|
||||
}
|
||||
|
||||
func (g *GameManager) BuyGoodsReq(player *model.Player, payloadMsg pb.Message) {
|
||||
logger.LOG.Debug("user buy goods, uid: %v", player.PlayerID)
|
||||
req := payloadMsg.(*proto.BuyGoodsReq)
|
||||
buyItemId := req.Goods.GoodsItem.ItemId
|
||||
buyItemCount := req.BuyCount
|
||||
costHcoinCount := req.Goods.Hcoin * buyItemCount
|
||||
|
||||
if buyItemId != 223 && buyItemId != 224 {
|
||||
return
|
||||
}
|
||||
|
||||
if player.GetItemCount(201) < costHcoinCount {
|
||||
return
|
||||
}
|
||||
g.CostUserItem(player.PlayerID, []*UserItem{{
|
||||
ItemId: 201,
|
||||
ChangeCount: costHcoinCount,
|
||||
}})
|
||||
|
||||
g.AddUserItem(player.PlayerID, []*UserItem{{
|
||||
ItemId: buyItemId,
|
||||
ChangeCount: buyItemCount,
|
||||
}}, true, constant.ActionReasonConst.Shop)
|
||||
req.Goods.BoughtNum = player.GetItemCount(buyItemId)
|
||||
|
||||
// PacketBuyGoodsRsp
|
||||
buyGoodsRsp := new(proto.BuyGoodsRsp)
|
||||
buyGoodsRsp.ShopType = req.ShopType
|
||||
buyGoodsRsp.BuyCount = req.BuyCount
|
||||
buyGoodsRsp.GoodsList = []*proto.ShopGoods{req.Goods}
|
||||
g.SendMsg(cmd.BuyGoodsRsp, player.PlayerID, player.ClientSeq, buyGoodsRsp)
|
||||
}
|
||||
|
||||
func (g *GameManager) McoinExchangeHcoinReq(player *model.Player, payloadMsg pb.Message) {
|
||||
logger.LOG.Debug("user mcoin exchange hcoin, uid: %v", player.PlayerID)
|
||||
req := payloadMsg.(*proto.McoinExchangeHcoinReq)
|
||||
if req.Hcoin != req.McoinCost {
|
||||
return
|
||||
}
|
||||
count := req.Hcoin
|
||||
|
||||
if player.GetItemCount(203) < count {
|
||||
return
|
||||
}
|
||||
g.CostUserItem(player.PlayerID, []*UserItem{{
|
||||
ItemId: 203,
|
||||
ChangeCount: count,
|
||||
}})
|
||||
|
||||
g.AddUserItem(player.PlayerID, []*UserItem{{
|
||||
ItemId: 201,
|
||||
ChangeCount: count,
|
||||
}}, false, 0)
|
||||
|
||||
// PacketMcoinExchangeHcoinRsp
|
||||
mcoinExchangeHcoinRsp := new(proto.McoinExchangeHcoinRsp)
|
||||
mcoinExchangeHcoinRsp.Hcoin = req.Hcoin
|
||||
mcoinExchangeHcoinRsp.McoinCost = req.McoinCost
|
||||
g.SendMsg(cmd.McoinExchangeHcoinRsp, player.PlayerID, player.ClientSeq, mcoinExchangeHcoinRsp)
|
||||
}
|
||||
335
gs/game/user_social.go
Normal file
335
gs/game/user_social.go
Normal file
@@ -0,0 +1,335 @@
|
||||
package game
|
||||
|
||||
import (
|
||||
pb "google.golang.org/protobuf/proto"
|
||||
"hk4e/common/utils/object"
|
||||
"hk4e/gs/constant"
|
||||
"hk4e/gs/model"
|
||||
"hk4e/logger"
|
||||
"hk4e/protocol/cmd"
|
||||
"hk4e/protocol/proto"
|
||||
"regexp"
|
||||
"time"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
func (g *GameManager) GetPlayerSocialDetailReq(player *model.Player, payloadMsg pb.Message) {
|
||||
logger.LOG.Debug("user get player social detail, uid: %v", player.PlayerID)
|
||||
req := payloadMsg.(*proto.GetPlayerSocialDetailReq)
|
||||
targetUid := req.Uid
|
||||
|
||||
// PacketGetPlayerSocialDetailRsp
|
||||
getPlayerSocialDetailRsp := new(proto.GetPlayerSocialDetailRsp)
|
||||
// TODO 同步阻塞待优化
|
||||
targetPlayer := g.userManager.LoadTempOfflineUserSync(targetUid)
|
||||
if targetPlayer != nil {
|
||||
socialDetail := new(proto.SocialDetail)
|
||||
socialDetail.Uid = targetPlayer.PlayerID
|
||||
socialDetail.ProfilePicture = &proto.ProfilePicture{AvatarId: targetPlayer.HeadImage}
|
||||
socialDetail.Nickname = targetPlayer.NickName
|
||||
socialDetail.Signature = targetPlayer.Signature
|
||||
socialDetail.Level = targetPlayer.PropertiesMap[constant.PlayerPropertyConst.PROP_PLAYER_LEVEL]
|
||||
socialDetail.Birthday = &proto.Birthday{Month: 2, Day: 13}
|
||||
socialDetail.WorldLevel = targetPlayer.PropertiesMap[constant.PlayerPropertyConst.PROP_PLAYER_WORLD_LEVEL]
|
||||
socialDetail.NameCardId = targetPlayer.NameCard
|
||||
socialDetail.IsShowAvatar = false
|
||||
socialDetail.FinishAchievementNum = 0
|
||||
_, exist := player.FriendList[targetPlayer.PlayerID]
|
||||
socialDetail.IsFriend = exist
|
||||
getPlayerSocialDetailRsp.DetailData = socialDetail
|
||||
} else {
|
||||
getPlayerSocialDetailRsp.Retcode = int32(proto.Retcode_RETCODE_RET_PLAYER_NOT_EXIST)
|
||||
}
|
||||
g.SendMsg(cmd.GetPlayerSocialDetailRsp, player.PlayerID, player.ClientSeq, getPlayerSocialDetailRsp)
|
||||
}
|
||||
|
||||
func (g *GameManager) SetPlayerBirthdayReq(player *model.Player, payloadMsg pb.Message) {
|
||||
logger.LOG.Debug("user set birthday, uid: %v", player.PlayerID)
|
||||
req := payloadMsg.(*proto.SetPlayerBirthdayReq)
|
||||
_ = req
|
||||
}
|
||||
|
||||
func (g *GameManager) SetNameCardReq(player *model.Player, payloadMsg pb.Message) {
|
||||
logger.LOG.Debug("user change name card, uid: %v", player.PlayerID)
|
||||
req := payloadMsg.(*proto.SetNameCardReq)
|
||||
nameCardId := req.NameCardId
|
||||
exist := false
|
||||
for _, nameCard := range player.NameCardList {
|
||||
if nameCard == nameCardId {
|
||||
exist = true
|
||||
}
|
||||
}
|
||||
if !exist {
|
||||
logger.LOG.Error("name card not exist, uid: %v", player.PlayerID)
|
||||
return
|
||||
}
|
||||
player.NameCard = nameCardId
|
||||
|
||||
// PacketSetNameCardRsp
|
||||
setNameCardRsp := new(proto.SetNameCardRsp)
|
||||
setNameCardRsp.NameCardId = nameCardId
|
||||
g.SendMsg(cmd.SetNameCardRsp, player.PlayerID, player.ClientSeq, setNameCardRsp)
|
||||
}
|
||||
|
||||
func (g *GameManager) SetPlayerSignatureReq(player *model.Player, payloadMsg pb.Message) {
|
||||
logger.LOG.Debug("user change signature, uid: %v", player.PlayerID)
|
||||
req := payloadMsg.(*proto.SetPlayerSignatureReq)
|
||||
signature := req.Signature
|
||||
|
||||
// PacketSetPlayerSignatureRsp
|
||||
setPlayerSignatureRsp := new(proto.SetPlayerSignatureRsp)
|
||||
if !object.IsUtf8String(signature) {
|
||||
setPlayerSignatureRsp.Retcode = int32(proto.Retcode_RETCODE_RET_SIGNATURE_ILLEGAL)
|
||||
} else if utf8.RuneCountInString(signature) > 50 {
|
||||
setPlayerSignatureRsp.Retcode = int32(proto.Retcode_RETCODE_RET_SIGNATURE_ILLEGAL)
|
||||
} else {
|
||||
player.Signature = signature
|
||||
setPlayerSignatureRsp.Signature = player.Signature
|
||||
}
|
||||
g.SendMsg(cmd.SetPlayerSignatureRsp, player.PlayerID, player.ClientSeq, setPlayerSignatureRsp)
|
||||
}
|
||||
|
||||
func (g *GameManager) SetPlayerNameReq(player *model.Player, payloadMsg pb.Message) {
|
||||
logger.LOG.Debug("user change nickname, uid: %v", player.PlayerID)
|
||||
req := payloadMsg.(*proto.SetPlayerNameReq)
|
||||
nickName := req.NickName
|
||||
|
||||
// PacketSetPlayerNameRsp
|
||||
setPlayerNameRsp := new(proto.SetPlayerNameRsp)
|
||||
if len(nickName) == 0 {
|
||||
setPlayerNameRsp.Retcode = int32(proto.Retcode_RETCODE_RET_NICKNAME_IS_EMPTY)
|
||||
} else if !object.IsUtf8String(nickName) {
|
||||
setPlayerNameRsp.Retcode = int32(proto.Retcode_RETCODE_RET_NICKNAME_UTF8_ERROR)
|
||||
} else if utf8.RuneCountInString(nickName) > 14 {
|
||||
setPlayerNameRsp.Retcode = int32(proto.Retcode_RETCODE_RET_NICKNAME_TOO_LONG)
|
||||
} else if len(regexp.MustCompile(`\d`).FindAllString(nickName, -1)) > 6 {
|
||||
setPlayerNameRsp.Retcode = int32(proto.Retcode_RETCODE_RET_NICKNAME_TOO_MANY_DIGITS)
|
||||
} else {
|
||||
player.NickName = nickName
|
||||
setPlayerNameRsp.NickName = player.NickName
|
||||
}
|
||||
g.SendMsg(cmd.SetPlayerNameRsp, player.PlayerID, player.ClientSeq, setPlayerNameRsp)
|
||||
}
|
||||
|
||||
func (g *GameManager) SetPlayerHeadImageReq(player *model.Player, payloadMsg pb.Message) {
|
||||
logger.LOG.Debug("user change head image, uid: %v", player.PlayerID)
|
||||
req := payloadMsg.(*proto.SetPlayerHeadImageReq)
|
||||
avatarId := req.AvatarId
|
||||
_, exist := player.AvatarMap[avatarId]
|
||||
if !exist {
|
||||
logger.LOG.Error("the head img of the avatar not exist, uid: %v", player.PlayerID)
|
||||
return
|
||||
}
|
||||
player.HeadImage = avatarId
|
||||
|
||||
// PacketSetPlayerHeadImageRsp
|
||||
setPlayerHeadImageRsp := new(proto.SetPlayerHeadImageRsp)
|
||||
setPlayerHeadImageRsp.ProfilePicture = &proto.ProfilePicture{AvatarId: player.HeadImage}
|
||||
g.SendMsg(cmd.SetPlayerHeadImageRsp, player.PlayerID, player.ClientSeq, setPlayerHeadImageRsp)
|
||||
}
|
||||
|
||||
func (g *GameManager) GetAllUnlockNameCardReq(player *model.Player, payloadMsg pb.Message) {
|
||||
logger.LOG.Debug("user get all unlock name card, uid: %v", player.PlayerID)
|
||||
|
||||
// PacketGetAllUnlockNameCardRsp
|
||||
getAllUnlockNameCardRsp := new(proto.GetAllUnlockNameCardRsp)
|
||||
getAllUnlockNameCardRsp.NameCardList = player.NameCardList
|
||||
g.SendMsg(cmd.GetAllUnlockNameCardRsp, player.PlayerID, player.ClientSeq, getAllUnlockNameCardRsp)
|
||||
}
|
||||
|
||||
func (g *GameManager) GetPlayerFriendListReq(player *model.Player, payloadMsg pb.Message) {
|
||||
logger.LOG.Debug("user get friend list, uid: %v", player.PlayerID)
|
||||
|
||||
// PacketGetPlayerFriendListRsp
|
||||
getPlayerFriendListRsp := new(proto.GetPlayerFriendListRsp)
|
||||
getPlayerFriendListRsp.FriendList = make([]*proto.FriendBrief, 0)
|
||||
for uid := range player.FriendList {
|
||||
// TODO 同步阻塞待优化
|
||||
var onlineState proto.FriendOnlineState
|
||||
online := g.userManager.GetUserOnlineState(uid)
|
||||
if online {
|
||||
onlineState = proto.FriendOnlineState_FRIEND_ONLINE_STATE_ONLINE
|
||||
} else {
|
||||
onlineState = proto.FriendOnlineState_FRIEND_ONLINE_STATE_FREIEND_DISCONNECT
|
||||
}
|
||||
friendPlayer := g.userManager.LoadTempOfflineUserSync(uid)
|
||||
if friendPlayer == nil {
|
||||
logger.LOG.Error("target player is nil, uid: %v", player.PlayerID)
|
||||
continue
|
||||
}
|
||||
friendBrief := &proto.FriendBrief{
|
||||
Uid: friendPlayer.PlayerID,
|
||||
Nickname: friendPlayer.NickName,
|
||||
Level: friendPlayer.PropertiesMap[constant.PlayerPropertyConst.PROP_PLAYER_LEVEL],
|
||||
ProfilePicture: &proto.ProfilePicture{AvatarId: friendPlayer.HeadImage},
|
||||
WorldLevel: friendPlayer.PropertiesMap[constant.PlayerPropertyConst.PROP_PLAYER_WORLD_LEVEL],
|
||||
Signature: friendPlayer.Signature,
|
||||
OnlineState: onlineState,
|
||||
IsMpModeAvailable: true,
|
||||
LastActiveTime: player.OfflineTime,
|
||||
NameCardId: friendPlayer.NameCard,
|
||||
Param: (uint32(time.Now().Unix()) - player.OfflineTime) / 3600 / 24,
|
||||
IsGameSource: true,
|
||||
PlatformType: proto.PlatformType_PLATFORM_TYPE_PC,
|
||||
}
|
||||
getPlayerFriendListRsp.FriendList = append(getPlayerFriendListRsp.FriendList, friendBrief)
|
||||
}
|
||||
g.SendMsg(cmd.GetPlayerFriendListRsp, player.PlayerID, player.ClientSeq, getPlayerFriendListRsp)
|
||||
}
|
||||
|
||||
func (g *GameManager) GetPlayerAskFriendListReq(player *model.Player, payloadMsg pb.Message) {
|
||||
logger.LOG.Debug("user get friend apply list, uid: %v", player.PlayerID)
|
||||
|
||||
// PacketGetPlayerAskFriendListRsp
|
||||
getPlayerAskFriendListRsp := new(proto.GetPlayerAskFriendListRsp)
|
||||
getPlayerAskFriendListRsp.AskFriendList = make([]*proto.FriendBrief, 0)
|
||||
for uid := range player.FriendApplyList {
|
||||
// TODO 同步阻塞待优化
|
||||
var onlineState proto.FriendOnlineState
|
||||
online := g.userManager.GetUserOnlineState(uid)
|
||||
if online {
|
||||
onlineState = proto.FriendOnlineState_FRIEND_ONLINE_STATE_ONLINE
|
||||
} else {
|
||||
onlineState = proto.FriendOnlineState_FRIEND_ONLINE_STATE_FREIEND_DISCONNECT
|
||||
}
|
||||
friendPlayer := g.userManager.LoadTempOfflineUserSync(uid)
|
||||
if friendPlayer == nil {
|
||||
logger.LOG.Error("target player is nil, uid: %v", player.PlayerID)
|
||||
continue
|
||||
}
|
||||
friendBrief := &proto.FriendBrief{
|
||||
Uid: friendPlayer.PlayerID,
|
||||
Nickname: friendPlayer.NickName,
|
||||
Level: friendPlayer.PropertiesMap[constant.PlayerPropertyConst.PROP_PLAYER_LEVEL],
|
||||
ProfilePicture: &proto.ProfilePicture{AvatarId: friendPlayer.HeadImage},
|
||||
WorldLevel: friendPlayer.PropertiesMap[constant.PlayerPropertyConst.PROP_PLAYER_WORLD_LEVEL],
|
||||
Signature: friendPlayer.Signature,
|
||||
OnlineState: onlineState,
|
||||
IsMpModeAvailable: true,
|
||||
LastActiveTime: player.OfflineTime,
|
||||
NameCardId: friendPlayer.NameCard,
|
||||
Param: (uint32(time.Now().Unix()) - player.OfflineTime) / 3600 / 24,
|
||||
IsGameSource: true,
|
||||
PlatformType: proto.PlatformType_PLATFORM_TYPE_PC,
|
||||
}
|
||||
getPlayerAskFriendListRsp.AskFriendList = append(getPlayerAskFriendListRsp.AskFriendList, friendBrief)
|
||||
}
|
||||
g.SendMsg(cmd.GetPlayerAskFriendListRsp, player.PlayerID, player.ClientSeq, getPlayerAskFriendListRsp)
|
||||
}
|
||||
|
||||
func (g *GameManager) AskAddFriendReq(player *model.Player, payloadMsg pb.Message) {
|
||||
logger.LOG.Debug("user apply add friend, uid: %v", player.PlayerID)
|
||||
req := payloadMsg.(*proto.AskAddFriendReq)
|
||||
targetUid := req.TargetUid
|
||||
|
||||
// TODO 同步阻塞待优化
|
||||
targetPlayerOnline := g.userManager.GetUserOnlineState(targetUid)
|
||||
targetPlayer := g.userManager.LoadTempOfflineUserSync(targetUid)
|
||||
if targetPlayer == nil {
|
||||
logger.LOG.Error("apply add friend target player is nil, uid: %v", player.PlayerID)
|
||||
return
|
||||
}
|
||||
_, applyExist := targetPlayer.FriendApplyList[player.PlayerID]
|
||||
_, friendExist := targetPlayer.FriendList[player.PlayerID]
|
||||
if applyExist || friendExist {
|
||||
logger.LOG.Error("friend or apply already exist, uid: %v", player.PlayerID)
|
||||
return
|
||||
}
|
||||
targetPlayer.FriendApplyList[player.PlayerID] = true
|
||||
|
||||
if targetPlayerOnline {
|
||||
// PacketAskAddFriendNotify
|
||||
askAddFriendNotify := new(proto.AskAddFriendNotify)
|
||||
askAddFriendNotify.TargetUid = player.PlayerID
|
||||
askAddFriendNotify.TargetFriendBrief = &proto.FriendBrief{
|
||||
Uid: player.PlayerID,
|
||||
Nickname: player.NickName,
|
||||
Level: player.PropertiesMap[constant.PlayerPropertyConst.PROP_PLAYER_LEVEL],
|
||||
ProfilePicture: &proto.ProfilePicture{AvatarId: player.HeadImage},
|
||||
WorldLevel: player.PropertiesMap[constant.PlayerPropertyConst.PROP_PLAYER_WORLD_LEVEL],
|
||||
Signature: player.Signature,
|
||||
OnlineState: proto.FriendOnlineState_FRIEND_ONLINE_STATE_ONLINE,
|
||||
IsMpModeAvailable: true,
|
||||
LastActiveTime: player.OfflineTime,
|
||||
NameCardId: player.NameCard,
|
||||
Param: (uint32(time.Now().Unix()) - player.OfflineTime) / 3600 / 24,
|
||||
IsGameSource: true,
|
||||
PlatformType: proto.PlatformType_PLATFORM_TYPE_PC,
|
||||
}
|
||||
g.SendMsg(cmd.AskAddFriendNotify, targetPlayer.PlayerID, targetPlayer.ClientSeq, askAddFriendNotify)
|
||||
}
|
||||
|
||||
// PacketAskAddFriendRsp
|
||||
askAddFriendRsp := new(proto.AskAddFriendRsp)
|
||||
askAddFriendRsp.TargetUid = targetUid
|
||||
g.SendMsg(cmd.AskAddFriendRsp, player.PlayerID, player.ClientSeq, askAddFriendRsp)
|
||||
}
|
||||
|
||||
func (g *GameManager) DealAddFriendReq(player *model.Player, payloadMsg pb.Message) {
|
||||
logger.LOG.Debug("user deal friend apply, uid: %v", player.PlayerID)
|
||||
req := payloadMsg.(*proto.DealAddFriendReq)
|
||||
targetUid := req.TargetUid
|
||||
result := req.DealAddFriendResult
|
||||
|
||||
if result == proto.DealAddFriendResultType_DEAL_ADD_FRIEND_RESULT_TYPE_ACCEPT {
|
||||
player.FriendList[targetUid] = true
|
||||
// TODO 同步阻塞待优化
|
||||
targetPlayer := g.userManager.LoadTempOfflineUserSync(targetUid)
|
||||
if targetPlayer == nil {
|
||||
logger.LOG.Error("agree friend apply target player is nil, uid: %v", player.PlayerID)
|
||||
return
|
||||
}
|
||||
targetPlayer.FriendList[player.PlayerID] = true
|
||||
}
|
||||
delete(player.FriendApplyList, targetUid)
|
||||
|
||||
// PacketDealAddFriendRsp
|
||||
dealAddFriendRsp := new(proto.DealAddFriendRsp)
|
||||
dealAddFriendRsp.TargetUid = targetUid
|
||||
dealAddFriendRsp.DealAddFriendResult = result
|
||||
g.SendMsg(cmd.DealAddFriendRsp, player.PlayerID, player.ClientSeq, dealAddFriendRsp)
|
||||
}
|
||||
|
||||
func (g *GameManager) GetOnlinePlayerListReq(player *model.Player, payloadMsg pb.Message) {
|
||||
logger.LOG.Debug("user get online player list, uid: %v", player.PlayerID)
|
||||
|
||||
count := 0
|
||||
onlinePlayerList := make([]*model.Player, 0)
|
||||
for _, onlinePlayer := range g.userManager.GetAllOnlineUserList() {
|
||||
if onlinePlayer.PlayerID == player.PlayerID {
|
||||
continue
|
||||
}
|
||||
onlinePlayerList = append(onlinePlayerList, onlinePlayer)
|
||||
count++
|
||||
if count >= 50 {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// PacketGetOnlinePlayerListRsp
|
||||
getOnlinePlayerListRsp := new(proto.GetOnlinePlayerListRsp)
|
||||
getOnlinePlayerListRsp.PlayerInfoList = make([]*proto.OnlinePlayerInfo, 0)
|
||||
for _, onlinePlayer := range onlinePlayerList {
|
||||
onlinePlayerInfo := g.PacketOnlinePlayerInfo(onlinePlayer)
|
||||
getOnlinePlayerListRsp.PlayerInfoList = append(getOnlinePlayerListRsp.PlayerInfoList, onlinePlayerInfo)
|
||||
}
|
||||
g.SendMsg(cmd.GetOnlinePlayerListRsp, player.PlayerID, player.ClientSeq, getOnlinePlayerListRsp)
|
||||
}
|
||||
|
||||
func (g *GameManager) PacketOnlinePlayerInfo(player *model.Player) *proto.OnlinePlayerInfo {
|
||||
onlinePlayerInfo := &proto.OnlinePlayerInfo{
|
||||
Uid: player.PlayerID,
|
||||
Nickname: player.NickName,
|
||||
PlayerLevel: player.PropertiesMap[constant.PlayerPropertyConst.PROP_PLAYER_LEVEL],
|
||||
MpSettingType: proto.MpSettingType(player.PropertiesMap[constant.PlayerPropertyConst.PROP_PLAYER_MP_SETTING_TYPE]),
|
||||
NameCardId: player.NameCard,
|
||||
Signature: player.Signature,
|
||||
ProfilePicture: &proto.ProfilePicture{AvatarId: player.HeadImage},
|
||||
CurPlayerNumInWorld: 1,
|
||||
}
|
||||
world := g.worldManager.GetWorldByID(player.WorldId)
|
||||
if world != nil && world.playerMap != nil {
|
||||
onlinePlayerInfo.CurPlayerNumInWorld = uint32(len(world.playerMap))
|
||||
}
|
||||
return onlinePlayerInfo
|
||||
}
|
||||
348
gs/game/user_team.go
Normal file
348
gs/game/user_team.go
Normal file
@@ -0,0 +1,348 @@
|
||||
package game
|
||||
|
||||
import (
|
||||
pb "google.golang.org/protobuf/proto"
|
||||
"hk4e/common/utils/endec"
|
||||
gdc "hk4e/gs/config"
|
||||
"hk4e/gs/constant"
|
||||
"hk4e/gs/model"
|
||||
"hk4e/logger"
|
||||
"hk4e/protocol/cmd"
|
||||
"hk4e/protocol/proto"
|
||||
)
|
||||
|
||||
func (g *GameManager) ChangeAvatarReq(player *model.Player, payloadMsg pb.Message) {
|
||||
logger.LOG.Debug("user change avatar, uid: %v", player.PlayerID)
|
||||
req := payloadMsg.(*proto.ChangeAvatarReq)
|
||||
targetAvatarGuid := req.Guid
|
||||
|
||||
world := g.worldManager.GetWorldByID(player.WorldId)
|
||||
scene := world.GetSceneById(player.SceneId)
|
||||
playerTeamEntity := scene.GetPlayerTeamEntity(player.PlayerID)
|
||||
|
||||
oldAvatarId := player.TeamConfig.GetActiveAvatarId()
|
||||
oldAvatar := player.AvatarMap[oldAvatarId]
|
||||
if oldAvatar.Guid == targetAvatarGuid {
|
||||
logger.LOG.Error("can not change to the same avatar, uid: %v, oldAvatarId: %v, oldAvatarGuid: %v", player.PlayerID, oldAvatarId, oldAvatar.Guid)
|
||||
return
|
||||
}
|
||||
activeTeam := player.TeamConfig.GetActiveTeam()
|
||||
index := -1
|
||||
for avatarIndex, avatarId := range activeTeam.AvatarIdList {
|
||||
if avatarId == 0 {
|
||||
break
|
||||
}
|
||||
if targetAvatarGuid == player.AvatarMap[avatarId].Guid {
|
||||
index = avatarIndex
|
||||
}
|
||||
}
|
||||
if index == -1 {
|
||||
logger.LOG.Error("can not find the target avatar in team, uid: %v, target avatar guid: %v", player.PlayerID, targetAvatarGuid)
|
||||
return
|
||||
}
|
||||
player.TeamConfig.CurrAvatarIndex = uint8(index)
|
||||
|
||||
entity := scene.GetEntity(playerTeamEntity.avatarEntityMap[oldAvatarId])
|
||||
if entity == nil {
|
||||
return
|
||||
}
|
||||
entity.moveState = uint16(proto.MotionState_MOTION_STATE_STANDBY)
|
||||
|
||||
// PacketSceneEntityDisappearNotify
|
||||
sceneEntityDisappearNotify := new(proto.SceneEntityDisappearNotify)
|
||||
sceneEntityDisappearNotify.DisappearType = proto.VisionType_VISION_TYPE_REPLACE
|
||||
sceneEntityDisappearNotify.EntityList = []uint32{playerTeamEntity.avatarEntityMap[oldAvatarId]}
|
||||
for _, scenePlayer := range scene.playerMap {
|
||||
g.SendMsg(cmd.SceneEntityDisappearNotify, scenePlayer.PlayerID, scenePlayer.ClientSeq, sceneEntityDisappearNotify)
|
||||
}
|
||||
|
||||
// PacketSceneEntityAppearNotify
|
||||
sceneEntityAppearNotify := new(proto.SceneEntityAppearNotify)
|
||||
sceneEntityAppearNotify.AppearType = proto.VisionType_VISION_TYPE_REPLACE
|
||||
sceneEntityAppearNotify.Param = playerTeamEntity.avatarEntityMap[oldAvatarId]
|
||||
sceneEntityAppearNotify.EntityList = []*proto.SceneEntityInfo{g.PacketSceneEntityInfoAvatar(scene, player, player.TeamConfig.GetActiveAvatarId())}
|
||||
for _, scenePlayer := range scene.playerMap {
|
||||
g.SendMsg(cmd.SceneEntityAppearNotify, scenePlayer.PlayerID, scenePlayer.ClientSeq, sceneEntityAppearNotify)
|
||||
}
|
||||
|
||||
// PacketChangeAvatarRsp
|
||||
changeAvatarRsp := new(proto.ChangeAvatarRsp)
|
||||
changeAvatarRsp.Retcode = int32(proto.Retcode_RETCODE_RET_SUCC)
|
||||
changeAvatarRsp.CurGuid = targetAvatarGuid
|
||||
g.SendMsg(cmd.ChangeAvatarRsp, player.PlayerID, player.ClientSeq, changeAvatarRsp)
|
||||
}
|
||||
|
||||
func (g *GameManager) SetUpAvatarTeamReq(player *model.Player, payloadMsg pb.Message) {
|
||||
logger.LOG.Debug("user change team, uid: %v", player.PlayerID)
|
||||
req := payloadMsg.(*proto.SetUpAvatarTeamReq)
|
||||
|
||||
teamId := req.TeamId
|
||||
if teamId <= 0 || teamId >= 5 {
|
||||
// PacketSetUpAvatarTeamRsp
|
||||
setUpAvatarTeamRsp := new(proto.SetUpAvatarTeamRsp)
|
||||
setUpAvatarTeamRsp.Retcode = int32(proto.Retcode_RETCODE_RET_SVR_ERROR)
|
||||
g.SendMsg(cmd.SetUpAvatarTeamRsp, player.PlayerID, player.ClientSeq, setUpAvatarTeamRsp)
|
||||
return
|
||||
}
|
||||
avatarGuidList := req.AvatarTeamGuidList
|
||||
world := g.worldManager.GetWorldByID(player.WorldId)
|
||||
multiTeam := teamId == 4
|
||||
selfTeam := teamId == uint32(player.TeamConfig.GetActiveTeamId())
|
||||
if (multiTeam && len(avatarGuidList) == 0) || (selfTeam && len(avatarGuidList) == 0) || len(avatarGuidList) > 4 || world.multiplayer {
|
||||
// PacketSetUpAvatarTeamRsp
|
||||
setUpAvatarTeamRsp := new(proto.SetUpAvatarTeamRsp)
|
||||
setUpAvatarTeamRsp.Retcode = int32(proto.Retcode_RETCODE_RET_SVR_ERROR)
|
||||
g.SendMsg(cmd.SetUpAvatarTeamRsp, player.PlayerID, player.ClientSeq, setUpAvatarTeamRsp)
|
||||
return
|
||||
}
|
||||
avatarIdList := make([]uint32, 0)
|
||||
for _, avatarGuid := range avatarGuidList {
|
||||
for avatarId, avatar := range player.AvatarMap {
|
||||
if avatarGuid == avatar.Guid {
|
||||
avatarIdList = append(avatarIdList, avatarId)
|
||||
}
|
||||
}
|
||||
}
|
||||
player.TeamConfig.ClearTeamAvatar(uint8(teamId - 1))
|
||||
for _, avatarId := range avatarIdList {
|
||||
player.TeamConfig.AddAvatarToTeam(avatarId, uint8(teamId-1))
|
||||
}
|
||||
|
||||
if world.multiplayer {
|
||||
// PacketSetUpAvatarTeamRsp
|
||||
setUpAvatarTeamRsp := new(proto.SetUpAvatarTeamRsp)
|
||||
setUpAvatarTeamRsp.Retcode = int32(proto.Retcode_RETCODE_RET_SVR_ERROR)
|
||||
g.SendMsg(cmd.SetUpAvatarTeamRsp, player.PlayerID, player.ClientSeq, setUpAvatarTeamRsp)
|
||||
return
|
||||
}
|
||||
|
||||
// PacketAvatarTeamUpdateNotify
|
||||
avatarTeamUpdateNotify := new(proto.AvatarTeamUpdateNotify)
|
||||
avatarTeamUpdateNotify.AvatarTeamMap = make(map[uint32]*proto.AvatarTeam)
|
||||
for teamIndex, team := range player.TeamConfig.TeamList {
|
||||
avatarTeam := new(proto.AvatarTeam)
|
||||
avatarTeam.TeamName = team.Name
|
||||
for _, avatarId := range team.AvatarIdList {
|
||||
if avatarId == 0 {
|
||||
break
|
||||
}
|
||||
avatarTeam.AvatarGuidList = append(avatarTeam.AvatarGuidList, player.AvatarMap[avatarId].Guid)
|
||||
}
|
||||
avatarTeamUpdateNotify.AvatarTeamMap[uint32(teamIndex)+1] = avatarTeam
|
||||
}
|
||||
g.SendMsg(cmd.AvatarTeamUpdateNotify, player.PlayerID, player.ClientSeq, avatarTeamUpdateNotify)
|
||||
|
||||
if selfTeam {
|
||||
player.TeamConfig.CurrAvatarIndex = 0
|
||||
player.TeamConfig.UpdateTeam()
|
||||
scene := world.GetSceneById(player.SceneId)
|
||||
scene.UpdatePlayerTeamEntity(player)
|
||||
|
||||
// PacketSceneTeamUpdateNotify
|
||||
sceneTeamUpdateNotify := g.PacketSceneTeamUpdateNotify(world)
|
||||
g.SendMsg(cmd.SceneTeamUpdateNotify, player.PlayerID, player.ClientSeq, sceneTeamUpdateNotify)
|
||||
|
||||
// PacketSetUpAvatarTeamRsp
|
||||
setUpAvatarTeamRsp := new(proto.SetUpAvatarTeamRsp)
|
||||
setUpAvatarTeamRsp.TeamId = teamId
|
||||
setUpAvatarTeamRsp.CurAvatarGuid = player.AvatarMap[player.TeamConfig.GetActiveAvatarId()].Guid
|
||||
team := player.TeamConfig.GetTeamByIndex(uint8(teamId - 1))
|
||||
for _, avatarId := range team.AvatarIdList {
|
||||
if avatarId == 0 {
|
||||
break
|
||||
}
|
||||
setUpAvatarTeamRsp.AvatarTeamGuidList = append(setUpAvatarTeamRsp.AvatarTeamGuidList, player.AvatarMap[avatarId].Guid)
|
||||
}
|
||||
g.SendMsg(cmd.SetUpAvatarTeamRsp, player.PlayerID, player.ClientSeq, setUpAvatarTeamRsp)
|
||||
} else {
|
||||
// PacketSetUpAvatarTeamRsp
|
||||
setUpAvatarTeamRsp := new(proto.SetUpAvatarTeamRsp)
|
||||
setUpAvatarTeamRsp.TeamId = teamId
|
||||
setUpAvatarTeamRsp.CurAvatarGuid = player.AvatarMap[player.TeamConfig.GetActiveAvatarId()].Guid
|
||||
team := player.TeamConfig.GetTeamByIndex(uint8(teamId - 1))
|
||||
for _, avatarId := range team.AvatarIdList {
|
||||
if avatarId == 0 {
|
||||
break
|
||||
}
|
||||
setUpAvatarTeamRsp.AvatarTeamGuidList = append(setUpAvatarTeamRsp.AvatarTeamGuidList, player.AvatarMap[avatarId].Guid)
|
||||
}
|
||||
g.SendMsg(cmd.SetUpAvatarTeamRsp, player.PlayerID, player.ClientSeq, setUpAvatarTeamRsp)
|
||||
}
|
||||
}
|
||||
|
||||
func (g *GameManager) ChooseCurAvatarTeamReq(player *model.Player, payloadMsg pb.Message) {
|
||||
logger.LOG.Debug("user switch team, uid: %v", player.PlayerID)
|
||||
req := payloadMsg.(*proto.ChooseCurAvatarTeamReq)
|
||||
teamId := req.TeamId
|
||||
world := g.worldManager.GetWorldByID(player.WorldId)
|
||||
if world.multiplayer {
|
||||
return
|
||||
}
|
||||
team := player.TeamConfig.GetTeamByIndex(uint8(teamId) - 1)
|
||||
if team == nil || len(team.AvatarIdList) == 0 {
|
||||
return
|
||||
}
|
||||
player.TeamConfig.CurrTeamIndex = uint8(teamId) - 1
|
||||
player.TeamConfig.CurrAvatarIndex = 0
|
||||
player.TeamConfig.UpdateTeam()
|
||||
scene := world.GetSceneById(player.SceneId)
|
||||
scene.UpdatePlayerTeamEntity(player)
|
||||
|
||||
// PacketSceneTeamUpdateNotify
|
||||
sceneTeamUpdateNotify := g.PacketSceneTeamUpdateNotify(world)
|
||||
g.SendMsg(cmd.SceneTeamUpdateNotify, player.PlayerID, player.ClientSeq, sceneTeamUpdateNotify)
|
||||
|
||||
// PacketChooseCurAvatarTeamRsp
|
||||
chooseCurAvatarTeamRsp := new(proto.ChooseCurAvatarTeamRsp)
|
||||
chooseCurAvatarTeamRsp.CurTeamId = teamId
|
||||
g.SendMsg(cmd.ChooseCurAvatarTeamRsp, player.PlayerID, player.ClientSeq, chooseCurAvatarTeamRsp)
|
||||
}
|
||||
|
||||
func (g *GameManager) ChangeMpTeamAvatarReq(player *model.Player, payloadMsg pb.Message) {
|
||||
logger.LOG.Debug("user change mp team, uid: %v", player.PlayerID)
|
||||
req := payloadMsg.(*proto.ChangeMpTeamAvatarReq)
|
||||
avatarGuidList := req.AvatarGuidList
|
||||
|
||||
world := g.worldManager.GetWorldByID(player.WorldId)
|
||||
if len(avatarGuidList) == 0 || len(avatarGuidList) > 4 || !world.multiplayer {
|
||||
// PacketChangeMpTeamAvatarRsp
|
||||
changeMpTeamAvatarRsp := new(proto.ChangeMpTeamAvatarRsp)
|
||||
changeMpTeamAvatarRsp.Retcode = int32(proto.Retcode_RETCODE_RET_SVR_ERROR)
|
||||
g.SendMsg(cmd.ChangeMpTeamAvatarRsp, player.PlayerID, player.ClientSeq, changeMpTeamAvatarRsp)
|
||||
return
|
||||
}
|
||||
avatarIdList := make([]uint32, 0)
|
||||
for _, avatarGuid := range avatarGuidList {
|
||||
for avatarId, avatar := range player.AvatarMap {
|
||||
if avatarGuid == avatar.Guid {
|
||||
avatarIdList = append(avatarIdList, avatarId)
|
||||
}
|
||||
}
|
||||
}
|
||||
player.TeamConfig.ClearTeamAvatar(3)
|
||||
for _, avatarId := range avatarIdList {
|
||||
player.TeamConfig.AddAvatarToTeam(avatarId, 3)
|
||||
}
|
||||
player.TeamConfig.CurrAvatarIndex = 0
|
||||
player.TeamConfig.UpdateTeam()
|
||||
scene := world.GetSceneById(player.SceneId)
|
||||
scene.UpdatePlayerTeamEntity(player)
|
||||
|
||||
for _, worldPlayer := range world.playerMap {
|
||||
// PacketSceneTeamUpdateNotify
|
||||
sceneTeamUpdateNotify := g.PacketSceneTeamUpdateNotify(world)
|
||||
g.SendMsg(cmd.SceneTeamUpdateNotify, worldPlayer.PlayerID, worldPlayer.ClientSeq, sceneTeamUpdateNotify)
|
||||
}
|
||||
|
||||
// PacketChangeMpTeamAvatarRsp
|
||||
changeMpTeamAvatarRsp := new(proto.ChangeMpTeamAvatarRsp)
|
||||
changeMpTeamAvatarRsp.CurAvatarGuid = player.AvatarMap[player.TeamConfig.GetActiveAvatarId()].Guid
|
||||
team := player.TeamConfig.GetTeamByIndex(3)
|
||||
for _, avatarId := range team.AvatarIdList {
|
||||
if avatarId == 0 {
|
||||
break
|
||||
}
|
||||
changeMpTeamAvatarRsp.AvatarGuidList = append(changeMpTeamAvatarRsp.AvatarGuidList, player.AvatarMap[avatarId].Guid)
|
||||
}
|
||||
g.SendMsg(cmd.ChangeMpTeamAvatarRsp, player.PlayerID, player.ClientSeq, changeMpTeamAvatarRsp)
|
||||
}
|
||||
|
||||
func (g *GameManager) PacketSceneTeamUpdateNotify(world *World) *proto.SceneTeamUpdateNotify {
|
||||
sceneTeamUpdateNotify := new(proto.SceneTeamUpdateNotify)
|
||||
sceneTeamUpdateNotify.IsInMp = world.multiplayer
|
||||
empty := new(proto.AbilitySyncStateInfo)
|
||||
for _, worldPlayer := range world.playerMap {
|
||||
worldPlayerScene := world.GetSceneById(worldPlayer.SceneId)
|
||||
worldPlayerTeamEntity := worldPlayerScene.GetPlayerTeamEntity(worldPlayer.PlayerID)
|
||||
team := worldPlayer.TeamConfig.GetActiveTeam()
|
||||
for _, avatarId := range team.AvatarIdList {
|
||||
if avatarId == 0 {
|
||||
break
|
||||
}
|
||||
worldPlayerAvatar := worldPlayer.AvatarMap[avatarId]
|
||||
equipIdList := make([]uint32, 0)
|
||||
weapon := worldPlayerAvatar.EquipWeapon
|
||||
equipIdList = append(equipIdList, weapon.ItemId)
|
||||
for _, reliquary := range worldPlayerAvatar.EquipReliquaryList {
|
||||
equipIdList = append(equipIdList, reliquary.ItemId)
|
||||
}
|
||||
sceneTeamAvatar := &proto.SceneTeamAvatar{
|
||||
PlayerUid: worldPlayer.PlayerID,
|
||||
AvatarGuid: worldPlayerAvatar.Guid,
|
||||
SceneId: worldPlayer.SceneId,
|
||||
EntityId: worldPlayerTeamEntity.avatarEntityMap[avatarId],
|
||||
SceneEntityInfo: g.PacketSceneEntityInfoAvatar(worldPlayerScene, worldPlayer, avatarId),
|
||||
WeaponGuid: worldPlayerAvatar.EquipWeapon.Guid,
|
||||
WeaponEntityId: worldPlayerTeamEntity.weaponEntityMap[worldPlayerAvatar.EquipWeapon.WeaponId],
|
||||
IsPlayerCurAvatar: worldPlayer.TeamConfig.GetActiveAvatarId() == avatarId,
|
||||
IsOnScene: worldPlayer.TeamConfig.GetActiveAvatarId() == avatarId,
|
||||
AvatarAbilityInfo: empty,
|
||||
WeaponAbilityInfo: empty,
|
||||
AbilityControlBlock: new(proto.AbilityControlBlock),
|
||||
}
|
||||
if world.multiplayer {
|
||||
sceneTeamAvatar.AvatarInfo = g.PacketAvatarInfo(worldPlayerAvatar)
|
||||
sceneTeamAvatar.SceneAvatarInfo = g.PacketSceneAvatarInfo(worldPlayerScene, worldPlayer, avatarId)
|
||||
}
|
||||
// add AbilityControlBlock
|
||||
avatarDataConfig := gdc.CONF.AvatarDataMap[int32(avatarId)]
|
||||
acb := sceneTeamAvatar.AbilityControlBlock
|
||||
embryoId := 0
|
||||
// add avatar abilities
|
||||
for _, abilityId := range avatarDataConfig.Abilities {
|
||||
embryoId++
|
||||
emb := &proto.AbilityEmbryo{
|
||||
AbilityId: uint32(embryoId),
|
||||
AbilityNameHash: uint32(abilityId),
|
||||
AbilityOverrideNameHash: uint32(constant.GameConstantConst.DEFAULT_ABILITY_NAME),
|
||||
}
|
||||
acb.AbilityEmbryoList = append(acb.AbilityEmbryoList, emb)
|
||||
}
|
||||
// add default abilities
|
||||
for _, abilityId := range constant.GameConstantConst.DEFAULT_ABILITY_HASHES {
|
||||
embryoId++
|
||||
emb := &proto.AbilityEmbryo{
|
||||
AbilityId: uint32(embryoId),
|
||||
AbilityNameHash: uint32(abilityId),
|
||||
AbilityOverrideNameHash: uint32(constant.GameConstantConst.DEFAULT_ABILITY_NAME),
|
||||
}
|
||||
acb.AbilityEmbryoList = append(acb.AbilityEmbryoList, emb)
|
||||
}
|
||||
// add team resonances
|
||||
for id := range worldPlayer.TeamConfig.TeamResonancesConfig {
|
||||
embryoId++
|
||||
emb := &proto.AbilityEmbryo{
|
||||
AbilityId: uint32(embryoId),
|
||||
AbilityNameHash: uint32(id),
|
||||
AbilityOverrideNameHash: uint32(constant.GameConstantConst.DEFAULT_ABILITY_NAME),
|
||||
}
|
||||
acb.AbilityEmbryoList = append(acb.AbilityEmbryoList, emb)
|
||||
}
|
||||
// add skill depot abilities
|
||||
skillDepot := gdc.CONF.AvatarSkillDepotDataMap[int32(worldPlayerAvatar.SkillDepotId)]
|
||||
if skillDepot != nil && len(skillDepot.Abilities) != 0 {
|
||||
for _, id := range skillDepot.Abilities {
|
||||
embryoId++
|
||||
emb := &proto.AbilityEmbryo{
|
||||
AbilityId: uint32(embryoId),
|
||||
AbilityNameHash: uint32(id),
|
||||
AbilityOverrideNameHash: uint32(constant.GameConstantConst.DEFAULT_ABILITY_NAME),
|
||||
}
|
||||
acb.AbilityEmbryoList = append(acb.AbilityEmbryoList, emb)
|
||||
}
|
||||
}
|
||||
// add equip abilities
|
||||
for skill := range worldPlayerAvatar.ExtraAbilityEmbryos {
|
||||
embryoId++
|
||||
emb := &proto.AbilityEmbryo{
|
||||
AbilityId: uint32(embryoId),
|
||||
AbilityNameHash: uint32(endec.Hk4eAbilityHashCode(skill)),
|
||||
AbilityOverrideNameHash: uint32(constant.GameConstantConst.DEFAULT_ABILITY_NAME),
|
||||
}
|
||||
acb.AbilityEmbryoList = append(acb.AbilityEmbryoList, emb)
|
||||
}
|
||||
sceneTeamUpdateNotify.SceneTeamAvatarList = append(sceneTeamUpdateNotify.SceneTeamAvatarList, sceneTeamAvatar)
|
||||
}
|
||||
}
|
||||
return sceneTeamUpdateNotify
|
||||
}
|
||||
78
gs/game/user_weapon.go
Normal file
78
gs/game/user_weapon.go
Normal file
@@ -0,0 +1,78 @@
|
||||
package game
|
||||
|
||||
import (
|
||||
gdc "hk4e/gs/config"
|
||||
"hk4e/gs/constant"
|
||||
"hk4e/logger"
|
||||
"hk4e/protocol/cmd"
|
||||
"hk4e/protocol/proto"
|
||||
)
|
||||
|
||||
func (g *GameManager) GetAllWeaponDataConfig() map[int32]*gdc.ItemData {
|
||||
allWeaponDataConfig := make(map[int32]*gdc.ItemData)
|
||||
for itemId, itemData := range gdc.CONF.ItemDataMap {
|
||||
if itemData.EquipEnumType != constant.EquipTypeConst.EQUIP_WEAPON {
|
||||
continue
|
||||
}
|
||||
if (itemId >= 10000 && itemId <= 10008) ||
|
||||
itemId == 11411 ||
|
||||
(itemId >= 11506 && itemId <= 11508) ||
|
||||
itemId == 12505 ||
|
||||
itemId == 12506 ||
|
||||
itemId == 12508 ||
|
||||
itemId == 12509 ||
|
||||
itemId == 13503 ||
|
||||
itemId == 13506 ||
|
||||
itemId == 14411 ||
|
||||
itemId == 14503 ||
|
||||
itemId == 14505 ||
|
||||
itemId == 14508 ||
|
||||
(itemId >= 15504 && itemId <= 15506) ||
|
||||
itemId == 20001 || itemId == 15306 || itemId == 14306 || itemId == 13304 || itemId == 12304 {
|
||||
// 跳过无效武器
|
||||
continue
|
||||
}
|
||||
allWeaponDataConfig[itemId] = itemData
|
||||
}
|
||||
return allWeaponDataConfig
|
||||
}
|
||||
|
||||
func (g *GameManager) AddUserWeapon(userId uint32, itemId uint32) uint64 {
|
||||
player := g.userManager.GetOnlineUser(userId)
|
||||
if player == nil {
|
||||
logger.LOG.Error("player is nil, uid: %v", userId)
|
||||
return 0
|
||||
}
|
||||
weaponId := uint64(g.snowflake.GenId())
|
||||
player.AddWeapon(itemId, weaponId)
|
||||
weapon := player.GetWeapon(weaponId)
|
||||
|
||||
// PacketStoreItemChangeNotify
|
||||
storeItemChangeNotify := new(proto.StoreItemChangeNotify)
|
||||
storeItemChangeNotify.StoreType = proto.StoreType_STORE_TYPE_PACK
|
||||
affixMap := make(map[uint32]uint32)
|
||||
for _, affixId := range weapon.AffixIdList {
|
||||
affixMap[affixId] = uint32(weapon.Refinement)
|
||||
}
|
||||
pbItem := &proto.Item{
|
||||
ItemId: itemId,
|
||||
Guid: player.GetWeaponGuid(weaponId),
|
||||
Detail: &proto.Item_Equip{
|
||||
Equip: &proto.Equip{
|
||||
Detail: &proto.Equip_Weapon{
|
||||
Weapon: &proto.Weapon{
|
||||
Level: uint32(weapon.Level),
|
||||
Exp: weapon.Exp,
|
||||
PromoteLevel: uint32(weapon.Promote),
|
||||
// key:武器效果id value:精炼等阶
|
||||
AffixMap: affixMap,
|
||||
},
|
||||
},
|
||||
IsLocked: weapon.Lock,
|
||||
},
|
||||
},
|
||||
}
|
||||
storeItemChangeNotify.ItemList = append(storeItemChangeNotify.ItemList, pbItem)
|
||||
g.SendMsg(cmd.StoreItemChangeNotify, userId, player.ClientSeq, storeItemChangeNotify)
|
||||
return weaponId
|
||||
}
|
||||
622
gs/game/world_manager.go
Normal file
622
gs/game/world_manager.go
Normal file
@@ -0,0 +1,622 @@
|
||||
package game
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/gob"
|
||||
pb "google.golang.org/protobuf/proto"
|
||||
"hk4e/common/utils/alg"
|
||||
gdc "hk4e/gs/config"
|
||||
"hk4e/gs/constant"
|
||||
"hk4e/gs/game/aoi"
|
||||
"hk4e/gs/model"
|
||||
"hk4e/logger"
|
||||
"hk4e/protocol/cmd"
|
||||
"hk4e/protocol/proto"
|
||||
"math"
|
||||
"time"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// 世界管理器
|
||||
|
||||
type MeshMapPos struct {
|
||||
X int16
|
||||
Y int16
|
||||
Z int16
|
||||
}
|
||||
|
||||
type WorldStatic struct {
|
||||
// x y z -> if terrain exist
|
||||
terrain map[MeshMapPos]bool
|
||||
// x y z -> gather id
|
||||
gather map[MeshMapPos]uint32
|
||||
pathfindingStartPos MeshMapPos
|
||||
pathfindingEndPos MeshMapPos
|
||||
pathVectorList []MeshMapPos
|
||||
aiMoveMeshSpeedParam int
|
||||
aiMoveVectorList []*model.Vector
|
||||
aiMoveCurrIndex int
|
||||
}
|
||||
|
||||
func NewWorldStatic() (r *WorldStatic) {
|
||||
r = new(WorldStatic)
|
||||
r.terrain = make(map[MeshMapPos]bool)
|
||||
r.gather = make(map[MeshMapPos]uint32)
|
||||
r.InitGather()
|
||||
r.pathfindingStartPos = MeshMapPos{
|
||||
X: 2747,
|
||||
Y: 194,
|
||||
Z: -1719,
|
||||
}
|
||||
r.pathfindingEndPos = MeshMapPos{
|
||||
X: 2588,
|
||||
Y: 211,
|
||||
Z: -1349,
|
||||
}
|
||||
r.pathVectorList = make([]MeshMapPos, 0)
|
||||
r.aiMoveMeshSpeedParam = 3
|
||||
r.aiMoveVectorList = make([]*model.Vector, 0)
|
||||
r.aiMoveCurrIndex = 0
|
||||
return r
|
||||
}
|
||||
|
||||
func (w *WorldStatic) ConvWSTMapToPFMap() map[alg.MeshMapPos]bool {
|
||||
return *(*map[alg.MeshMapPos]bool)(unsafe.Pointer(&w.terrain))
|
||||
}
|
||||
|
||||
func (w *WorldStatic) ConvWSPosToPFPos(v MeshMapPos) alg.MeshMapPos {
|
||||
return alg.MeshMapPos(v)
|
||||
}
|
||||
|
||||
func (w *WorldStatic) ConvPFPVLToWSPVL(v []alg.MeshMapPos) []MeshMapPos {
|
||||
return *(*[]MeshMapPos)(unsafe.Pointer(&v))
|
||||
}
|
||||
|
||||
func (w *WorldStatic) Pathfinding() {
|
||||
bfs := alg.NewBFS()
|
||||
bfs.InitMap(
|
||||
w.ConvWSTMapToPFMap(),
|
||||
w.ConvWSPosToPFPos(w.pathfindingStartPos),
|
||||
w.ConvWSPosToPFPos(w.pathfindingEndPos),
|
||||
100,
|
||||
)
|
||||
pathVectorList := bfs.Pathfinding()
|
||||
if pathVectorList == nil {
|
||||
logger.LOG.Error("could not find path")
|
||||
return
|
||||
}
|
||||
logger.LOG.Debug("find path success, path: %v", pathVectorList)
|
||||
w.pathVectorList = w.ConvPFPVLToWSPVL(pathVectorList)
|
||||
}
|
||||
|
||||
func (w *WorldStatic) ConvPathVectorListToAiMoveVectorList() {
|
||||
for index, currPathVector := range w.pathVectorList {
|
||||
if index > 0 {
|
||||
lastPathVector := w.pathVectorList[index-1]
|
||||
for i := 0; i < w.aiMoveMeshSpeedParam; i++ {
|
||||
w.aiMoveVectorList = append(w.aiMoveVectorList, &model.Vector{
|
||||
X: float64(lastPathVector.X) + float64(currPathVector.X-lastPathVector.X)/float64(w.aiMoveMeshSpeedParam)*float64(i),
|
||||
Y: float64(lastPathVector.Y) + float64(currPathVector.Y-lastPathVector.Y)/float64(w.aiMoveMeshSpeedParam)*float64(i),
|
||||
Z: float64(lastPathVector.Z) + float64(currPathVector.Z-lastPathVector.Z)/float64(w.aiMoveMeshSpeedParam)*float64(i),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (w *WorldStatic) InitTerrain() bool {
|
||||
data := gdc.CONF.ReadWorldTerrain()
|
||||
decoder := gob.NewDecoder(bytes.NewReader(data))
|
||||
err := decoder.Decode(&w.terrain)
|
||||
if err != nil {
|
||||
logger.LOG.Error("unmarshal world terrain data error: %v", err)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (w *WorldStatic) SaveTerrain() bool {
|
||||
var buffer bytes.Buffer
|
||||
encoder := gob.NewEncoder(&buffer)
|
||||
err := encoder.Encode(w.terrain)
|
||||
if err != nil {
|
||||
logger.LOG.Error("marshal world terrain data error: %v", err)
|
||||
return false
|
||||
}
|
||||
gdc.CONF.WriteWorldTerrain(buffer.Bytes())
|
||||
return true
|
||||
}
|
||||
|
||||
func (w *WorldStatic) GetTerrain(x int16, y int16, z int16) (exist bool) {
|
||||
pos := MeshMapPos{
|
||||
X: x,
|
||||
Y: y,
|
||||
Z: z,
|
||||
}
|
||||
exist = w.terrain[pos]
|
||||
return exist
|
||||
}
|
||||
|
||||
func (w *WorldStatic) SetTerrain(x int16, y int16, z int16) {
|
||||
pos := MeshMapPos{
|
||||
X: x,
|
||||
Y: y,
|
||||
Z: z,
|
||||
}
|
||||
w.terrain[pos] = true
|
||||
}
|
||||
|
||||
func (w *WorldStatic) InitGather() {
|
||||
}
|
||||
|
||||
func (w *WorldStatic) GetGather(x int16, y int16, z int16) (gatherId uint32, exist bool) {
|
||||
pos := MeshMapPos{
|
||||
X: x,
|
||||
Y: y,
|
||||
Z: z,
|
||||
}
|
||||
gatherId, exist = w.gather[pos]
|
||||
return gatherId, exist
|
||||
}
|
||||
|
||||
func (w *WorldStatic) SetGather(x int16, y int16, z int16, gatherId uint32) {
|
||||
pos := MeshMapPos{
|
||||
X: x,
|
||||
Y: y,
|
||||
Z: z,
|
||||
}
|
||||
w.gather[pos] = gatherId
|
||||
}
|
||||
|
||||
type WorldManager struct {
|
||||
worldMap map[uint32]*World
|
||||
snowflake *alg.SnowflakeWorker
|
||||
worldStatic *WorldStatic
|
||||
bigWorld *World
|
||||
}
|
||||
|
||||
func NewWorldManager(snowflake *alg.SnowflakeWorker) (r *WorldManager) {
|
||||
r = new(WorldManager)
|
||||
r.worldMap = make(map[uint32]*World)
|
||||
r.snowflake = snowflake
|
||||
r.worldStatic = NewWorldStatic()
|
||||
return r
|
||||
}
|
||||
|
||||
func (w *WorldManager) GetWorldByID(worldId uint32) *World {
|
||||
return w.worldMap[worldId]
|
||||
}
|
||||
|
||||
func (w *WorldManager) GetWorldMap() map[uint32]*World {
|
||||
return w.worldMap
|
||||
}
|
||||
|
||||
func (w *WorldManager) CreateWorld(owner *model.Player, multiplayer bool) *World {
|
||||
worldId := uint32(w.snowflake.GenId())
|
||||
world := &World{
|
||||
id: worldId,
|
||||
owner: owner,
|
||||
playerMap: make(map[uint32]*model.Player),
|
||||
sceneMap: make(map[uint32]*Scene),
|
||||
entityIdCounter: 0,
|
||||
worldLevel: 0,
|
||||
multiplayer: multiplayer,
|
||||
mpLevelEntityId: 0,
|
||||
chatMsgList: make([]*proto.ChatInfo, 0),
|
||||
// aoi划分
|
||||
// TODO 为减少内存占用暂时去掉Y轴AOI格子划分 原来的Y轴格子数量为80
|
||||
aoiManager: aoi.NewAoiManager(
|
||||
-8000, 4000, 120,
|
||||
-2000, 2000, 1,
|
||||
-5500, 6500, 120,
|
||||
),
|
||||
}
|
||||
if world.IsBigWorld() {
|
||||
world.aoiManager = aoi.NewAoiManager(
|
||||
-8000, 4000, 800,
|
||||
-2000, 2000, 1,
|
||||
-5500, 6500, 800,
|
||||
)
|
||||
}
|
||||
world.mpLevelEntityId = world.GetNextWorldEntityId(constant.EntityIdTypeConst.MPLEVEL)
|
||||
w.worldMap[worldId] = world
|
||||
return world
|
||||
}
|
||||
|
||||
func (w *WorldManager) DestroyWorld(worldId uint32) {
|
||||
world := w.GetWorldByID(worldId)
|
||||
for _, player := range world.playerMap {
|
||||
world.RemovePlayer(player)
|
||||
player.WorldId = 0
|
||||
}
|
||||
delete(w.worldMap, worldId)
|
||||
}
|
||||
|
||||
func (w *WorldManager) GetBigWorld() *World {
|
||||
return w.bigWorld
|
||||
}
|
||||
|
||||
func (w *WorldManager) InitBigWorld(owner *model.Player) {
|
||||
w.bigWorld = w.GetWorldByID(owner.WorldId)
|
||||
w.bigWorld.multiplayer = true
|
||||
}
|
||||
|
||||
type World struct {
|
||||
id uint32
|
||||
owner *model.Player
|
||||
playerMap map[uint32]*model.Player
|
||||
sceneMap map[uint32]*Scene
|
||||
entityIdCounter uint32
|
||||
worldLevel uint8
|
||||
multiplayer bool
|
||||
mpLevelEntityId uint32
|
||||
chatMsgList []*proto.ChatInfo
|
||||
aoiManager *aoi.AoiManager // 当前世界地图的aoi管理器
|
||||
}
|
||||
|
||||
func (w *World) GetNextWorldEntityId(entityType uint16) uint32 {
|
||||
w.entityIdCounter++
|
||||
ret := (uint32(entityType) << 24) + w.entityIdCounter
|
||||
return ret
|
||||
}
|
||||
|
||||
func (w *World) AddPlayer(player *model.Player, sceneId uint32) {
|
||||
player.PeerId = uint32(len(w.playerMap) + 1)
|
||||
w.playerMap[player.PlayerID] = player
|
||||
scene := w.GetSceneById(sceneId)
|
||||
scene.AddPlayer(player)
|
||||
}
|
||||
|
||||
func (w *World) RemovePlayer(player *model.Player) {
|
||||
scene := w.sceneMap[player.SceneId]
|
||||
scene.RemovePlayer(player)
|
||||
delete(w.playerMap, player.PlayerID)
|
||||
}
|
||||
|
||||
func (w *World) CreateScene(sceneId uint32) *Scene {
|
||||
scene := &Scene{
|
||||
id: sceneId,
|
||||
world: w,
|
||||
playerMap: make(map[uint32]*model.Player),
|
||||
entityMap: make(map[uint32]*Entity),
|
||||
playerTeamEntityMap: make(map[uint32]*PlayerTeamEntity),
|
||||
gameTime: 18 * 60,
|
||||
attackQueue: alg.NewRAQueue[*Attack](1000),
|
||||
createTime: time.Now().UnixMilli(),
|
||||
}
|
||||
w.sceneMap[sceneId] = scene
|
||||
return scene
|
||||
}
|
||||
|
||||
func (w *World) GetSceneById(sceneId uint32) *Scene {
|
||||
scene, exist := w.sceneMap[sceneId]
|
||||
if !exist {
|
||||
scene = w.CreateScene(sceneId)
|
||||
}
|
||||
return scene
|
||||
}
|
||||
|
||||
func (w *World) AddChat(chatInfo *proto.ChatInfo) {
|
||||
w.chatMsgList = append(w.chatMsgList, chatInfo)
|
||||
}
|
||||
|
||||
func (w *World) GetChatList() []*proto.ChatInfo {
|
||||
return w.chatMsgList
|
||||
}
|
||||
|
||||
func (w *World) IsBigWorld() bool {
|
||||
return w.owner.PlayerID == 1
|
||||
}
|
||||
|
||||
type Scene struct {
|
||||
id uint32
|
||||
world *World
|
||||
playerMap map[uint32]*model.Player
|
||||
entityMap map[uint32]*Entity
|
||||
playerTeamEntityMap map[uint32]*PlayerTeamEntity
|
||||
gameTime uint32
|
||||
attackQueue *alg.RAQueue[*Attack]
|
||||
createTime int64
|
||||
}
|
||||
|
||||
type AvatarEntity struct {
|
||||
uid uint32
|
||||
avatarId uint32
|
||||
}
|
||||
|
||||
type MonsterEntity struct {
|
||||
}
|
||||
|
||||
type GadgetEntity struct {
|
||||
gatherId uint32
|
||||
}
|
||||
|
||||
type Entity struct {
|
||||
id uint32
|
||||
scene *Scene
|
||||
pos *model.Vector
|
||||
rot *model.Vector
|
||||
moveState uint16
|
||||
lastMoveSceneTimeMs uint32
|
||||
lastMoveReliableSeq uint32
|
||||
fightProp map[uint32]float32
|
||||
entityType uint32
|
||||
level uint8
|
||||
avatarEntity *AvatarEntity
|
||||
monsterEntity *MonsterEntity
|
||||
gadgetEntity *GadgetEntity
|
||||
}
|
||||
|
||||
type PlayerTeamEntity struct {
|
||||
teamEntityId uint32
|
||||
avatarEntityMap map[uint32]uint32
|
||||
weaponEntityMap map[uint64]uint32
|
||||
}
|
||||
|
||||
type Attack struct {
|
||||
combatInvokeEntry *proto.CombatInvokeEntry
|
||||
uid uint32
|
||||
}
|
||||
|
||||
func (s *Scene) ChangeGameTime(time uint32) {
|
||||
s.gameTime = time % 1440
|
||||
}
|
||||
|
||||
func (s *Scene) GetSceneTime() int64 {
|
||||
now := time.Now().UnixMilli()
|
||||
return now - s.createTime
|
||||
}
|
||||
|
||||
func (s *Scene) GetPlayerTeamEntity(userId uint32) *PlayerTeamEntity {
|
||||
return s.playerTeamEntityMap[userId]
|
||||
}
|
||||
|
||||
func (s *Scene) CreatePlayerTeamEntity(player *model.Player) {
|
||||
playerTeamEntity := &PlayerTeamEntity{
|
||||
teamEntityId: s.world.GetNextWorldEntityId(constant.EntityIdTypeConst.TEAM),
|
||||
avatarEntityMap: make(map[uint32]uint32),
|
||||
weaponEntityMap: make(map[uint64]uint32),
|
||||
}
|
||||
s.playerTeamEntityMap[player.PlayerID] = playerTeamEntity
|
||||
}
|
||||
|
||||
func (s *Scene) UpdatePlayerTeamEntity(player *model.Player) {
|
||||
team := player.TeamConfig.GetActiveTeam()
|
||||
playerTeamEntity := s.playerTeamEntityMap[player.PlayerID]
|
||||
for _, avatarId := range team.AvatarIdList {
|
||||
if avatarId == 0 {
|
||||
break
|
||||
}
|
||||
avatar := player.AvatarMap[avatarId]
|
||||
avatarEntityId, exist := playerTeamEntity.avatarEntityMap[avatarId]
|
||||
if exist {
|
||||
s.DestroyEntity(avatarEntityId)
|
||||
}
|
||||
playerTeamEntity.avatarEntityMap[avatarId] = s.CreateEntityAvatar(player, avatarId)
|
||||
weaponEntityId, exist := playerTeamEntity.weaponEntityMap[avatar.EquipWeapon.WeaponId]
|
||||
if exist {
|
||||
s.DestroyEntity(weaponEntityId)
|
||||
}
|
||||
playerTeamEntity.weaponEntityMap[avatar.EquipWeapon.WeaponId] = s.CreateEntityWeapon()
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Scene) AddPlayer(player *model.Player) {
|
||||
s.playerMap[player.PlayerID] = player
|
||||
s.CreatePlayerTeamEntity(player)
|
||||
s.UpdatePlayerTeamEntity(player)
|
||||
}
|
||||
|
||||
func (s *Scene) RemovePlayer(player *model.Player) {
|
||||
playerTeamEntity := s.GetPlayerTeamEntity(player.PlayerID)
|
||||
for _, avatarEntityId := range playerTeamEntity.avatarEntityMap {
|
||||
s.DestroyEntity(avatarEntityId)
|
||||
}
|
||||
for _, weaponEntityId := range playerTeamEntity.weaponEntityMap {
|
||||
s.DestroyEntity(weaponEntityId)
|
||||
}
|
||||
delete(s.playerTeamEntityMap, player.PlayerID)
|
||||
delete(s.playerMap, player.PlayerID)
|
||||
}
|
||||
|
||||
func (s *Scene) CreateEntityAvatar(player *model.Player, avatarId uint32) uint32 {
|
||||
entityId := s.world.GetNextWorldEntityId(constant.EntityIdTypeConst.AVATAR)
|
||||
entity := &Entity{
|
||||
id: entityId,
|
||||
scene: s,
|
||||
pos: player.Pos,
|
||||
rot: player.Rot,
|
||||
moveState: uint16(proto.MotionState_MOTION_STATE_NONE),
|
||||
lastMoveSceneTimeMs: 0,
|
||||
lastMoveReliableSeq: 0,
|
||||
fightProp: player.AvatarMap[avatarId].FightPropMap,
|
||||
entityType: uint32(proto.ProtEntityType_PROT_ENTITY_TYPE_AVATAR),
|
||||
level: player.AvatarMap[avatarId].Level,
|
||||
avatarEntity: &AvatarEntity{
|
||||
uid: player.PlayerID,
|
||||
avatarId: avatarId,
|
||||
},
|
||||
}
|
||||
s.entityMap[entity.id] = entity
|
||||
if avatarId == player.TeamConfig.GetActiveAvatarId() {
|
||||
s.world.aoiManager.AddEntityIdToGridByPos(entity.id, float32(entity.pos.X), float32(entity.pos.Y), float32(entity.pos.Z))
|
||||
}
|
||||
return entity.id
|
||||
}
|
||||
|
||||
func (s *Scene) CreateEntityWeapon() uint32 {
|
||||
entityId := s.world.GetNextWorldEntityId(constant.EntityIdTypeConst.WEAPON)
|
||||
entity := &Entity{
|
||||
id: entityId,
|
||||
scene: s,
|
||||
pos: new(model.Vector),
|
||||
rot: new(model.Vector),
|
||||
moveState: uint16(proto.MotionState_MOTION_STATE_NONE),
|
||||
lastMoveSceneTimeMs: 0,
|
||||
lastMoveReliableSeq: 0,
|
||||
fightProp: nil,
|
||||
entityType: uint32(proto.ProtEntityType_PROT_ENTITY_TYPE_WEAPON),
|
||||
level: 0,
|
||||
}
|
||||
s.entityMap[entity.id] = entity
|
||||
return entity.id
|
||||
}
|
||||
|
||||
func (s *Scene) CreateEntityMonster(pos *model.Vector, level uint8, fightProp map[uint32]float32) uint32 {
|
||||
entityId := s.world.GetNextWorldEntityId(constant.EntityIdTypeConst.MONSTER)
|
||||
entity := &Entity{
|
||||
id: entityId,
|
||||
scene: s,
|
||||
pos: pos,
|
||||
rot: new(model.Vector),
|
||||
moveState: uint16(proto.MotionState_MOTION_STATE_NONE),
|
||||
lastMoveSceneTimeMs: 0,
|
||||
lastMoveReliableSeq: 0,
|
||||
fightProp: fightProp,
|
||||
entityType: uint32(proto.ProtEntityType_PROT_ENTITY_TYPE_MONSTER),
|
||||
level: level,
|
||||
}
|
||||
s.entityMap[entity.id] = entity
|
||||
s.world.aoiManager.AddEntityIdToGridByPos(entity.id, float32(entity.pos.X), float32(entity.pos.Y), float32(entity.pos.Z))
|
||||
return entity.id
|
||||
}
|
||||
|
||||
func (s *Scene) CreateEntityGadget(pos *model.Vector, gatherId uint32) uint32 {
|
||||
entityId := s.world.GetNextWorldEntityId(constant.EntityIdTypeConst.GADGET)
|
||||
entity := &Entity{
|
||||
id: entityId,
|
||||
scene: s,
|
||||
pos: pos,
|
||||
rot: new(model.Vector),
|
||||
moveState: uint16(proto.MotionState_MOTION_STATE_NONE),
|
||||
lastMoveSceneTimeMs: 0,
|
||||
lastMoveReliableSeq: 0,
|
||||
fightProp: map[uint32]float32{
|
||||
uint32(constant.FightPropertyConst.FIGHT_PROP_CUR_HP): math.MaxFloat32,
|
||||
uint32(constant.FightPropertyConst.FIGHT_PROP_MAX_HP): math.MaxFloat32,
|
||||
uint32(constant.FightPropertyConst.FIGHT_PROP_BASE_HP): float32(1),
|
||||
},
|
||||
entityType: uint32(proto.ProtEntityType_PROT_ENTITY_TYPE_GADGET),
|
||||
level: 0,
|
||||
gadgetEntity: &GadgetEntity{
|
||||
gatherId: gatherId,
|
||||
},
|
||||
}
|
||||
s.entityMap[entity.id] = entity
|
||||
s.world.aoiManager.AddEntityIdToGridByPos(entity.id, float32(entity.pos.X), float32(entity.pos.Y), float32(entity.pos.Z))
|
||||
return entity.id
|
||||
}
|
||||
|
||||
func (s *Scene) DestroyEntity(entityId uint32) {
|
||||
entity := s.GetEntity(entityId)
|
||||
if entity == nil {
|
||||
return
|
||||
}
|
||||
s.world.aoiManager.RemoveEntityIdFromGridByPos(entity.id, float32(entity.pos.X), float32(entity.pos.Y), float32(entity.pos.Z))
|
||||
delete(s.entityMap, entityId)
|
||||
}
|
||||
|
||||
func (s *Scene) GetEntity(entityId uint32) *Entity {
|
||||
return s.entityMap[entityId]
|
||||
}
|
||||
|
||||
func (s *Scene) AddAttack(attack *Attack) {
|
||||
s.attackQueue.EnQueue(attack)
|
||||
}
|
||||
|
||||
func (s *Scene) AttackHandler(gameManager *GameManager) {
|
||||
combatInvokeEntryListAll := make([]*proto.CombatInvokeEntry, 0)
|
||||
combatInvokeEntryListOther := make(map[uint32][]*proto.CombatInvokeEntry)
|
||||
combatInvokeEntryListHost := make([]*proto.CombatInvokeEntry, 0)
|
||||
|
||||
for s.attackQueue.Len() != 0 {
|
||||
attack := s.attackQueue.DeQueue()
|
||||
if attack.combatInvokeEntry == nil {
|
||||
logger.LOG.Error("error attack data, attack value: %v", attack)
|
||||
continue
|
||||
}
|
||||
|
||||
hitInfo := new(proto.EvtBeingHitInfo)
|
||||
err := pb.Unmarshal(attack.combatInvokeEntry.CombatData, hitInfo)
|
||||
if err != nil {
|
||||
logger.LOG.Error("parse combat invocations entity hit info error: %v", err)
|
||||
continue
|
||||
}
|
||||
|
||||
attackResult := hitInfo.AttackResult
|
||||
//logger.LOG.Debug("run attack handler, attackResult: %v", attackResult)
|
||||
target := s.entityMap[attackResult.DefenseId]
|
||||
if target == nil {
|
||||
logger.LOG.Error("could not found target, defense id: %v", attackResult.DefenseId)
|
||||
continue
|
||||
}
|
||||
attackResult.Damage *= 100
|
||||
damage := attackResult.Damage
|
||||
attackerId := attackResult.AttackerId
|
||||
_ = attackerId
|
||||
currHp := float32(0)
|
||||
if target.fightProp != nil {
|
||||
currHp = target.fightProp[uint32(constant.FightPropertyConst.FIGHT_PROP_CUR_HP)]
|
||||
currHp -= damage
|
||||
if currHp < 0 {
|
||||
currHp = 0
|
||||
}
|
||||
target.fightProp[uint32(constant.FightPropertyConst.FIGHT_PROP_CUR_HP)] = currHp
|
||||
}
|
||||
|
||||
// PacketEntityFightPropUpdateNotify
|
||||
entityFightPropUpdateNotify := new(proto.EntityFightPropUpdateNotify)
|
||||
entityFightPropUpdateNotify.EntityId = target.id
|
||||
entityFightPropUpdateNotify.FightPropMap = make(map[uint32]float32)
|
||||
entityFightPropUpdateNotify.FightPropMap[uint32(constant.FightPropertyConst.FIGHT_PROP_CUR_HP)] = currHp
|
||||
for _, player := range s.playerMap {
|
||||
gameManager.SendMsg(cmd.EntityFightPropUpdateNotify, player.PlayerID, player.ClientSeq, entityFightPropUpdateNotify)
|
||||
}
|
||||
|
||||
combatData, err := pb.Marshal(hitInfo)
|
||||
if err != nil {
|
||||
logger.LOG.Error("create combat invocations entity hit info error: %v", err)
|
||||
}
|
||||
attack.combatInvokeEntry.CombatData = combatData
|
||||
switch attack.combatInvokeEntry.ForwardType {
|
||||
case proto.ForwardType_FORWARD_TYPE_TO_ALL:
|
||||
combatInvokeEntryListAll = append(combatInvokeEntryListAll, attack.combatInvokeEntry)
|
||||
case proto.ForwardType_FORWARD_TYPE_TO_ALL_EXCEPT_CUR:
|
||||
fallthrough
|
||||
case proto.ForwardType_FORWARD_TYPE_TO_ALL_EXIST_EXCEPT_CUR:
|
||||
if combatInvokeEntryListOther[attack.uid] == nil {
|
||||
combatInvokeEntryListOther[attack.uid] = make([]*proto.CombatInvokeEntry, 0)
|
||||
}
|
||||
combatInvokeEntryListOther[attack.uid] = append(combatInvokeEntryListOther[attack.uid], attack.combatInvokeEntry)
|
||||
case proto.ForwardType_FORWARD_TYPE_TO_HOST:
|
||||
combatInvokeEntryListHost = append(combatInvokeEntryListHost, attack.combatInvokeEntry)
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
// PacketCombatInvocationsNotify
|
||||
if len(combatInvokeEntryListAll) > 0 {
|
||||
combatInvocationsNotifyAll := new(proto.CombatInvocationsNotify)
|
||||
combatInvocationsNotifyAll.InvokeList = combatInvokeEntryListAll
|
||||
for _, player := range s.playerMap {
|
||||
gameManager.SendMsg(cmd.CombatInvocationsNotify, player.PlayerID, player.ClientSeq, combatInvocationsNotifyAll)
|
||||
}
|
||||
}
|
||||
if len(combatInvokeEntryListOther) > 0 {
|
||||
for uid, list := range combatInvokeEntryListOther {
|
||||
combatInvocationsNotifyOther := new(proto.CombatInvocationsNotify)
|
||||
combatInvocationsNotifyOther.InvokeList = list
|
||||
for _, player := range s.playerMap {
|
||||
if player.PlayerID == uid {
|
||||
continue
|
||||
}
|
||||
gameManager.SendMsg(cmd.CombatInvocationsNotify, player.PlayerID, player.ClientSeq, combatInvocationsNotifyOther)
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(combatInvokeEntryListHost) > 0 {
|
||||
combatInvocationsNotifyHost := new(proto.CombatInvocationsNotify)
|
||||
combatInvocationsNotifyHost.InvokeList = combatInvokeEntryListHost
|
||||
gameManager.SendMsg(cmd.CombatInvocationsNotify, s.world.owner.PlayerID, s.world.owner.ClientSeq, combatInvocationsNotifyHost)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user