game_sync/gamesrv/base/scene.go

2583 lines
68 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package base
import (
"fmt"
"github.com/globalsign/mgo/bson"
"math"
"math/rand"
"strconv"
"time"
rawproto "google.golang.org/protobuf/proto"
"mongo.games.com/goserver/core/logger"
"mongo.games.com/goserver/core/netlib"
"mongo.games.com/goserver/core/utils"
"mongo.games.com/goserver/srvlib/action"
srvlibproto "mongo.games.com/goserver/srvlib/protocol"
"mongo.games.com/game/common"
"mongo.games.com/game/model"
"mongo.games.com/game/mq"
"mongo.games.com/game/proto"
"mongo.games.com/game/protocol/gamehall"
"mongo.games.com/game/protocol/player"
"mongo.games.com/game/protocol/server"
"mongo.games.com/game/protocol/webapi"
"mongo.games.com/game/srvdata"
)
const ReplayIdTf = "20060102150405"
var sceneRandSeed = time.Now().UnixNano()
var RobotSceneDBGameFreeSync = make(map[int]bool)
type GameScene interface {
SceneDestroy(force bool)
}
// todo 结构优化
type Scene struct {
*server.WGCreateScene
ws *netlib.Session // 大厅服
Rand *rand.Rand // 随机数生成器
ExtraData interface{} // 房间数据
aiMgr AIMgr //
WithLocalAI bool //
disbandGen int //第几次解散申请
disbandParam []int64 //解散参数
disbandPos int32 //发起解散的玩家位置
disbandTs int64 //解散发起时间戳
realPlayerNum int //真实玩家人数
robotNum int //机器人数量
robotLimit int //最大限制机器人数量
robotNumLastInvite int //上次邀请机器人时的数量
NumOfGames int //局数
Players map[int32]*Player //参与者
audiences map[int32]*Player //观众
sp ScenePolicy //场景游戏策略
rr *ReplayRecorder //回放记录器
rrVer int32 //录像的协议版本号
SceneState SceneState //场景状态
StateStartTime time.Time //状态开始时间
stateEndTime time.Time //状态结束时间
GameStartTime time.Time //游戏开始计时时间
GameNowTime time.Time //当局游戏开始时间
nextInviteTime time.Time //下次邀请机器人时间
inviteInterval int64 //邀请间隔
pause bool
Gaming bool
destroyed bool
completed bool
Testing bool //是否为测试场
graceDestroy bool //等待销毁
replayAddId int32
KeyGameId string //游戏类型唯一ID
KeyGamefreeId string //游戏场次唯一id
KeyGameDif string
GroupId int32 //分组id
bEnterAfterStart bool //是否允许中途加入
ClubId int32
RoomId string //俱乐部那个包间
RoomPos int32 //房间桌号
PumpCoin int32 //抽水比例,同一个俱乐部下面的抽水比例是一定的,百分比
DealyTime int64 //结算延时时间
CpCtx model.CoinPoolCtx //水池环境
CpControlled bool //被水池控制了
timerRandomRobot int64
nogDismiss int //检查机器人离场时的局数(同一局只检查一次)
SystemCoinOut int64 //本局游戏机器人营收 机器人赢:正值 机器人输:负值
ChessRank []int32
RealCtrl bool
CycleID string // 房卡场多轮对局id
LogId string // 游戏每局id
}
func NewScene(args *CreateSceneParam) *Scene {
gameId := int(args.GetGameId())
gameMode := int(args.GetGameMode())
sp := GetScenePolicy(gameId, gameMode)
if sp == nil {
logger.Logger.Errorf("Game id %v not register in ScenePolicyPool.", gameId)
return nil
}
tNow := time.Now()
s := &Scene{
WGCreateScene: args.WGCreateScene,
ws: args.Session,
Players: make(map[int32]*Player),
audiences: make(map[int32]*Player),
sp: sp,
GameStartTime: tNow,
inviteInterval: model.GameParamData.RobotInviteInitInterval,
bEnterAfterStart: args.GetEnterAfterStart(),
ChessRank: args.GetChessRank(),
KeyGameId: strconv.Itoa(int(args.GetGameId())),
KeyGamefreeId: strconv.Itoa(int(args.GetDBGameFree().GetId())),
KeyGameDif: args.GetDBGameFree().GetGameDif(),
}
s.CycleID, _ = model.AutoIncGameLogId()
s.rrVer = ReplayRecorderVer[gameId]
s.RecordReplayStart()
s.init()
return s
}
func (this *Scene) GetSceneType() int32 {
if this.GetDBGameFree() != nil {
return this.GetDBGameFree().GetSceneType()
}
return 0
}
func (this *Scene) GetInit() bool {
return this.init()
}
func (this *Scene) init() bool {
tNow := time.Now()
sceneRandSeed++
this.Rand = rand.New(rand.NewSource(sceneRandSeed))
this.nextInviteTime = tNow.Add(time.Second * time.Duration(this.Rand.Int63n(model.GameParamData.RobotInviteInitInterval)))
this.RandRobotCnt()
return true
}
func (this *Scene) GetParam(idx int) int64 {
if idx < 0 || idx >= len(this.Params) {
return -1
}
return this.Params[idx]
}
func (this *Scene) GetBetMap() []int64 {
return this.GetDBGameFree().GetOtherIntParams()
}
func (this *Scene) GetGameFreeId() int32 {
return this.GetDBGameFree().GetId()
}
func (this *Scene) GetKeyGameId() string {
return this.KeyGameId
}
func (this *Scene) SetKeyGameId(keyGameId string) {
this.KeyGameId = keyGameId
}
func (this *Scene) GetSceneId() int {
return int(this.SceneId)
}
func (this *Scene) SetSceneId(sceneId int) {
this.SceneId = int32(sceneId)
}
func (this *Scene) GetGroupId() int32 {
return this.GroupId
}
func (this *Scene) SetGroupId(groupId int32) {
this.GroupId = groupId
}
func (this *Scene) GetExtraData() interface{} {
return this.ExtraData
}
func (this *Scene) SetExtraData(data interface{}) {
this.ExtraData = data
}
func (this *Scene) GetSceneState() SceneState {
return this.SceneState
}
func (this *Scene) SetSceneState(state SceneState) {
this.SceneState = state
}
func (this *Scene) GetGameId() int {
return int(this.GameId)
}
func (this *Scene) SetGameId(gameId int) {
this.GameId = int32(gameId)
}
func (this *Scene) GetPlayerNum() int {
n := this.WGCreateScene.GetPlayerNum()
if n > 0 {
return int(n)
}
return int(this.PlayerNum)
}
func (this *Scene) SetPlayerNum(playerNum int) {
this.WGCreateScene.PlayerNum = int32(playerNum)
this.PlayerNum = int32(playerNum)
}
func (this *Scene) GetGameMode() int {
return int(this.GameMode)
}
func (this *Scene) SetGameMode(gameMode int) {
this.GameMode = int32(gameMode)
}
func (this *Scene) GetGaming() bool {
return this.Gaming
}
func (this *Scene) SetGaming(gaming bool) {
this.Gaming = gaming
}
func (this *Scene) GetTesting() bool {
return this.Testing
}
func (this *Scene) SetTesting(testing bool) {
this.Testing = testing
}
func (this *Scene) GetCreator() int32 {
return this.Creator
}
func (this *Scene) SetCreator(creator int32) {
this.Creator = creator
}
func (this *Scene) GetSceneMode() int {
return int(this.SceneMode)
}
func (this *Scene) SetSceneMode(sceneMode int) {
this.SceneMode = int32(sceneMode)
}
func (this *Scene) GetParams() []int64 {
return this.Params
}
func (this *Scene) GetStateStartTime() time.Time {
return this.StateStartTime
}
func (this *Scene) SetStateStartTime(stateStartTime time.Time) {
this.StateStartTime = stateStartTime
}
func (this *Scene) GetGameStartTime() time.Time {
return this.GameStartTime
}
func (this *Scene) SetGameStartTime(gameStartTime time.Time) {
this.GameStartTime = gameStartTime
}
func (this *Scene) GetGameNowTime() time.Time {
return this.GameNowTime
}
func (this *Scene) SetGameNowTime(gameNowTime time.Time) {
this.GameNowTime = gameNowTime
}
func (this *Scene) GetNumOfGames() int {
return this.NumOfGames
}
func (this *Scene) SetNumOfGames(numOfGames int) {
this.NumOfGames = numOfGames
}
func (this *Scene) GetCpCtx() model.CoinPoolCtx {
return this.CpCtx
}
func (this *Scene) SetCpCtx(cpCtx model.CoinPoolCtx) {
this.CpCtx = cpCtx
}
func (this *Scene) GetAudiences() map[int32]*Player {
return this.audiences
}
func (this *Scene) GetDisbandGen() int {
return this.disbandGen
}
func (this *Scene) SetDisbandGen(disbandGen int) {
this.disbandGen = disbandGen
}
func (this *Scene) GetScenePolicy() ScenePolicy {
return this.sp
}
func (this *Scene) SetScenePolicy(sp ScenePolicy) {
this.sp = sp
}
func (this *Scene) GetGraceDestroy() bool {
return this.graceDestroy
}
func (this *Scene) SetGraceDestroy() {
this.graceDestroy = true
}
func (this *Scene) GetCpControlled() bool {
return this.CpControlled
}
func (this *Scene) SetCpControlled(cpControlled bool) {
this.CpControlled = cpControlled
}
func (this *Scene) GetSystemCoinOut() int64 {
return this.SystemCoinOut
}
func (this *Scene) SetSystemCoinOut(systemCoinOut int64) {
this.SystemCoinOut = systemCoinOut
}
func (this *Scene) GetBEnterAfterStart() bool {
return this.bEnterAfterStart
}
func (this *Scene) SetBEnterAfterStart(bEnterAfterStart bool) {
this.bEnterAfterStart = bEnterAfterStart
}
func (this *Scene) GetTimerRandomRobot() int64 {
return this.timerRandomRobot
}
func (this *Scene) SetTimerRandomRobot(timerRandomRobot int64) {
this.timerRandomRobot = timerRandomRobot
}
func (this *Scene) GetDestroyed() bool {
return this.destroyed
}
func (this *Scene) SetDestroyed(destroyed bool) {
this.destroyed = destroyed
}
// ////////////////////////////////////////////////
func (this *Scene) OnStart() {
logger.Logger.Trace("Scene on start.")
this.sp.OnStart(this)
this.TryInviteRobot()
}
func (this *Scene) OnStop() {
logger.Logger.Trace("Scene on stop.")
this.sp.OnStop(this)
}
func (this *Scene) OnTick() {
if !this.pause {
this.TryInviteRobot()
this.sp.OnTick(this)
}
}
func (this *Scene) SendRoomType(p *Player) {
//通知客户端 当前房间类型
//RoomSign := &protocol.SCClubRoomSign{
// ClubId: proto.Int64(this.ClubId),
//}
//proto.SetDefaults(RoomSign)
//logger.Logger.Trace("RoomSign: ", RoomSign)
//p.SendToClient(int(protocol.MmoPacketID_PACKET_SC_CLUB_ROOMSIGN), RoomSign)
}
//////////////////////////////////////////////////
func (this *Scene) PlayerEnter(p *Player, isLoaded bool) {
logger.Logger.Trace("(this *Scene) PlayerEnter:", p.SnId, isLoaded, this.SceneId, p.GetName())
this.Players[p.SnId] = p
p.scene = this
pack := &gamehall.SCEnterRoom{
GameId: this.GameId,
ModeType: this.GameMode,
RoomId: this.SceneId,
OpRetCode: gamehall.OpResultCode_Game_OPRC_Sucess_Game,
Params: []int32{},
ClubId: proto.Int32(this.ClubId),
}
proto.SetDefaults(pack)
p.SendToClient(int(gamehall.GameHallPacketID_PACKET_SC_ENTERROOM), pack)
if p.IsRob {
this.robotNum++
logger.Logger.Tracef("(this *Scene) PlayerEnter(%v) robot(%v) robotlimit(%v)", this.GetDBGameFree().GetName()+this.GetDBGameFree().GetTitle(), this.robotNum, this.robotLimit)
} else {
p.Trusteeship = 0
p.ValidCacheBetTotal = 0
this.realPlayerNum++
this.RandRobotCnt()
}
p.OnEnter(this)
p.SyncFlagToWorld()
if !isLoaded && !p.IsRob { //等待玩家加载
p.MarkFlag(PlayerState_Leave)
}
//避免游戏接口异常
utils.RunPanicless(func() { this.sp.OnPlayerEnter(this, p) })
if p.WBLevel < 0 {
WarningBlackPlayer(p.SnId, this.GetDBGameFree().Id)
}
this.ResetNextInviteTime()
}
func (this *Scene) PlayerLeave(p *Player, reason int, isBill bool) {
logger.Logger.Trace("===(this *Scene) PlayerLeave ", p.SnId, reason, isBill)
//logger.Logger.Trace(utils.GetCallStack())
if _, exist := this.Players[p.SnId]; !exist {
logger.Logger.Warnf("(this *Scene) PlayerLeave(%v) no found in scene(%v)", p.SnId, this.SceneId)
return
}
//当前状态不能离场
if !this.CanChangeCoinScene(p) && !this.destroyed {
pack := &gamehall.SCLeaveRoom{
//OpRetCode: p.opCode, //protocol.OpResultCode_OPRC_Hundred_YouHadBetCannotLeave,
OpRetCode: gamehall.OpResultCode_Game(p.OpCode),
RoomId: this.SceneId,
}
if pack.GetOpRetCode() == gamehall.OpResultCode_Game_OPRC_Sucess_Game {
//不能这么做,机器人有特殊判定
//pack.OpRetCode = gamehall.OpResultCode_OPRC_Error
pack.OpRetCode = gamehall.OpResultCode_Game_OPRC_Error_Game
}
proto.SetDefaults(pack)
p.SendToClient(int(gamehall.GameHallPacketID_PACKET_SC_LEAVEROOM), pack)
logger.Logger.Tracef("(this *Scene) Cant PlayerLeave(%v) no found in scene(%v)", p.SnId, this.SceneId)
return
}
//避免游戏接口异常
utils.RunPanicless(func() { this.sp.OnPlayerLeave(this, p, reason) })
p.OnLeave(reason)
delete(this.Players, p.SnId)
isBill = true
//send world离开房间
pack := &server.GWPlayerLeave{
RoomId: this.SceneId,
PlayerId: proto.Int32(p.SnId),
Reason: proto.Int(reason),
ServiceFee: proto.Int64(p.serviceFee),
GameTimes: proto.Int32(p.GameTimes),
BetCoin: proto.Int64(p.TotalBet),
WinTimes: proto.Int(p.winTimes),
LostTimes: proto.Int(p.lostTimes),
TotalConvertibleFlow: proto.Int64(p.TotalConvertibleFlow),
ValidCacheBetTotal: proto.Int64(p.ValidCacheBetTotal),
MatchId: this.GetMatch().GetMatchSortId(),
CurIsWin: proto.Int64(p.CurIsWin), // 负数:输 0平局 正数:赢
}
matchRobotGrades := p.MatchRobotGrades
if matchRobotGrades != nil {
pack.MatchRobotGrades = make(map[int32]int32)
for _, gradeInfo := range matchRobotGrades {
pack.MatchRobotGrades[gradeInfo.CopySnid] = proto.Int32(gradeInfo.Grade)
}
p.MatchRobotGrades = nil
}
pack.ReturnCoin = proto.Int64(p.Coin)
if this.Testing {
pack.ReturnCoin = proto.Int64(p.takeCoin)
}
pack.GameCoinTs = proto.Int64(p.GameCoinTs)
if !p.IsLocal {
data, err := p.MarshalData(int(this.GameId))
if err == nil {
pack.PlayerData = data
}
}
//pack.Items = make(map[int32]int64)
//for id, num := range p.Items {
// pack.Items[id] = num
//}
pack.RankScore = make(map[int32]int64)
for k, v := range p.RankScore {
pack.RankScore[k] = v
}
proto.SetDefaults(pack)
this.SendToWorld(int(server.SSPacketID_PACKET_GW_PLAYERLEAVE), pack)
logger.Logger.Tracef("(this *Scene) PlayerLeave(%v) success reason %v", p.SnId, reason)
if p.IsRob {
this.robotNum--
if this.robotNum != len(this.Players) {
var num int
for _, p2 := range this.Players {
if p2.IsRob {
num++
}
}
this.robotNum = num
}
logger.Logger.Tracef("(this *Scene) PlayerLeave(%v) robot(%v) robotlimit(%v)", this.GetDBGameFree().GetName()+this.GetDBGameFree().GetTitle(), this.robotNum, this.robotLimit)
} else {
this.realPlayerNum--
this.RandRobotCnt()
}
this.ResetNextInviteTime()
}
func (this *Scene) AudienceEnter(p *Player, isload bool) {
logger.Logger.Trace("(this *Scene) AudienceEnter")
this.audiences[p.SnId] = p
p.scene = this
p.MarkFlag(PlayerState_Audience)
pack := &gamehall.SCEnterRoom{
GameId: this.GameId,
ModeType: this.GameMode,
RoomId: this.SceneId,
OpRetCode: gamehall.OpResultCode_Game_OPRC_Sucess_Game,
}
proto.SetDefaults(pack)
p.SendToClient(int(gamehall.GameHallPacketID_PACKET_SC_ENTERROOM), pack)
p.OnAudienceEnter(this)
if !isload && !p.IsRob {
p.MarkFlag(PlayerState_Leave)
}
//避免游戏接口异常
utils.RunPanicless(func() { this.sp.OnAudienceEnter(this, p) })
}
func (this *Scene) AudienceLeave(p *Player, reason int) {
logger.Logger.Trace("(this *Scene) AudienceLeave")
//当前状态不能离场
if !this.CanChangeCoinScene(p) {
pack := &gamehall.SCLeaveRoom{
OpRetCode: gamehall.OpResultCode_Game(p.OpCode), //protocol.OpResultCode_OPRC_Hundred_YouHadBetCannotLeave,
RoomId: this.SceneId,
}
proto.SetDefaults(pack)
p.SendToClient(int(gamehall.GameHallPacketID_PACKET_SC_LEAVEROOM), pack)
return
}
//避免游戏接口异常
utils.RunPanicless(func() { this.sp.OnAudienceLeave(this, p, reason) })
p.OnAudienceLeave(reason)
delete(this.audiences, p.SnId)
//send world离开房间
pack := &server.GWPlayerLeave{
RoomId: this.SceneId,
PlayerId: proto.Int32(p.SnId),
Reason: proto.Int(reason),
TotalConvertibleFlow: proto.Int64(p.TotalConvertibleFlow),
ValidCacheBetTotal: proto.Int64(p.ValidCacheBetTotal),
}
pack.ReturnCoin = proto.Int64(p.Coin)
if this.Testing {
pack.ReturnCoin = proto.Int64(p.takeCoin)
}
pack.GameCoinTs = proto.Int64(p.GameCoinTs)
// if p.dirty {
// data, err := p.MarshalData(this.gameId)
// if err == nil {
// pack.PlayerData = data
// }
// }
proto.SetDefaults(pack)
this.SendToWorld(int(server.SSPacketID_PACKET_GW_AUDIENCELEAVE), pack)
}
func (this *Scene) AudienceSit(p *Player) {
logger.Logger.Trace("(this *Scene) AudienceSit")
if _, exist := this.audiences[p.SnId]; exist {
delete(this.audiences, p.SnId)
this.Players[p.SnId] = p
p.scene = this
p.OnEnter(this)
//避免游戏接口异常
utils.RunPanicless(func() { this.sp.OnAudienceSit(this, p) })
if !p.IsRob {
this.realPlayerNum++
}
}
}
func (this *Scene) HasPlayer(p *Player) bool {
if p == nil {
return false
}
if pp, ok := this.Players[p.SnId]; ok && pp == p {
return true
}
return false
}
func (this *Scene) HasAudience(p *Player) bool {
if p == nil {
return false
}
if pp, ok := this.audiences[p.SnId]; ok && pp == p {
return true
}
return false
}
func (this *Scene) GetPlayer(id int32) *Player {
if p, exist := this.Players[id]; exist {
return p
}
return nil
}
func (this *Scene) GetPlayerByPos(pos int) *Player {
for _, p := range this.Players {
if p.Pos == pos {
return p
}
}
return nil
}
func (this *Scene) PlayerDropLine(snid int32) {
logger.Logger.Trace("(this *Scene) PlayerDropLine")
if p, exist := this.Players[snid]; exist {
p.OnDropLine()
//避免游戏接口异常
utils.RunPanicless(func() { this.sp.OnPlayerDropLine(this, p) })
} else if p, exist := this.audiences[snid]; exist {
p.OnAudienceDropLine()
//避免游戏接口异常
utils.RunPanicless(func() { this.sp.OnAudienceDropLine(this, p) })
}
}
func (this *Scene) PlayerRehold(snid int32, sid int64, gs *netlib.Session) {
logger.Logger.Trace("(this *Scene) PlayerRehold")
if p, exist := this.Players[snid]; exist {
p.OnRehold(sid, gs)
//if !p.IsRob {
// p.trusteeship = 0
//}
//避免游戏接口异常
utils.RunPanicless(func() { this.sp.OnPlayerRehold(this, p) })
} else if p, exist := this.audiences[snid]; exist {
p.OnRehold(sid, gs)
//if !p.IsRob {
// p.trusteeship = 0
//}
//避免游戏接口异常
utils.RunPanicless(func() { this.sp.OnAudienceEnter(this, p) })
}
}
func (this *Scene) PlayerReturn(p *Player, isLoaded bool) {
logger.Logger.Trace("(this *Scene) PlayerReturn")
pack := &gamehall.SCReturnRoom{
RoomId: this.SceneId,
GameId: this.GameId,
ModeType: this.GameMode,
Params: common.CopySliceInt64ToInt32(this.Params),
HallId: this.GetDBGameFree().GetId(),
IsLoaded: proto.Bool(isLoaded),
OpRetCode: gamehall.OpResultCode_Game_OPRC_Sucess_Game,
ClubId: proto.Int32(this.ClubId),
}
proto.SetDefaults(pack)
p.SendToClient(int(gamehall.GameHallPacketID_PACKET_SC_RETURNROOM), pack)
logger.Logger.Tracef("Scene.PlayerReturn %v", pack)
//if !p.IsRob {
// p.trusteeship = 0
//}
if this.HasPlayer(p) {
//避免游戏接口异常
//utils.RunPanicless(func() { this.sp.OnPlayerRehold(this, p) })
//这里应该调用 return消息 因为在上面rehold的消息已经处理过了
utils.RunPanicless(func() { this.sp.OnPlayerReturn(this, p) })
} else if this.HasAudience(p) {
//避免游戏接口异常
utils.RunPanicless(func() { this.sp.OnAudienceEnter(this, p) })
}
if !p.IsRob { //等待玩家加载
if isLoaded {
p.UnmarkFlag(PlayerState_Leave)
} else {
p.MarkFlag(PlayerState_Leave)
}
}
if this.IsMatchScene() {
p.SetIParam(common.PlayerIParam_IsQuit, 0)
p.UnmarkFlag(PlayerState_MatchQuit)
}
}
// 广播消息
func (this *Scene) Broadcast(packetid int, msg rawproto.Message, excludeSid int64, includeOffline ...bool) {
excludePos := -1
mgs := make(map[*netlib.Session][]*srvlibproto.MCSessionUnion)
for _, p := range this.Players {
if p != nil {
if p.sid != excludeSid {
if (p.gateSess != nil && p.IsOnLine() && !p.IsMarkFlag(PlayerState_Leave)) || len(includeOffline) != 0 {
mgs[p.gateSess] = append(mgs[p.gateSess], &srvlibproto.MCSessionUnion{
Mccs: &srvlibproto.MCClientSession{
SId: proto.Int64(p.sid),
},
})
}
}
if p.sid == excludeSid {
excludePos = p.Pos
}
}
}
for _, p := range this.audiences {
if p != nil && p.sid != excludeSid {
if (p.gateSess != nil && p.IsOnLine() && !p.IsMarkFlag(PlayerState_Leave)) || len(includeOffline) != 0 {
mgs[p.gateSess] = append(mgs[p.gateSess], &srvlibproto.MCSessionUnion{
Mccs: &srvlibproto.MCClientSession{
SId: proto.Int64(p.sid),
},
})
}
}
}
if this.rr != nil && !this.Testing && this.Gaming && !this.IsHundredScene() && !this.IsMatchScene() {
this.rr.Record(-1, excludePos, packetid, msg)
}
for gateSess, v := range mgs {
if gateSess != nil && len(v) != 0 {
action.MulticastMessageToServer(gateSess, packetid, msg, v...)
}
}
}
func (this *Scene) RobotBroadcast(packetid int, msg rawproto.Message) {
mgs := make(map[*netlib.Session][]*srvlibproto.MCSessionUnion)
for _, p := range this.Players {
if p != nil && p.IsRob {
if p.gateSess != nil && p.IsOnLine() && !p.IsMarkFlag(PlayerState_Leave) {
mgs[p.gateSess] = append(mgs[p.gateSess], &srvlibproto.MCSessionUnion{
Mccs: &srvlibproto.MCClientSession{
SId: proto.Int64(p.sid),
},
})
}
}
}
for gateSess, v := range mgs {
if gateSess != nil && len(v) != 0 {
action.MulticastMessageToServer(gateSess, packetid, msg, v...)
}
}
}
func (this *Scene) BroadcastToAudience(packetid int, msg rawproto.Message) {
if len(this.audiences) > 0 {
mgs := make(map[*netlib.Session][]*srvlibproto.MCSessionUnion)
for _, p := range this.audiences {
if p != nil {
if p.gateSess != nil && p.IsOnLine() {
mgs[p.gateSess] = append(mgs[p.gateSess], &srvlibproto.MCSessionUnion{
Mccs: &srvlibproto.MCClientSession{
SId: proto.Int64(p.sid),
},
})
}
}
}
for gateSess, v := range mgs {
if gateSess != nil && len(v) != 0 {
action.MulticastMessageToServer(gateSess, packetid, msg, v...)
}
}
}
}
func (this *Scene) GetAudiencesNum() int {
if this.audiences != nil {
return len(this.audiences)
}
return 0
}
func (this *Scene) ChangeSceneState(stateid int) {
if this.destroyed {
return
}
state := this.sp.GetSceneState(this, stateid)
if state == nil {
return
}
oldState := -1
if this.SceneState != nil {
oldState = this.SceneState.GetState()
if this.SceneState.CanChangeTo(state) {
logger.Logger.Tracef("(this *Scene) [%v] ChangeSceneState %v -> %v", this.SceneId, this.SceneState.GetState(), state.GetState())
this.SceneState.OnLeave(this)
this.SceneState = state
this.SceneState.OnEnter(this)
this.sp.NotifyGameState(this)
} else {
logger.Logger.Tracef("(this *Scene) [%v] ChangeSceneState failed %v -> %v", this.SceneId, this.SceneState.GetState(), state.GetState())
}
} else {
logger.Logger.Tracef("(this *Scene) [%v] ChangeSceneState -> %v", this.SceneId, state.GetState())
this.SceneState = state
this.SceneState.OnEnter(this)
//this.SyncSceneState(stateid)
}
if this.aiMgr != nil {
this.aiMgr.OnChangeState(this, oldState, stateid)
}
}
func (this *Scene) SendToWorld(packetid int, pack interface{}) {
if this.ws != nil {
this.ws.Send(packetid, pack)
}
}
func (this *Scene) FirePlayerEvent(p *Player, evtcode int, params []int64) {
if this.SceneState != nil {
this.SceneState.OnPlayerEvent(this, p, evtcode, params)
}
////比赛事件
//if this.mp != nil {
// this.mp.OnPlayerEvent(this, p, evtcode, params)
//}
}
func (this *Scene) Pause() {
this.pause = true
}
// RankMatchDestroy 排位解散房间
func (this *Scene) RankMatchDestroy() {
if this.IsRankMatch() {
this.Destroy(true)
}
}
func (this *Scene) Destroy(force bool) {
this.destroyed = true
this.pause = true
if !this.IsMatchScene() {
for _, p := range this.Players {
this.PlayerLeave(p, common.PlayerLeaveReason_OnDestroy, true)
}
for _, p := range this.audiences {
this.AudienceLeave(p, common.PlayerLeaveReason_OnDestroy)
}
} else {
for _, p := range this.Players {
this.PlayerLeave(p, common.PlayerLeaveReason_OnBilled, true)
}
}
for _, p := range this.Players {
PlayerMgrSington.DelPlayerBySnId(p.SnId)
}
for _, p := range this.audiences {
PlayerMgrSington.DelPlayerBySnId(p.SnId)
}
isCompleted := this.sp.IsCompleted(this) || this.completed
SceneMgrSington.DestroyScene(int(this.SceneId))
pack := &server.GWDestroyScene{
SceneId: int64(this.SceneId),
IsCompleted: isCompleted,
}
proto.SetDefaults(pack)
this.SendToWorld(int(server.SSPacketID_PACKET_GW_DESTROYSCENE), pack)
logger.Logger.Trace("(this *Scene) Destroy(force bool) isCompleted", isCompleted)
}
// IsSceneMode 房间模式
func (this *Scene) IsSceneMode(mode int) bool {
return this.SceneMode == int32(mode)
}
func (this *Scene) IsPrivateScene() bool {
return this.IsSceneMode(common.SceneModePrivate) || this.IsSceneMode(common.SceneModePrivateMatch)
}
// IsFreePublic 自由桌
func (this *Scene) IsFreePublic() bool {
return this.GetDBGameFree().GetFreeMode() == 1
}
// IsRankMatch 排位赛
func (this *Scene) IsRankMatch() bool {
return this.GetDBGameFree().GetRankType() > 0
}
// IsMatchScene 比赛场
func (this *Scene) IsMatchScene() bool {
return this.IsSceneMode(common.SceneModeMatch)
}
func (this *Scene) IsCustom() bool {
if this.IsSceneMode(common.SceneModePrivateMatch) {
return true
}
return this.GetDBGameFree().GetIsCustom() > 0
}
func (this *Scene) IsFull() bool {
return len(this.Players) >= this.GetPlayerNum()
}
// 对战场
func (this *Scene) IsCoinScene() bool {
return this.SceneId >= common.CoinSceneStartId && this.SceneId <= common.CoinSceneMaxId
}
// 百人场
func (this *Scene) IsHundredScene() bool {
return this.SceneId >= common.HundredSceneStartId && this.SceneId <= common.HundredSceneMaxId
}
func (this *Scene) GetCoinSceneLowerThanKick() int64 {
if this.GetDBGameFree() != nil {
return this.GetDBGameFree().GetLowerThanKick()
}
return 0
}
func (this *Scene) GetCoinSceneMaxCoinLimit() int64 {
if this.GetDBGameFree() != nil {
return this.GetDBGameFree().GetMaxCoinLimit()
}
return 0
}
// CoinInLimitLocal 本地游戏入场限额检查
func (this *Scene) CoinInLimitLocal(coin int64) bool {
minCoin := this.GetLimitCoin()
if minCoin != 0 && coin < minCoin {
return false
}
if coin <= 0 {
return false
}
return true
}
// NotCoinInLimitType 金额超出入场限额,返回踢出类型
func (this *Scene) NotCoinInLimitType(coin int64) int {
if common.IsLocalGame(int(this.GameId)) {
minCoin := this.GetLimitCoin()
if minCoin != 0 && coin < minCoin {
return common.PlayerLeaveReason_Bekickout
}
if coin <= 0 {
return common.PlayerLeaveReason_Bekickout
}
return common.PlayerLeaveReason_Normal
}
minCoin := int(this.GetCoinSceneLowerThanKick())
maxCoin := int(this.GetCoinSceneMaxCoinLimit())
if minCoin != 0 && coin < int64(minCoin) {
return common.PlayerLeaveReason_Bekickout
}
if maxCoin != 0 && coin > int64(maxCoin) {
return common.PlayerLeaveReason_RoomMaxCoin
}
if coin <= 0 {
return common.PlayerLeaveReason_Bekickout
}
return common.PlayerLeaveReason_Normal
}
// CoinInLimit 单入场限额检查
func (this *Scene) CoinInLimit(coin int64) bool {
if common.IsLocalGame(int(this.GameId)) {
return this.CoinInLimitLocal(coin)
}
minCoin := int(this.GetCoinSceneLowerThanKick())
maxCoin := int(this.GetCoinSceneMaxCoinLimit())
if minCoin != 0 && coin < int64(minCoin) {
return false
}
if maxCoin != 0 && coin > int64(maxCoin) {
return false
}
if coin <= 0 {
return false
}
return true
}
// 根据底注去取createroom表里面的最小携带金额
func (this *Scene) GetLimitCoin() int64 {
limitCoin := int64(0)
tmpIds := []int32{}
for _, data := range srvdata.PBDB_CreateroomMgr.Datas.GetArr() {
if data.GameId == this.GameId && data.GameSite == this.GetDBGameFree().GetSceneType() {
betRange := data.GetBetRange()
if len(betRange) == 0 {
continue
}
for j := 0; j < len(betRange); j++ {
if betRange[j] == this.BaseScore && len(data.GetGoldRange()) > 0 && data.GetGoldRange()[0] != 0 {
tmpIds = append(tmpIds, data.GetId())
break
}
}
}
}
if len(tmpIds) > 0 {
goldRange := srvdata.PBDB_CreateroomMgr.GetData(tmpIds[0]).GetGoldRange()
if len(goldRange) != 0 && goldRange[0] != 0 {
limitCoin = int64(goldRange[0])
}
if limitCoin != 0 {
for _, id := range tmpIds {
tmp := srvdata.PBDB_CreateroomMgr.GetData(id).GetGoldRange()
if int64(tmp[0]) < limitCoin && tmp[0] != 0 {
limitCoin = int64(tmp[0])
}
}
}
}
return limitCoin
}
func (this *Scene) CoinOverMaxLimit(coin int64, p *Player) bool {
if this.Testing {
return false
}
if coin < 0 {
return false
}
if p.ExpectLeaveCoin != 0 && this.IsCoinScene() { //暂只对对战场生效
if p.ExpectLeaveCoin < p.takeCoin { //期望输的时候离场
if coin <= p.ExpectLeaveCoin {
return true
}
} else { //期望赢的时候离场
if coin >= p.ExpectLeaveCoin {
return true
}
}
} else {
if this.GetDBGameFree() != nil {
limit := this.GetDBGameFree().GetRobotLimitCoin()
if len(limit) >= 2 {
comp := common.RandInt(int(limit[0]), int(limit[1]))
if coin > int64(comp) {
return true
}
}
}
}
return false
}
func (this *Scene) CorrectBillCoin(coin, limit1, limit2 int64) int64 {
if coin > limit1 {
coin = limit1
}
if coin > limit2 {
coin = limit2
}
return coin
}
func (this *Scene) GetCoinSceneServiceFee() int32 {
if this.GetDBGameFree() != nil {
return this.GetDBGameFree().GetServiceFee()
}
return 0
}
func (this *Scene) GetCoinSceneTypeId() int32 {
if this.GetDBGameFree() != nil {
return this.GetDBGameFree().Id
}
return 0
}
func (this *Scene) GetCoinSceneName() string {
if this.GetDBGameFree() != nil {
return this.GetDBGameFree().GetName() + this.GetDBGameFree().GetTitle()
}
return ""
}
func (this *Scene) GetHundredSceneName() string {
if this.IsHundredScene() && this.GetDBGameFree() != nil {
if this.GetDBGameFree().GetName() == this.GetDBGameFree().GetTitle() {
return this.GetDBGameFree().GetTitle()
} else {
return this.GetDBGameFree().GetName() + this.GetDBGameFree().GetTitle()
}
}
return ""
}
func (this *Scene) GetSceneName() string {
if this.IsCoinScene() {
return this.GetCoinSceneName()
} else if this.IsHundredScene() {
return this.GetHundredSceneName()
}
return ""
}
func (this *Scene) CanChangeCoinScene(p *Player) bool {
//if p.IsMarkFlag(PlayerState_Audience) {
// if this.drp != nil {
// return this.drp.CanChangeCoinScene(this, p)
// }
//}
//if this.mp != nil {
// if !this.mp.IsMatchEnd(this) {
// return false
// }
//}
if this.sp != nil {
return this.sp.CanChangeCoinScene(this, p)
}
return false
}
func (this *Scene) SyncPlayerCoin() {
//if this.Testing {
// return
//}
//pack := &server.GWSyncPlayerCoin{
// SceneId: proto.Int(this.SceneId),
//}
//switch this.GameId {
//case common.GameId_HFishing, common.GameId_TFishing:
// for _, value := range this.Players {
// if value.IsRob {
// continue
// }
// //todo dev 捕鱼的逻辑暂时不用 开发的时候再增加
// //if exData, ok := value.extraData.(*FishingPlayerData); ok {
// // if exData.CoinCache != value.LastSyncCoin {
// // pack.PlayerCoins = append(pack.PlayerCoins, int64(value.SnId))
// // pack.PlayerCoins = append(pack.PlayerCoins, exData.CoinCache)
// // value.LastSyncCoin = exData.CoinCache
// // }
// //}
// }
//default:
// for _, value := range this.Players {
// if value.Coin != value.LastSyncCoin && !value.IsRob {
// pack.PlayerCoins = append(pack.PlayerCoins, int64(value.SnId))
// pack.PlayerCoins = append(pack.PlayerCoins, value.Coin)
// value.LastSyncCoin = value.Coin
// }
// }
//}
//if len(pack.PlayerCoins) > 0 {
// proto.SetDefaults(pack)
// this.SendToWorld(int(server.SSPacketID_PACKET_GW_SYNCPLAYERCOIN), pack)
//}
}
func (this *Scene) SyncSceneState(state int) {
pack := &server.GWSceneState{
RoomId: int32(this.SceneId),
RoomState: int32(state),
}
this.SendToWorld(int(server.SSPacketID_PACKET_GW_SCENESTATE), pack)
}
func (this *Scene) NotifySceneRoundStart(round int) {
pack := &server.GWSceneStart{
RoomId: this.SceneId,
CurrRound: proto.Int(round),
Start: proto.Bool(true),
MaxRound: this.TotalOfGames,
}
proto.SetDefaults(pack)
this.SendToWorld(int(server.SSPacketID_PACKET_GW_SCENESTART), pack)
}
func (this *Scene) NotifySceneRoundPause() {
pack := &server.GWSceneStart{
RoomId: this.SceneId,
Start: proto.Bool(false),
CurrRound: proto.Int(this.NumOfGames),
MaxRound: this.TotalOfGames,
}
proto.SetDefaults(pack)
this.SendToWorld(int(server.SSPacketID_PACKET_GW_SCENESTART), pack)
}
// SyncScenePlayer 游戏开始的时候同步防伙牌数据
func (this *Scene) SyncScenePlayer() {
pack := &server.GWScenePlayerLog{
GameId: this.GameId,
GameFreeId: proto.Int32(this.GetDBGameFree().GetId()),
}
for _, value := range this.Players {
if value.IsRob || !value.IsGameing() {
continue
}
pack.Snids = append(pack.Snids, value.SnId)
}
this.SendToWorld(int(server.SSPacketID_PACKET_GW_SCENEPLAYERLOG), pack)
}
func (this *Scene) RecordReplayStart() {
if !this.IsHundredScene() && !this.IsMatchScene() {
logger.Logger.Trace("RecordReplayStart-----", this.GetReplayCode(), this.NumOfGames, this.replayAddId)
id := fmt.Sprintf("%d%d%v%d", this.GameId, this.SceneId, this.GameNowTime.Format(ReplayIdTf), this.replayAddId)
this.rr = NewReplayRecorder(id)
}
}
func (this *Scene) RecordReplayOver() {
if !this.Testing && !this.IsHundredScene() && !this.IsMatchScene() {
logger.Logger.Trace("RecordReplayOver-----", this.GetReplayCode(), this.NumOfGames, this.replayAddId)
this.replayAddId++
this.rr.Fini(this)
this.RecordReplayStart()
}
}
// TryDismissRob 尝试机器人离场
func (this *Scene) TryDismissRob(params ...int) {
if this.IsMatchScene() {
return
}
if this.IsCoinScene() {
allRobot := true
for _, p := range this.Players {
if !p.IsRob {
allRobot = false
break
}
}
//一次离开一个
hasLeave := false
if allRobot && !this.IsPreCreateScene() {
for _, p := range this.Players {
if p.IsRob {
this.PlayerLeave(p, common.PlayerLeaveReason_Normal, true)
hasLeave = true
}
}
}
//当局已经检查过了
if this.nogDismiss == this.NumOfGames {
return
}
this.nogDismiss = this.NumOfGames
//如果是满桌并且是禁止匹配真人,那么保持满桌几局
if this.GetDBGameFree().GetMatchTrueMan() == common.MatchTrueMan_Forbid && this.IsFull() && rand.Intn(4) == 1 {
hasLeave = true
}
if !hasLeave && !this.Testing {
for _, p := range this.Players {
rands := this.Rand.Int63n(20) + 20
a := float64(p.Coin) / float64(p.takeCoin)
if p != nil && p.IsRob && a >= float64(rands)/10 {
this.PlayerLeave(p, common.PlayerLeaveReason_Normal, true)
hasLeave = true
break
}
}
}
if !hasLeave && this.GetDBGameFree().GetMatchTrueMan() != common.MatchTrueMan_Forbid && len(params) > 0 &&
params[0] == 1 && this.IsFull() && common.RandInt(10000) < 4000 {
for _, r := range this.Players {
if r.IsRob {
this.PlayerLeave(r, common.PlayerLeaveReason_Normal, true)
hasLeave = true
break
}
}
}
if !hasLeave {
for _, r := range this.Players {
if r.IsRob {
if !r.IsGameing() { //5%的概率,不玩游戏直接离场
if rand.Intn(100) < 5 {
this.PlayerLeave(r, common.PlayerLeaveReason_Normal, true)
hasLeave = true
break
}
} else { //玩游戏的,玩几局有概率离场
expectTimes := 5 + rand.Int31n(20)
if r.GameTimes >= expectTimes {
this.PlayerLeave(r, common.PlayerLeaveReason_Normal, true)
hasLeave = true
break
}
}
}
}
}
//如果当局有机器人离开,适当延长下下次邀请的时间
if hasLeave {
tNow := time.Now()
if this.nextInviteTime.Sub(tNow) < time.Second {
this.nextInviteTime = tNow.Add(time.Second * time.Duration(rand.Int31n(3)+1))
}
}
}
}
func (this *Scene) CreateGameRecPacket() *server.GWGameRec {
return &server.GWGameRec{
RoomId: this.SceneId,
NumOfGames: proto.Int(this.NumOfGames),
GameTime: proto.Int(int(time.Now().Sub(this.GameStartTime) / time.Second)),
}
}
func (this *Scene) IsAllReady() bool {
for _, p := range this.Players {
if !p.IsOnLine() || !p.IsReady() {
return false
}
}
return true
}
func (this *Scene) GetOnlineCnt() int {
cnt := 0
for _, p := range this.Players {
if p.IsOnLine() && !p.IsMarkFlag(PlayerState_Leave) {
cnt++
}
}
return cnt
}
func (this *Scene) GetRealPlayerCnt() int {
cnt := 0
for _, p := range this.Players {
if !p.IsRob {
cnt++
}
}
return cnt
}
func (this *Scene) GetGameingPlayerCnt() int {
cnt := 0
for _, p := range this.Players {
if p != nil && p.IsGameing() {
cnt += 1
}
}
return cnt
}
func (this *Scene) GetGameingRealPlayerCnt() int {
cnt := 0
for _, p := range this.Players {
if p != nil && p.IsGameing() && !p.IsRob {
cnt += 1
}
}
return cnt
}
func (this *Scene) GetRandomRobotPlayer() *Player {
robotArray := []*Player{}
for _, p := range this.Players {
if p != nil && p.IsGameing() && p.IsRob {
robotArray = append(robotArray, p)
}
}
if len(robotArray) > 0 {
return robotArray[common.RandInt(0, len(robotArray))]
}
return nil
}
func (this *Scene) CoinPoolCanOut() bool {
return true
/* 暂时屏蔽
noRobotPlayerCount := this.GetRealPlayerCnt()
setting := coinPoolMgr.GetCoinPoolSetting(this.platform, this.gamefreeId, this.groupId)
if setting != nil {
return int32(noRobotPlayerCount) >= setting.GetMinOutPlayerNum()
}
return int32(noRobotPlayerCount) >= this.GetDBGameFree().GetMinOutPlayerNum()
*/
}
func (this *Scene) ClearAutoPlayer() {
for _, p := range this.Players {
if p.IsAuto() {
p.UnmarkFlag(PlayerState_Auto)
p.SyncFlag()
}
}
}
func (this *Scene) SaveFriendRecord(snid int32, isWin int32, billCoin int64, baseScore int32) {
if this.SceneMode == common.SceneModePrivate {
return
}
log := model.NewFriendRecordLogEx(this.Platform, snid, isWin, this.GameId, baseScore, billCoin, int64(this.GetMatch().GetMatchType()))
if log != nil {
mq.Write(log)
}
}
type SaveGameDetailedParam struct {
LogId string // 日志id
Detail string // 游戏详细信息
GameTime int64 // 游戏时长
Trend20Lately string // 最近20局开奖结果
CtrlType int // 调控类型 1控赢 2控输
PlayerPool map[int]int // 个人水池分
}
func (this *Scene) SaveGameDetailedLog(param *SaveGameDetailedParam) {
if this == nil || param == nil {
return
}
if param.GameTime <= 0 {
param.GameTime = int64(time.Now().Sub(this.GameNowTime).Seconds())
}
if param.GameTime < 0 {
param.GameTime = 0
}
now := time.Now()
f := func(plt string) {
log := &model.GameDetailedLog{
Id: bson.NewObjectId(),
LogId: param.LogId,
GameId: this.GameId,
Platform: plt,
MatchId: this.GetMatch().GetMatchSortId(),
SceneId: this.SceneId,
GameMode: this.GameMode,
GameFreeid: this.GetGameFreeId(),
PlayerCount: int32(len(this.Players)),
GameTiming: int32(param.GameTime),
GameBaseBet: this.GetBaseScore(),
GameDetailedNote: param.Detail,
GameDetailVer: GameDetailedVer[int(this.GameId)],
CpCtx: this.CpCtx,
Time: now,
Trend20Lately: param.Trend20Lately,
Ts: now.Unix(),
CtrlType: param.CtrlType,
PlayerPool: make(map[int]int),
CycleId: this.CycleID,
}
for k, v := range param.PlayerPool {
log.PlayerPool[k] = v
}
mq.Write(log)
}
switch {
case this.IsCoinScene():
mapPlatform := make(map[string]bool)
for _, v := range this.Players {
if v == nil {
continue
}
if _, ok := mapPlatform[v.Platform]; ok {
continue
}
mapPlatform[v.Platform] = true
f(v.Platform)
}
default:
f(this.Platform)
}
}
type SaveGamePlayerListLogParam struct {
LogId string // 详情日志id
Platform string // 平台
Snid int32 // 玩家id
PlayerName string // 玩家名字
Channel string // 渠道
ChannelId string // 推广渠道
TotalIn int64 // 总投入
TotalOut int64 // 总产出(税前)
TaxCoin int64 // 总税收
BetAmount int64 // 下注量
WinAmountNoAnyTax int64 // 税后赢取额(净利润,正负值)
IsFirstGame bool // 是否第一次游戏
IsFree bool // 拉霸专用 是否免费
WinSmallGame int64 // 拉霸专用 小游戏奖励
WinTotal int64 // 拉霸专用 本局输赢
GameTime int64 // 游戏时长
}
// SaveGamePlayerListLog 保存玩家对局记录
func (this *Scene) SaveGamePlayerListLog(param *SaveGamePlayerListLogParam) {
if this == nil {
return
}
if param == nil {
return
}
p := this.GetPlayer(param.Snid)
if p == nil {
return
}
if param.PlayerName == "" {
param.PlayerName = p.Name
}
baseScore := this.GetBaseScore()
// 上报玩家游戏记录
if !p.IsRob && (param.IsFree || param.TotalIn != 0 || param.TotalOut != 0) {
p.ReportGameEvent(&ReportGameEventParam{
Tax: param.TaxCoin,
Change: param.WinAmountNoAnyTax,
In: param.TotalIn,
Out: param.TotalOut,
GameTime: param.GameTime,
})
}
// 保存玩家游戏日志
now := time.Now()
log := &model.GamePlayerListLog{
LogId: bson.NewObjectId(),
SnId: p.SnId,
Name: param.PlayerName,
GameId: this.GameId,
BaseScore: baseScore,
TaxCoin: param.TaxCoin,
Platform: param.Platform,
Channel: param.Channel,
SceneId: this.SceneId,
GameMode: this.GameMode,
GameFreeid: this.GetGameFreeId(),
GameDetailedLogId: param.LogId,
IsFirstGame: param.IsFirstGame,
BetAmount: param.BetAmount,
WinAmountNoAnyTax: param.WinAmountNoAnyTax,
TotalIn: param.TotalIn,
TotalOut: param.TotalOut,
Time: now,
RoomType: this.SceneMode,
GameDif: this.GetDBGameFree().GetGameDif(),
GameClass: this.GetDBGameFree().GetGameClass(),
MatchId: this.GetMatch().GetMatchSortId(),
MatchType: int64(this.GetMatch().GetMatchType()),
Ts: now.Unix(),
IsFree: param.IsFree,
WinSmallGame: param.WinSmallGame,
WinTotal: param.WinTotal,
CycleId: this.CycleID,
}
mq.Write(log)
}
func (this *Scene) IsPlayerFirst(p *Player) bool {
if p == nil {
return false
}
if p.GDatas != nil {
if data, ok := p.GDatas[this.KeyGameId]; ok {
if data.Statics.GameTimes <= 1 {
return true
}
return false
}
return true
}
return false
}
func (this *Scene) RobotIsLimit() bool {
if this.robotLimit != 0 {
if this.IsCoinScene() {
if this.robotLimit <= this.robotNum {
return true
}
// 房间需要给真人留一个空位
//if this.GetDBGameFree().GetMatchTrueMan() == common.MatchTrueMan_Priority && this.playerNum-this.realPlayerNum-1 <= this.robotNum {
// 没有真人的房间需要给真人留一个空位
if this.GetDBGameFree().GetMatchTrueMan() == common.MatchTrueMan_Priority && this.GetPlayerNum()-1 <= this.robotNum {
return true
}
} else if this.IsHundredScene() {
if this.robotNum >= this.robotLimit {
return true
}
}
}
return false
}
func (this *Scene) RandRobotCnt() {
if this.GetDBGameFree() != nil {
if this.GetDBGameFree().GetMatchMode() == 1 {
return
}
numrng := this.GetDBGameFree().GetRobotNumRng()
if len(numrng) >= 2 {
if numrng[1] == numrng[0] {
this.robotLimit = int(numrng[0])
} else {
if numrng[1] < numrng[0] {
numrng[1], numrng[0] = numrng[0], numrng[1]
}
this.robotLimit = int(numrng[0] + this.Rand.Int31n(numrng[1]-numrng[0]+1))
}
}
//logger.Logger.Tracef("===(this *Scene) RandRobotCnt() sceneid:%v gameid:%v mode:%v robotLimit:%v robotNum:%v", this.SceneId, this.GameId, this.GameMode, this.robotLimit, this.robotNum)
}
}
func (this *Scene) GetRobotTime() int64 {
l := int64(common.RandInt(model.NormalParamData.RobotRandomTimeMin, model.NormalParamData.RobotRandomTimeMax))
return l + time.Now().Unix()
}
func (this *Scene) IsPreCreateScene() bool {
return this.GetDBGameFree().GetCreateRoomNum() > 0
}
func (this *Scene) TryInviteRobot() {
if this.aiMgr != nil {
return
}
// 游戏配置错误
if this.GetDBGameFree() == nil {
return
}
// 私有房间不邀请机器人,比赛场部邀请机器人
if this.IsPrivateScene() || this.IsMatchScene() {
return
}
// 队列匹配不邀请机器人
if this.GetDBGameFree().GetMatchMode() == 1 {
return
}
// 不使用机器人
if this.GetDBGameFree().GetBot() == 0 { //机器人不进的场
return
}
// 分组模式下机器人是否使用(默认不使用)
if !model.GameParamData.GameConfigGroupUseRobot && this.GroupId != 0 {
return
}
// 对战场有真实玩家的情况才需要机器人匹配
if !this.IsRobFightGame() && this.realPlayerNum <= 0 && !this.IsHundredScene() && !this.IsPreCreateScene() { //预创建房间的对战场可以优先进机器人,如:21点 判断依据:CreateRoomNum
return
}
switch this.GetDBGameFree().GetGameType() {
case common.GameType_Fishing:
if this.robotNum >= this.robotLimit {
return
}
}
tNow := time.Now()
if tNow.Before(this.nextInviteTime) {
return
}
if model.GameParamData.EnterAfterStartSwitch && this.IsCoinScene() && this.Gaming && !this.bEnterAfterStart {
return
}
if this.robotNumLastInvite == this.robotNum {
this.inviteInterval = this.inviteInterval + 1
if this.inviteInterval > model.GameParamData.RobotInviteIntervalMax {
this.inviteInterval = model.GameParamData.RobotInviteIntervalMax
}
} else {
this.inviteInterval = model.GameParamData.RobotInviteInitInterval
}
this.ResetNextInviteTime()
this.robotNumLastInvite = this.robotNum
if !this.RobotIsLimit() {
var robCnt int
if this.robotLimit != 0 {
if this.IsCoinScene() {
if this.robotNum >= this.robotLimit { //机器人数量已达上限
return
}
hadCnt := len(this.Players)
robCnt = this.robotLimit - this.robotNum
if robCnt > this.GetPlayerNum()-hadCnt {
robCnt = this.GetPlayerNum() - hadCnt
}
} else if this.IsHundredScene() {
robCnt = this.robotLimit - this.robotNum
}
} else {
if this.IsCoinScene() {
if this.IsFull() {
return
}
hadCnt := len(this.Players)
robCnt = this.GetPlayerNum() - hadCnt
if this.realPlayerNum == 0 { //一个真人都没有,不让机器人坐满房间
robCnt--
}
}
}
if robCnt > 0 {
var num int32
if this.GetDBGameFree().GameId == common.GameId_ChesstitiansCambodianRobot {
num = int32(robCnt)
} else {
num = this.Rand.Int31n(int32(robCnt + 1))
}
if num > 0 {
if this.IsCoinScene() /* && this.gaming*/ { //如果牌局正在进行中,一个一个进
num = 1
}
//logger.Logger.Tracef("(this *Scene)(groupid:%v sceneid:%v) TryInviteRobot(%v) current robot(%v+%v) robotlimit(%v)", this.groupId, this.sceneId, this.GetDBGameFree().GetName()+this.GetDBGameFree().GetTitle(), this.robotNum, num, this.robotLimit)
//同步下房间里的参数'
NpcServerAgentSingleton.SyncDBGameFree(int(this.SceneId), this.GetDBGameFree())
//然后再邀请
NpcServerAgentSingleton.Invite(int(this.SceneId), int(num), this.GetDBGameFree().Id)
}
}
}
}
func (this *Scene) ResetNextInviteTime() {
this.nextInviteTime = time.Now().Add(time.Second * (time.Duration(this.Rand.Int63n(2+this.inviteInterval)) + 1))
}
// 是否有真人参与游戏
func (this *Scene) IsRealInGame() bool {
for _, player := range this.Players {
if player != nil && player.IsGameing() && !player.IsRob {
return true
}
}
return false
}
// 是否都是真人
func (this *Scene) IsAllRealInGame() bool {
for _, player := range this.Players {
if player != nil && player.IsGameing() && player.IsRob {
return false
}
}
return true
}
// 是否开启机器人对战游戏
func (this *Scene) IsRobFightGame() bool {
if this.GetDBGameFree() == nil {
return false
}
if this.GetDBGameFree().GetAi()[0] == 1 && model.GameParamData.IsRobFightTest == true {
return true
}
return false
}
// 百人场机器人离场规则
func (this *Scene) RobotLeaveHundred() {
for _, p := range this.Players {
if p != nil {
leave := false
var reason int
//if p.trusteeship >= 5 {
// leave = true
// reason = common.PlayerLeaveReason_LongTimeNoOp
//}
if !leave && !p.IsOnLine() && time.Now().Sub(p.DropTime) > 30*time.Second {
leave = true
reason = common.PlayerLeaveReason_DropLine
}
if !leave && p.IsRob {
if !this.CoinInLimit(p.Coin) {
//钱少
leave = true
reason = common.PlayerLeaveReason_Bekickout
} else if this.CoinOverMaxLimit(p.Coin, p) {
//钱多
leave = true
reason = common.PlayerLeaveReason_Normal
} else if p.Coin < int64(this.GetDBGameFree().GetBetLimit()) {
//少于下注限额
leave = true
reason = common.PlayerLeaveReason_Normal
}
}
if leave {
this.PlayerLeave(p, reason, leave)
}
}
}
}
func (this *Scene) RandInt(args ...int) int {
switch len(args) {
case 0:
return this.Rand.Int()
case 1:
if args[0] != 0 {
return this.Rand.Intn(args[0])
} else {
return 0
}
default:
l := args[0]
u := args[1]
switch {
case l == u:
{
return l
}
case l > u:
{
return u + this.Rand.Intn(l-u)
}
default:
{
return l + this.Rand.Intn(u-l)
}
}
}
}
func (this *Scene) CheckNeedDestroy() bool {
//if common.IsLocalGame(this.GameId) {
return ServerStateMgr.GetState() == common.GameSessStateOff || this.graceDestroy
//} else {
// return (ServerStateMgr.GetState() == common.GAME_SESS_STATE_OFF || this.graceDestroy) || (this.IsPrivateScene() && this.NumOfGames >= this.TotalOfGames)
//}
}
func (this *Scene) GetRecordId() string {
if this.rr != nil {
return this.rr.id
}
return fmt.Sprintf("%d%d%v%d", this.GameId, this.SceneId, this.GameNowTime.Format(ReplayIdTf), this.NumOfGames)
}
func (this *Scene) RandTakeCoin(p *Player) (takeCoin, leaveCoin, gameTimes int64) {
if p.IsRob && p.IsLocal {
dbGameFree := this.GetDBGameFree()
takerng := dbGameFree.GetRobotTakeCoin()
if len(takerng) >= 2 && takerng[1] > takerng[0] {
if takerng[0] < dbGameFree.GetLimitCoin() {
takerng[0] = dbGameFree.GetLimitCoin()
}
takeCoin = int64(common.RandInt(int(takerng[0]), int(takerng[1])))
} else {
maxlimit := int64(dbGameFree.GetMaxCoinLimit())
if maxlimit != 0 && p.Coin > maxlimit {
logger.Logger.Trace("Player coin:", p.Coin)
//在下限和上限之间随机并对其的100的整数倍
takeCoin = int64(common.RandInt(int(dbGameFree.GetLimitCoin()), int(maxlimit)))
logger.Logger.Trace("Take coin:", takeCoin)
}
if maxlimit == 0 && this.IsCoinScene() {
maxlimit = int64(common.RandInt(10, 50)) * int64(dbGameFree.GetLimitCoin())
takeCoin = int64(common.RandInt(int(dbGameFree.GetLimitCoin()), int(maxlimit)))
logger.Logger.Trace("Take coin:", takeCoin)
}
}
takeCoin = takeCoin / 100 * 100
//离场金币
leaverng := dbGameFree.GetRobotLimitCoin()
if len(leaverng) >= 2 {
leaveCoin = int64(leaverng[0] + rand.Int63n(leaverng[1]-leaverng[0]))
}
}
return
}
// TryBillExGameDrop 掉落道具
func (this *Scene) TryBillExGameDrop(p *Player) {
if p.IsRob {
return
}
this.DropCollectBox(p)
baseScore := this.GetDBGameFree().BaseScore
if common.IsLocalGame(int(this.GameId)) {
baseScore = this.BaseScore
}
if baseScore == 0 {
return
}
// 场次掉落开关
if this.GetDBGameFree().IsDrop != 1 {
return
}
// 渠道开关
if !ConfigMgrInst.IsOn(p.Platform, common.ChannelSwitchDropItem, p.LastChannel) {
return
}
dropInfo := srvdata.GameDropMgrSingleton.GetDropInfoByBaseScore(baseScore)
if dropInfo != nil && len(dropInfo) != 0 {
realDrop := make(map[int32]int32)
for _, drop := range dropInfo {
//概率
randTmp := rand.Int31n(10000)
if randTmp < drop.Rate {
//个数
num := drop.MinAmount
if drop.MaxAmount > drop.MinAmount {
num = rand.Int31n(drop.MaxAmount-drop.MinAmount+1) + drop.MinAmount
}
oldNum := num
a := math.Max(float64(p.MoneyTotal), 50) * 10.0 / math.Max(float64(p.VCardCost), 500.0)
num = int32(float64(num) * math.Min(a, 1.5))
if num == 0 {
// 50%概率给oldNum
if rand.Int31n(100) < 50 {
num = oldNum
}
}
realDrop[drop.ItemId] = num
}
}
if realDrop != nil && len(realDrop) != 0 {
//通知客户端游戏内额外掉落
pack := &player.SCGameExDropItems{}
pack.Items = make(map[int32]int32)
for id, num := range realDrop {
pack.Items[id] = proto.Int32(num)
itemData := srvdata.GameItemMgr.Get(p.Platform, id)
if itemData != nil {
p.AddItems(&model.AddItemParam{
Platform: p.Platform,
SnId: p.SnId,
Change: []*model.Item{
{
ItemId: id,
ItemNum: int64(num),
},
},
GainWay: common.GainWay_Game,
Operator: "system",
Remark: fmt.Sprintf("游戏掉落%v", id),
GameId: int64(this.GameId),
GameFreeId: int64(this.GetGameFreeId()),
})
}
}
if len(pack.Items) > 0 {
p.SendToClient(int(player.PlayerPacketID_PACKET_SCGAMEEXDROPITEMS), pack)
logger.Logger.Trace("SCGAMEEXDROPITEMS ", pack)
}
}
}
}
// DropCollectBox 掉落集卡礼盒
func (this *Scene) DropCollectBox(p *Player) {
if p == nil || p.IsRob || ConfigMgrInst.GetConfig(p.Platform).WelfareCollectConfig.Switch != model.WelfareOpen {
return
}
data := srvdata.PBDB_CollectBoxGainMgr.GetData(this.GetGameFreeId())
if data == nil {
return
}
n := this.RandInt(100)
if n < int(data.GetRate()) {
pack := &player.SCGameExDropItems{}
pack.Items = make(map[int32]int32)
itemData := srvdata.GameItemMgr.Get(p.Platform, common.ItemIDCollectBox)
if itemData != nil {
pack.Items = map[int32]int32{itemData.Id: 1}
p.AddItems(&model.AddItemParam{
Platform: p.Platform,
SnId: p.SnId,
Change: []*model.Item{
{
ItemId: itemData.Id,
ItemNum: 1,
},
},
GainWay: common.GainWay_Game,
Operator: "system",
Remark: fmt.Sprintf("游戏掉落%v", itemData.Id),
GameId: int64(this.GameId),
GameFreeId: int64(this.GetGameFreeId()),
})
}
if len(pack.Items) > 0 {
p.SendToClient(int(player.PlayerPacketID_PACKET_SCGAMEEXDROPITEMS), pack)
logger.Logger.Trace("SCGAMEEXDROPITEMS", pack)
}
}
}
// 生成名字
func (this *Scene) RandNickName() string {
//if rand.Int31n(100) < 60 {
pool := srvdata.PBDB_NameMgr.Datas.GetArr()
cnt := int32(len(pool))
if cnt > 0 {
return pool[rand.Int31n(cnt)].GetName()
}
//}
return "Guest"
}
func (this *Scene) GetRobotNum() int {
return this.robotNum
}
func (this *Scene) GetRealPlayerNum() int {
return this.realPlayerNum
}
func (this *Scene) GetBaseScore() int32 {
if this.BaseScore > 0 {
return this.BaseScore
}
return this.GetDBGameFree().GetBaseScore()
}
func (this *Scene) PlayerPoolOdds(p *Player) int32 {
config := ConfigMgrInst.GetConfig(p.Platform).PlayerPool
if config == nil {
return 0
}
if !config.GetPlayerPoolSwitch() || p == nil {
return 0
}
pCoin := p.TotalOut - p.PlayerTax - p.TotalIn
var gameCoin int64
var upLine, lowLine int64
lowLine = p.GetPoolLower(config)
upLine = p.GetPoolUpper(config)
odds := int32(p.GetPoolOdds(config))
p.TestLog = append(p.TestLog, fmt.Sprintf("个人水池调控 gameID:%v 兑换金币:%v 玩家初始值:%v, 游戏类型:%v, gameCoin:%v, 上线:%v, 下线:%v 概率:%v",
this.GameId, p.DiamondToCoin, pCoin, this.GetDBGameFree().GetGameType(), gameCoin, upLine, lowLine, odds))
return odds
}
// GetPlayerOdds 获取玩家发牌调控概率
func (this *Scene) GetPlayerOdds(p *Player, gameId int, hasRobot bool) int32 {
if !this.IsControl(hasRobot) {
return 0
}
if p == nil {
return 0
}
// 黑白名单概率
odds, ok := p.BlackWhiteOdds(gameId)
if ok {
return odds
}
// 新手补偿概率
odds, ok = p.NoviceOdds(gameId)
if ok {
return odds
}
var f, g, t, ret int32
// 个人水池概率
g = this.PlayerPoolOdds(p)
setting := CoinPoolMgr.GetCoinPoolSetting(this.Platform, this.GetGameFreeId(), this.GroupId)
if setting != nil && setting.GetSwitch() == 0 {
// 场次水池概率
f = CoinPoolMgr.GetCoinPoolOdds(this.Platform, this.GetGameFreeId(), this.GroupId)
cfg := ConfigMgrInst.GetConfig(p.Platform).PlayerPool
if cfg != nil && cfg.PlayerPoolSwitch {
if g > 0 {
t = f + (1000-f)*g/1000
ret = t
} else if g < 0 {
t = f + (1000+f)*g/1000
ret = t
} else {
ret = f
}
} else {
ret = f
}
//logger.Logger.Tracef("TienLenSceneData snid(%v) 水池配置 水位:%v 配置:%+v",
// p.SnId, CoinPoolMgr.GetCoin(this.GetGameFreeId(), this.Platform, this.GroupId), *setting)
p.TestLog = append(p.TestLog, fmt.Sprintf("水位:%v 水池配置:%+v",
CoinPoolMgr.GetCoin(this.GetGameFreeId(), this.Platform, this.GroupId), *setting))
} else {
ret = g
}
//logger.Logger.Tracef("TienLenSceneData snid(%v) 个人及场次水池调控 hasRobot:%v 个人水池:%v 场次水池:%v 概率:%v", p.SnId, hasRobot, g, f, ret)
p.TestLog = append(p.TestLog, fmt.Sprintf("个人及场次水池调控 有机器人:%v 个人水池:%v 场次水池:%v 概率:%v", hasRobot, g, f, ret))
return ret
}
type PlayerDataParam struct {
HasRobotGaming bool
Data *server.GWPlayerData
}
// SyncPlayerDatas 同步玩家游戏数据到worldsrv
// hasRobotGaming 本局是否有机器人参与游戏
// 返回 溢出金额
func (this *Scene) SyncPlayerDatas(param *PlayerDataParam) int64 {
if param == nil || param.Data == nil {
return 0
}
var n int64
// 比赛场,私人房,公共房无机器人不统计黑白名单输赢金额
if this.IsControl(param.HasRobotGaming) {
for _, v := range param.Data.Datas {
if v.WBGain == 0 {
v.WBGain = v.Gain
}
if v.WBGain != 0 {
if p := this.GetPlayer(v.SnId); p != nil {
n = p.WBUpdate(v.WBGain)
}
}
}
}
this.SendToWorld(int(server.SSPacketID_PACKET_GW_PLAYERDATA), param.Data)
logger.Logger.Trace("Send PlayerData ===>", param.Data)
return n
}
type StaticParam struct {
SnId int32 // 玩家id
Gain int64 // 输赢金币(税后)
GainTax int64 // 赢取金币时的税收
IsAddTimes bool // 是否统计游戏次数
HasRobotGaming bool // 是否有机器人玩本局游戏
WinState int32 // 输赢状态 1 赢 2 输 3 和
}
// IsControl 是否调控
func (this *Scene) IsControl(hasRobotGaming bool) bool {
return !this.IsMatchScene() && !this.IsPrivateScene() && !(this.IsFreePublic() && !hasRobotGaming)
}
// Statistics 玩家游戏数据统计
// 包含水池统计,黑白名单统计,新手调控统计,个人水池统计
func (this *Scene) Statistics(param *StaticParam) {
if param == nil {
return
}
p := this.GetPlayer(param.SnId)
if p == nil || p.IsRob {
return
}
_, isNovice := p.NoviceOdds(int(this.GameId))
isControl := this.IsControl(param.HasRobotGaming) // 需要调控的房间
var wbLevel = p.WBLevel // 原来的黑白名单等级; 注意SyncPlayerDatas会修改WBLevel
var addGain int64 // 玩家溢出金额
// 黑白名单
// 解除黑白名单,记录黑白名单投入产出
addGain += this.SyncPlayerDatas(&PlayerDataParam{
HasRobotGaming: param.HasRobotGaming,
Data: &server.GWPlayerData{
Datas: []*server.PlayerData{
{
SnId: param.SnId,
Gain: param.Gain,
Tax: param.GainTax,
Coin: p.Coin,
GameCoinTs: p.GameCoinTs,
WinState: param.WinState,
},
},
GameFreeId: this.GetGameFreeId(),
SceneId: int32(this.SceneId),
},
})
logger.Logger.Tracef("Statistics gameId:%v wbLevel:%v gain:%v addGain:%v", this.GameId, wbLevel, param.Gain, addGain)
// 比赛场,私人房不统计
if this.IsMatchScene() || this.IsPrivateScene() {
return
}
var totalIn int64
var totalOut int64
now := time.Now()
if param.Gain > 0 {
totalOut = param.Gain + param.GainTax
} else {
totalIn = -param.Gain
}
var statics []*model.PlayerGameStatics
keyGameId := strconv.Itoa(this.GetGameId())
keyGameFreeId := strconv.Itoa(int(this.GetGameFreeId()))
// 当天数据统计
// 按场次分
if data, ok := p.TodayGameData.CtrlData[keyGameFreeId]; ok {
statics = append(statics, data)
} else {
gs := model.NewPlayerGameStatics()
p.TodayGameData.CtrlData[keyGameFreeId] = gs
statics = append(statics, gs)
}
// 按游戏分
if data, ok := p.TodayGameData.CtrlData[keyGameId]; ok {
statics = append(statics, data)
} else {
data = model.NewPlayerGameStatics()
p.TodayGameData.CtrlData[keyGameId] = data
statics = append(statics, data)
}
// 按场次分
if data, ok := p.GDatas[keyGameFreeId]; ok {
if data.FirstTime.IsZero() {
data.FirstTime = now
}
statics = append(statics, &data.Statics)
} else {
data = &model.PlayerGameInfo{FirstTime: now}
p.GDatas[keyGameFreeId] = data
statics = append(statics, &data.Statics)
}
// 按游戏分
if data, ok := p.GDatas[keyGameId]; ok {
if data.FirstTime.IsZero() {
data.FirstTime = now
}
statics = append(statics, &data.Statics)
} else {
data = &model.PlayerGameInfo{FirstTime: now}
p.GDatas[keyGameId] = data
statics = append(statics, &data.Statics)
}
// 新手输赢统计
if !model.GameParamData.CloseNovice && !common.InSliceInt(model.GameParamData.CloseNoviceGame, int(this.GameId)) && isControl && wbLevel == 0 && isNovice {
keyNoviceGameId := common.GetKeyNoviceGameId(int(this.GameId))
var gs *model.PlayerGameStatics
if data, ok := p.GDatas[keyNoviceGameId]; ok {
statics = append(statics, &data.Statics)
gs = &data.Statics
} else {
data = &model.PlayerGameInfo{FirstTime: time.Now(), Statics: *model.NewPlayerGameStatics()}
p.GDatas[keyNoviceGameId] = data
statics = append(statics, &data.Statics)
gs = &data.Statics
}
// 溢出
data := srvdata.PBDB_NewPlayerMgr.GetData(int32(this.GameId))
if data != nil {
switch data.GetCondition1() {
case 2: // gameId输赢金额
if gs != nil {
out := gs.TotalOut + totalOut
in := gs.TotalIn + totalIn
tax := gs.Tax + param.GainTax
cur := out - tax - in
if cur > data.GetConditionValue1() {
addGain += cur - data.GetConditionValue1()
}
}
}
switch data.GetCondition2() {
case 2: // gameId输赢金额
if gs != nil {
out := gs.TotalOut + totalOut
in := gs.TotalIn + totalIn
tax := gs.Tax + param.GainTax
cur := out - tax - in
if cur > data.GetConditionValue2() {
addGain += cur - data.GetConditionValue2()
}
}
}
}
}
logger.Logger.Tracef("Statistics Novice gameId:%v wbLevel:%v gain:%v addGain:%v", this.GameId, wbLevel, param.Gain, addGain)
// 个人输赢统计条件(个人水池)
// 黑白名单和新手调控,溢出金币统计到个人水池
cfg := ConfigMgrInst.GetConfig(p.Platform).PlayerPool
isPlayerPool := cfg != nil && cfg.PlayerPoolSwitch && isControl && ((wbLevel == 0 && !isNovice) || addGain > 0)
if isPlayerPool {
keyGameType := common.GetKeyGameType(int(this.GetDBGameFree().GetGameType()))
gs, ok := p.GDatas[keyGameType]
if !ok {
gs = &model.PlayerGameInfo{FirstTime: time.Now()}
p.GDatas[keyGameType] = gs
}
if addGain == 0 {
// 正常统计
// 游戏类型输赢统计(个人水池调控使用)
statics = append(statics, &gs.Statics)
} else {
// 溢出统计;只有多赢的值,多输的不计算
if wbLevel >= 0 {
gs.Statics.TotalOut += addGain
}
}
logger.Logger.Tracef("Statistics PlayerPool gameId:%v wbLevel:%v gain:%v addGain:%v", this.GameId, wbLevel, param.Gain, addGain)
}
for _, data := range statics {
if data != nil {
data.TotalIn += totalIn
data.TotalOut += totalOut
data.Tax += param.GainTax
if param.IsAddTimes {
data.GameTimes++
if param.Gain > 0 {
data.WinGameTimes++
data.WinGameTimesNum++
data.LoseGameTimesNum = 0
} else if param.Gain < 0 {
data.LoseGameTimes++
data.LoseGameTimesNum++
data.WinGameTimesNum = 0
} else {
data.DrawGameTimes++
data.WinGameTimesNum = 0
data.LoseGameTimesNum = 0
}
}
}
}
// 玩家身上元数据
if param.IsAddTimes {
p.GameTimes++
}
if param.Gain > 0 {
if param.IsAddTimes {
p.WinTimes++
}
p.WinCoin += totalOut
p.TaxCoin += param.GainTax
if isPlayerPool && srvdata.GameFreeMgr.IsPlayerPool(int(this.GameId)) {
p.TotalOut += totalOut
p.PlayerTax += param.GainTax
}
} else if param.Gain < 0 {
if param.IsAddTimes {
p.FailTimes++
}
p.FailCoin += totalIn
if isPlayerPool && srvdata.GameFreeMgr.IsPlayerPool(int(this.GameId)) {
p.TotalIn += totalIn
}
} else {
if param.IsAddTimes {
p.DrawTimes++
}
}
// 水池统计
if isControl && ((wbLevel == 0 && !isNovice) || addGain > 0) {
if addGain == 0 {
CoinPoolMgr.PushCoin(this.GetGameFreeId(), this.GroupId, this.Platform, -param.Gain)
} else {
// 溢出统计;只有多赢的值,多输的不计算
if wbLevel >= 0 {
CoinPoolMgr.PushCoin(this.GetGameFreeId(), this.GroupId, this.Platform, -addGain)
}
}
logger.Logger.Tracef("Statisticsis CoinPool gameId:%v wbLevel:%v gain:%v addGain:%v", this.GameId, wbLevel, param.Gain, addGain)
}
}
type StaticLabaParam struct {
SnId int32 // 玩家id
Gain int64 // 输赢金币(税后)
GainTax int64 // 赢取金币时的税收
IsAddTimes bool // 是否统计游戏次数
}
// StaticsLaba 拉霸游戏数据统计,一次下注记录一次
// 不含水池统计,黑白名单统计,在游戏中另外处理
func (this *Scene) StaticsLaba(param *StaticLabaParam) {
if param == nil {
return
}
p := this.GetPlayer(param.SnId)
if p == nil || p.IsRob {
return
}
// 比赛场,私人房不统计
if this.IsMatchScene() || this.IsPrivateScene() {
return
}
var totalIn int64
var totalOut int64
now := time.Now()
if param.Gain > 0 {
totalOut = param.Gain + param.GainTax
} else {
totalIn = -param.Gain
}
var statics []*model.PlayerGameStatics
keyGameId := strconv.Itoa(this.GetGameId())
keyGameFreeId := strconv.Itoa(int(this.GetGameFreeId()))
// 当天数据统计
// 按场次分
if data, ok := p.TodayGameData.CtrlData[keyGameFreeId]; ok {
statics = append(statics, data)
} else {
gs := model.NewPlayerGameStatics()
p.TodayGameData.CtrlData[keyGameFreeId] = gs
statics = append(statics, gs)
}
// 按游戏分
if data, ok := p.TodayGameData.CtrlData[keyGameId]; ok {
statics = append(statics, data)
} else {
data = model.NewPlayerGameStatics()
p.TodayGameData.CtrlData[keyGameId] = data
statics = append(statics, data)
}
// 按场次分
if data, ok := p.GDatas[keyGameFreeId]; ok {
if data.FirstTime.IsZero() {
data.FirstTime = now
}
statics = append(statics, &data.Statics)
} else {
data = &model.PlayerGameInfo{FirstTime: now}
p.GDatas[keyGameFreeId] = data
statics = append(statics, &data.Statics)
}
// 按游戏分
if data, ok := p.GDatas[keyGameId]; ok {
if data.FirstTime.IsZero() {
data.FirstTime = now
}
statics = append(statics, &data.Statics)
} else {
data = &model.PlayerGameInfo{FirstTime: now}
p.GDatas[keyGameId] = data
statics = append(statics, &data.Statics)
}
for _, data := range statics {
if data != nil {
data.TotalIn += totalIn
data.TotalOut += totalOut
data.Tax += param.GainTax
if param.IsAddTimes {
data.GameTimes++
if param.Gain > 0 {
data.WinGameTimes++
data.WinGameTimesNum++
data.LoseGameTimesNum = 0
} else if param.Gain < 0 {
data.LoseGameTimes++
data.LoseGameTimesNum++
data.WinGameTimesNum = 0
} else {
data.DrawGameTimes++
data.WinGameTimesNum = 0
data.LoseGameTimesNum = 0
}
}
}
}
// 玩家身上元数据
if param.IsAddTimes {
p.GameTimes++
}
if param.Gain > 0 {
if param.IsAddTimes {
p.WinTimes++
}
p.WinCoin += totalOut
p.TaxCoin += param.GainTax
} else if param.Gain < 0 {
if param.IsAddTimes {
p.FailTimes++
}
p.FailCoin += totalIn
} else {
if param.IsAddTimes {
p.DrawTimes++
}
}
}
func (this *Scene) TryRelease() {
if !this.IsMatchScene() && this.realPlayerNum == 0 {
this.Destroy(true)
}
}
func (this *Scene) GetMachineServerInfo(MachineId int32, platform string) *webapi.MachineInfo {
config := ConfigMgrInst.GetConfig(platform).MachineConfig
logger.Logger.Tracef("========GetMachineServerInfo=========== platform=%s, MachineId=%d ,config = %v", platform, MachineId, config)
if config == nil {
return nil
}
for _, info := range config.Info {
if info.MachineId == MachineId {
return info
}
}
return nil
}