From fecb462d497d96661766e7b7541a165526b46de4 Mon Sep 17 00:00:00 2001 From: sk <123456@qq.com> Date: Thu, 28 Nov 2024 15:48:39 +0800 Subject: [PATCH 01/41] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=85=94=E5=AD=90?= =?UTF-8?q?=E6=8B=89=E9=9C=B8=E6=B8=B8=E6=88=8F=E8=AE=B0=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gamesrv/fortunedragon/scenepolicy_fortunedragon.go | 12 +++++++++--- gamesrv/fortunerabbit/scenepolicy_fortunerabbit.go | 10 ++++++++-- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/gamesrv/fortunedragon/scenepolicy_fortunedragon.go b/gamesrv/fortunedragon/scenepolicy_fortunedragon.go index 747886c..ed98382 100644 --- a/gamesrv/fortunedragon/scenepolicy_fortunedragon.go +++ b/gamesrv/fortunedragon/scenepolicy_fortunedragon.go @@ -505,12 +505,18 @@ func (this *ScenePolicyFortuneDragon) GetSceneState(s *base.Scene, stateid int) func FortuneDragonAndSaveLog(sceneEx *FortuneDragonSceneData, playerEx *FortuneDragonPlayerData, data assemble.GameEnd) { if !playerEx.IsRob { data.SnId = playerEx.SnId + if playerEx.isFree { + data.TotalBet = 0 + } info, err := model.MarshalGameNoteByROLL(data) if err == nil { logid, _ := model.AutoIncGameLogId() playerEx.currentLogId = logid sceneEx.SaveGameDetailedLog(logid, info, &base.GameDetailedParam{}) - totalin := playerEx.totalBet + var totalin int64 + if !playerEx.isFree { + totalin = playerEx.totalBet + } totalout := int64(data.RoundReward) + playerEx.taxCoin validFlow := totalin + totalout validBet := common.AbsI64(totalin - totalout) @@ -524,8 +530,8 @@ func FortuneDragonAndSaveLog(sceneEx *FortuneDragonSceneData, playerEx *FortuneD TotalIn: totalin, TotalOut: totalout, TaxCoin: playerEx.taxCoin, - BetAmount: playerEx.totalBet, - WinAmountNoAnyTax: int64(data.RoundReward) + playerEx.taxCoin, + BetAmount: totalin, + WinAmountNoAnyTax: int64(data.RoundReward), ValidBet: validBet, ValidFlow: validFlow, IsFirstGame: sceneEx.IsPlayerFirst(playerEx.Player), diff --git a/gamesrv/fortunerabbit/scenepolicy_fortunerabbit.go b/gamesrv/fortunerabbit/scenepolicy_fortunerabbit.go index 60ed868..954921e 100644 --- a/gamesrv/fortunerabbit/scenepolicy_fortunerabbit.go +++ b/gamesrv/fortunerabbit/scenepolicy_fortunerabbit.go @@ -504,12 +504,18 @@ func (this *ScenePolicyFortuneRabbit) GetSceneState(s *base.Scene, stateid int) func FortuneRabbitAndSaveLog(sceneEx *FortuneRabbitSceneData, playerEx *FortuneRabbitPlayerData, data assemble.GameEnd) { if !playerEx.IsRob { data.SnId = playerEx.SnId + if playerEx.isFree { + data.TotalBet = 0 + } info, err := model.MarshalGameNoteByROLL(data) if err == nil { logid, _ := model.AutoIncGameLogId() playerEx.currentLogId = logid sceneEx.SaveGameDetailedLog(logid, info, &base.GameDetailedParam{}) - totalin := playerEx.totalBet + var totalin int64 + if !playerEx.isFree { + totalin = playerEx.totalBet + } totalout := int64(data.RoundReward) + playerEx.taxCoin validFlow := totalin + totalout validBet := common.AbsI64(totalin - totalout) @@ -524,7 +530,7 @@ func FortuneRabbitAndSaveLog(sceneEx *FortuneRabbitSceneData, playerEx *FortuneR TotalOut: totalout, TaxCoin: playerEx.taxCoin, BetAmount: playerEx.totalBet, - WinAmountNoAnyTax: int64(data.RoundReward) + playerEx.taxCoin, + WinAmountNoAnyTax: int64(data.RoundReward), ValidBet: validBet, ValidFlow: validFlow, IsFirstGame: sceneEx.IsPlayerFirst(playerEx.Player), From b3798d54b87bcee7c105fca6045e05b996ef3d69 Mon Sep 17 00:00:00 2001 From: sk <123456@qq.com> Date: Thu, 28 Nov 2024 16:39:46 +0800 Subject: [PATCH 02/41] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=85=94=E5=AD=90?= =?UTF-8?q?=E6=8B=89=E9=9C=B8=E6=B8=B8=E6=88=8F=E8=AE=B0=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gamesrv/fortunerabbit/scenepolicy_fortunerabbit.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/gamesrv/fortunerabbit/scenepolicy_fortunerabbit.go b/gamesrv/fortunerabbit/scenepolicy_fortunerabbit.go index 954921e..d9974b1 100644 --- a/gamesrv/fortunerabbit/scenepolicy_fortunerabbit.go +++ b/gamesrv/fortunerabbit/scenepolicy_fortunerabbit.go @@ -512,11 +512,13 @@ func FortuneRabbitAndSaveLog(sceneEx *FortuneRabbitSceneData, playerEx *FortuneR logid, _ := model.AutoIncGameLogId() playerEx.currentLogId = logid sceneEx.SaveGameDetailedLog(logid, info, &base.GameDetailedParam{}) - var totalin int64 - if !playerEx.isFree { + var totalin, totalout int64 + if data.Results[0].FreeStatus == 1 || data.Results[0].FreeNumMax == 0 { totalin = playerEx.totalBet } - totalout := int64(data.RoundReward) + playerEx.taxCoin + if data.Results[0].FreeStatus == 3 || data.Results[0].FreeNumMax == 0 { + totalout = int64(data.RoundReward) + playerEx.taxCoin - playerEx.totalBet + } validFlow := totalin + totalout validBet := common.AbsI64(totalin - totalout) logParam := &base.SaveGamePlayerListLogParam{ From ce5e66b14858635e3d9ed1169d11483f9fdda6df Mon Sep 17 00:00:00 2001 From: sk <123456@qq.com> Date: Thu, 28 Nov 2024 17:45:25 +0800 Subject: [PATCH 03/41] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=85=94=E5=AD=90?= =?UTF-8?q?=E6=8B=89=E9=9C=B8=E6=B8=B8=E6=88=8F=E8=AE=B0=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gamesrv/fortunerabbit/scenepolicy_fortunerabbit.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/gamesrv/fortunerabbit/scenepolicy_fortunerabbit.go b/gamesrv/fortunerabbit/scenepolicy_fortunerabbit.go index d9974b1..2c340ee 100644 --- a/gamesrv/fortunerabbit/scenepolicy_fortunerabbit.go +++ b/gamesrv/fortunerabbit/scenepolicy_fortunerabbit.go @@ -504,7 +504,7 @@ func (this *ScenePolicyFortuneRabbit) GetSceneState(s *base.Scene, stateid int) func FortuneRabbitAndSaveLog(sceneEx *FortuneRabbitSceneData, playerEx *FortuneRabbitPlayerData, data assemble.GameEnd) { if !playerEx.IsRob { data.SnId = playerEx.SnId - if playerEx.isFree { + if data.Results[0].FreeStatus != 1 && data.Results[0].FreeNumMax != 0 { data.TotalBet = 0 } info, err := model.MarshalGameNoteByROLL(data) @@ -517,7 +517,7 @@ func FortuneRabbitAndSaveLog(sceneEx *FortuneRabbitSceneData, playerEx *FortuneR totalin = playerEx.totalBet } if data.Results[0].FreeStatus == 3 || data.Results[0].FreeNumMax == 0 { - totalout = int64(data.RoundReward) + playerEx.taxCoin - playerEx.totalBet + totalout = int64(data.RoundReward) + playerEx.taxCoin } validFlow := totalin + totalout validBet := common.AbsI64(totalin - totalout) @@ -532,7 +532,7 @@ func FortuneRabbitAndSaveLog(sceneEx *FortuneRabbitSceneData, playerEx *FortuneR TotalOut: totalout, TaxCoin: playerEx.taxCoin, BetAmount: playerEx.totalBet, - WinAmountNoAnyTax: int64(data.RoundReward), + WinAmountNoAnyTax: int64(totalout - totalin - playerEx.taxCoin), ValidBet: validBet, ValidFlow: validFlow, IsFirstGame: sceneEx.IsPlayerFirst(playerEx.Player), From 10d494e9a86598994aaa1deaf1654207a8bf0c75 Mon Sep 17 00:00:00 2001 From: sk <123456@qq.com> Date: Thu, 28 Nov 2024 17:48:56 +0800 Subject: [PATCH 04/41] =?UTF-8?q?=E4=BF=AE=E6=94=B9fortune=E7=89=8C?= =?UTF-8?q?=E5=B1=80=E8=AE=B0=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gamesrv/fortunedragon/scenepolicy_fortunedragon.go | 12 +++++++----- gamesrv/fortuneox/scenepolicy_fortuneox.go | 14 +++++++++++--- gamesrv/fortunerabbit/scenepolicy_fortunerabbit.go | 2 +- gamesrv/fortunetiger/scenepolicy_fortunetiger.go | 14 +++++++++++--- 4 files changed, 30 insertions(+), 12 deletions(-) diff --git a/gamesrv/fortunedragon/scenepolicy_fortunedragon.go b/gamesrv/fortunedragon/scenepolicy_fortunedragon.go index ed98382..c5fc2d8 100644 --- a/gamesrv/fortunedragon/scenepolicy_fortunedragon.go +++ b/gamesrv/fortunedragon/scenepolicy_fortunedragon.go @@ -505,7 +505,7 @@ func (this *ScenePolicyFortuneDragon) GetSceneState(s *base.Scene, stateid int) func FortuneDragonAndSaveLog(sceneEx *FortuneDragonSceneData, playerEx *FortuneDragonPlayerData, data assemble.GameEnd) { if !playerEx.IsRob { data.SnId = playerEx.SnId - if playerEx.isFree { + if data.Results[0].FreeStatus != 1 && data.Results[0].FreeNumMax != 0 { data.TotalBet = 0 } info, err := model.MarshalGameNoteByROLL(data) @@ -513,11 +513,13 @@ func FortuneDragonAndSaveLog(sceneEx *FortuneDragonSceneData, playerEx *FortuneD logid, _ := model.AutoIncGameLogId() playerEx.currentLogId = logid sceneEx.SaveGameDetailedLog(logid, info, &base.GameDetailedParam{}) - var totalin int64 - if !playerEx.isFree { + var totalin, totalout int64 + if data.Results[0].FreeStatus == 1 || data.Results[0].FreeNumMax == 0 { totalin = playerEx.totalBet } - totalout := int64(data.RoundReward) + playerEx.taxCoin + if data.Results[0].FreeStatus == 3 || data.Results[0].FreeNumMax == 0 { + totalout = int64(data.RoundReward) + playerEx.taxCoin + } validFlow := totalin + totalout validBet := common.AbsI64(totalin - totalout) logParam := &base.SaveGamePlayerListLogParam{ @@ -531,7 +533,7 @@ func FortuneDragonAndSaveLog(sceneEx *FortuneDragonSceneData, playerEx *FortuneD TotalOut: totalout, TaxCoin: playerEx.taxCoin, BetAmount: totalin, - WinAmountNoAnyTax: int64(data.RoundReward), + WinAmountNoAnyTax: totalout - totalin - playerEx.taxCoin, ValidBet: validBet, ValidFlow: validFlow, IsFirstGame: sceneEx.IsPlayerFirst(playerEx.Player), diff --git a/gamesrv/fortuneox/scenepolicy_fortuneox.go b/gamesrv/fortuneox/scenepolicy_fortuneox.go index 6c130ff..1e05719 100644 --- a/gamesrv/fortuneox/scenepolicy_fortuneox.go +++ b/gamesrv/fortuneox/scenepolicy_fortuneox.go @@ -510,13 +510,21 @@ func (this *ScenePolicyFortuneOx) GetSceneState(s *base.Scene, stateid int) base func FortuneOxAndSaveLog(sceneEx *FortuneOxSceneData, playerEx *FortuneOxPlayerData, data assemble.GameEnd) { if !playerEx.IsRob { data.SnId = playerEx.SnId + if data.Results[0].FreeStatus != 1 && data.Results[0].FreeNumMax != 0 { + data.TotalBet = 0 + } info, err := model.MarshalGameNoteByROLL(data) if err == nil { logid, _ := model.AutoIncGameLogId() playerEx.currentLogId = logid sceneEx.SaveGameDetailedLog(logid, info, &base.GameDetailedParam{}) - totalin := playerEx.totalBet - totalout := int64(data.RoundReward) + playerEx.taxCoin + var totalin, totalout int64 + if data.Results[0].FreeStatus == 1 || data.Results[0].FreeNumMax == 0 { + totalin = playerEx.totalBet + } + if data.Results[0].FreeStatus == 3 || data.Results[0].FreeNumMax == 0 { + totalout = int64(data.RoundReward) + playerEx.taxCoin + } validFlow := totalin + totalout validBet := common.AbsI64(totalin - totalout) logParam := &base.SaveGamePlayerListLogParam{ @@ -530,7 +538,7 @@ func FortuneOxAndSaveLog(sceneEx *FortuneOxSceneData, playerEx *FortuneOxPlayerD TotalOut: totalout, TaxCoin: playerEx.taxCoin, BetAmount: playerEx.totalBet, - WinAmountNoAnyTax: int64(data.RoundReward) + playerEx.taxCoin, + WinAmountNoAnyTax: totalout - totalin - playerEx.taxCoin, ValidBet: validBet, ValidFlow: validFlow, IsFirstGame: sceneEx.IsPlayerFirst(playerEx.Player), diff --git a/gamesrv/fortunerabbit/scenepolicy_fortunerabbit.go b/gamesrv/fortunerabbit/scenepolicy_fortunerabbit.go index 2c340ee..13e788c 100644 --- a/gamesrv/fortunerabbit/scenepolicy_fortunerabbit.go +++ b/gamesrv/fortunerabbit/scenepolicy_fortunerabbit.go @@ -532,7 +532,7 @@ func FortuneRabbitAndSaveLog(sceneEx *FortuneRabbitSceneData, playerEx *FortuneR TotalOut: totalout, TaxCoin: playerEx.taxCoin, BetAmount: playerEx.totalBet, - WinAmountNoAnyTax: int64(totalout - totalin - playerEx.taxCoin), + WinAmountNoAnyTax: totalout - totalin - playerEx.taxCoin, ValidBet: validBet, ValidFlow: validFlow, IsFirstGame: sceneEx.IsPlayerFirst(playerEx.Player), diff --git a/gamesrv/fortunetiger/scenepolicy_fortunetiger.go b/gamesrv/fortunetiger/scenepolicy_fortunetiger.go index 5cd4ab0..9edc6be 100644 --- a/gamesrv/fortunetiger/scenepolicy_fortunetiger.go +++ b/gamesrv/fortunetiger/scenepolicy_fortunetiger.go @@ -507,13 +507,21 @@ func (this *ScenePolicyFortuneTiger) GetSceneState(s *base.Scene, stateid int) b func FortuneTigerAndSaveLog(sceneEx *FortuneTigerSceneData, playerEx *FortuneTigerPlayerData, data assemble.GameEnd) { if !playerEx.IsRob { data.SnId = playerEx.SnId + if data.Results[0].FreeStatus != 1 && data.Results[0].FreeNumMax != 0 { + data.TotalBet = 0 + } info, err := model.MarshalGameNoteByROLL(data) if err == nil { logid, _ := model.AutoIncGameLogId() playerEx.currentLogId = logid sceneEx.SaveGameDetailedLog(logid, info, &base.GameDetailedParam{}) - totalin := playerEx.totalBet - totalout := int64(data.RoundReward) + playerEx.taxCoin + var totalin, totalout int64 + if data.Results[0].FreeStatus == 1 || data.Results[0].FreeNumMax == 0 { + totalin = playerEx.totalBet + } + if data.Results[0].FreeStatus == 3 || data.Results[0].FreeNumMax == 0 { + totalout = int64(data.RoundReward) + playerEx.taxCoin + } validFlow := totalin + totalout validBet := common.AbsI64(totalin - totalout) logParam := &base.SaveGamePlayerListLogParam{ @@ -527,7 +535,7 @@ func FortuneTigerAndSaveLog(sceneEx *FortuneTigerSceneData, playerEx *FortuneTig TotalOut: totalout, TaxCoin: playerEx.taxCoin, BetAmount: playerEx.totalBet, - WinAmountNoAnyTax: int64(data.RoundReward) + playerEx.taxCoin, + WinAmountNoAnyTax: totalout - totalin - playerEx.taxCoin, ValidBet: validBet, ValidFlow: validFlow, IsFirstGame: sceneEx.IsPlayerFirst(playerEx.Player), From 2fb75da43e6d1d6cd86c1c7da1aa6a71c8ee3e0f Mon Sep 17 00:00:00 2001 From: sk <123456@qq.com> Date: Fri, 29 Nov 2024 18:01:19 +0800 Subject: [PATCH 05/41] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=8D=81=E4=B8=89?= =?UTF-8?q?=E5=BC=A0=E6=8E=A8=E8=8D=90=E7=89=8C=E5=9E=8B=E7=AE=97=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gamerule/thirteen/logic.go | 12 +++++++++--- gamerule/thirteen/logic_test.go | 11 +++++++++++ 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/gamerule/thirteen/logic.go b/gamerule/thirteen/logic.go index e0cd97a..9a72eaa 100644 --- a/gamerule/thirteen/logic.go +++ b/gamerule/thirteen/logic.go @@ -612,13 +612,19 @@ func (l *Logic) findAllCombine(cards [13]int) (pokers []*Group) { i++ } } else if i == PokersTypeTwoPairs { + // 6,7,8 对子 + // 4,5,6 两对 al := len(copyCards) - if al == 7 || al == 6 { + if al == 8 || al == 7 { copy(poker.Mid[2:], card) } else if al == 5 || al == 4 { copy(poker.Mid[:], card) - } else if al == 8 { - copy(poker.Mid[:], card) + } else if al == 6 { + if poker.Mid[2] == -1 { + copy(poker.Mid[2:], card) + } else { + copy(poker.Mid[:], card) + } } else { copyCards = append(copyCards, card...) i++ diff --git a/gamerule/thirteen/logic_test.go b/gamerule/thirteen/logic_test.go index 729d406..2679cdf 100644 --- a/gamerule/thirteen/logic_test.go +++ b/gamerule/thirteen/logic_test.go @@ -87,6 +87,17 @@ func TestFindAllPokers(t *testing.T) { {46, 35, 30, 50, 34, 9, 25, 41, 3, 26, 2, 6, 45}, } + // + //牌序- A, K, Q, J,10, 9, 8, 7, 6, 5, 4, 3, 2 + //黑桃-51,50,49,48,47,46,45,44,43,42,41,40,39 + //红桃-38,37,36,35,34,33,32,31,30,29,28,27,26 + //梅花-25,24,23,22,21,20,19,18,17,16,15,14,13 + //方片-12,11,10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 + //data = [][13]int{ + // //{31, 42, 14, 49, 23, 25, 12, 6, 33, 20, 34, 21, 7}, + // {13, 23, 24, 36, 37, 38, 39, 51, 51, 50, 10, 11, 12}, + //} + for _, v := range data { cards := v fmt.Println(PokersShow(cards[:])) From 126f9579c5f6a5cb345c8d6fb673420748c160ca Mon Sep 17 00:00:00 2001 From: tomas Date: Mon, 2 Dec 2024 10:26:47 +0800 Subject: [PATCH 06/41] =?UTF-8?q?fix=20ox=20=E8=90=A5=E6=94=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- common/constant.go | 2 ++ gamesrv/fortuneox/scenepolicy_fortuneox.go | 14 +++++++++++--- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/common/constant.go b/common/constant.go index acc9646..4d6d278 100644 --- a/common/constant.go +++ b/common/constant.go @@ -84,6 +84,8 @@ const ( GameId_FortuneRabbit = 310 // FortuneRabbit GameId_FortuneOx = 311 // FortuneOx GameId_FortuneMouse = 312 // FortuneMouse + GameId_CashMania = 313 // CashMania + GameId_GatesOfOlympus = 314 // GatesOfOlympus __GameId_Fishing_Min__ = 400 //################捕鱼类################ GameId_HFishing = 401 //欢乐捕鱼 GameId_TFishing = 402 //天天捕鱼 diff --git a/gamesrv/fortuneox/scenepolicy_fortuneox.go b/gamesrv/fortuneox/scenepolicy_fortuneox.go index 1e05719..80de922 100644 --- a/gamesrv/fortuneox/scenepolicy_fortuneox.go +++ b/gamesrv/fortuneox/scenepolicy_fortuneox.go @@ -510,19 +510,27 @@ func (this *ScenePolicyFortuneOx) GetSceneState(s *base.Scene, stateid int) base func FortuneOxAndSaveLog(sceneEx *FortuneOxSceneData, playerEx *FortuneOxPlayerData, data assemble.GameEnd) { if !playerEx.IsRob { data.SnId = playerEx.SnId - if data.Results[0].FreeStatus != 1 && data.Results[0].FreeNumMax != 0 { + var respinStatus int + if data.Results[0].ArrSpins[0].Special != nil { + sp, _ := json.Marshal(data.Results[0].ArrSpins[0].Special) + var spinLock SpinLock + json.Unmarshal(sp, &spinLock) + respinStatus = spinLock.ReSpinStatus + } + if respinStatus != 0 && respinStatus != 1 { data.TotalBet = 0 } + info, err := model.MarshalGameNoteByROLL(data) if err == nil { logid, _ := model.AutoIncGameLogId() playerEx.currentLogId = logid sceneEx.SaveGameDetailedLog(logid, info, &base.GameDetailedParam{}) var totalin, totalout int64 - if data.Results[0].FreeStatus == 1 || data.Results[0].FreeNumMax == 0 { + if respinStatus == 1 { totalin = playerEx.totalBet } - if data.Results[0].FreeStatus == 3 || data.Results[0].FreeNumMax == 0 { + if respinStatus == 0 || respinStatus == 3 { totalout = int64(data.RoundReward) + playerEx.taxCoin } validFlow := totalin + totalout From 5dcd4175f9cf82242bc360ef520f535d9784e28c Mon Sep 17 00:00:00 2001 From: tomas Date: Mon, 2 Dec 2024 10:40:19 +0800 Subject: [PATCH 07/41] add cm goo proto and mouse.go --- gamerule/fortunemouse/constants.go | 22 + gamesrv/fortunemouse/action_fortunemouse.go | 46 + .../fortunemouse/playerdata_fortunemouse.go | 51 ++ .../fortunemouse/scenedata_fortunemouse.go | 45 + .../fortunemouse/scenepolicy_fortunemouse.go | 585 +++++++++++++ protocol/cashmania/cashmania.pb.go | 799 +++++++++++++++++ protocol/cashmania/cashmania.proto | 68 ++ protocol/doc.md | 22 +- protocol/gatesofolympus/gatesofolympus.pb.go | 806 ++++++++++++++++++ protocol/gatesofolympus/gatesofolympus.proto | 68 ++ 10 files changed, 2505 insertions(+), 7 deletions(-) create mode 100644 gamerule/fortunemouse/constants.go create mode 100644 gamesrv/fortunemouse/action_fortunemouse.go create mode 100644 gamesrv/fortunemouse/playerdata_fortunemouse.go create mode 100644 gamesrv/fortunemouse/scenedata_fortunemouse.go create mode 100644 gamesrv/fortunemouse/scenepolicy_fortunemouse.go create mode 100644 protocol/cashmania/cashmania.pb.go create mode 100644 protocol/cashmania/cashmania.proto create mode 100644 protocol/gatesofolympus/gatesofolympus.pb.go create mode 100644 protocol/gatesofolympus/gatesofolympus.proto diff --git a/gamerule/fortunemouse/constants.go b/gamerule/fortunemouse/constants.go new file mode 100644 index 0000000..e99fda7 --- /dev/null +++ b/gamerule/fortunemouse/constants.go @@ -0,0 +1,22 @@ +package fortunemouse + +// 房间类型 +const ( + RoomMode_Classic int = iota //经典 + RoomMode_Max +) + +// 场景状态 +const ( + FortuneMouseStateStart int = iota //默认状态 + FortuneMouseStateMax +) + +// 玩家操作 +const ( + FortuneMousePlayerOpStart int = iota + FortuneMousePlayerOpSwitch +) +const NowByte int64 = 10000 + +const GameDataKey = "FortuneData" diff --git a/gamesrv/fortunemouse/action_fortunemouse.go b/gamesrv/fortunemouse/action_fortunemouse.go new file mode 100644 index 0000000..2015e97 --- /dev/null +++ b/gamesrv/fortunemouse/action_fortunemouse.go @@ -0,0 +1,46 @@ +package fortunemouse + +import ( + "mongo.games.com/game/common" + "mongo.games.com/game/gamesrv/base" + "mongo.games.com/game/protocol/fortunemouse" + "mongo.games.com/goserver/core/logger" + "mongo.games.com/goserver/core/netlib" +) + +type CSFortuneMouseOpPacketFactory struct { +} +type CSFortuneMouseOpHandler struct { +} + +func (this *CSFortuneMouseOpPacketFactory) CreatePacket() interface{} { + pack := &fortunemouse.CSFortuneMouseOp{} + return pack +} + +func (this *CSFortuneMouseOpHandler) Process(s *netlib.Session, packetid int, data interface{}, sid int64) error { + if op, ok := data.(*fortunemouse.CSFortuneMouseOp); ok { + p := base.PlayerMgrSington.GetPlayer(sid) + if p == nil { + logger.Logger.Warn("CSFortuneMouseOpHandler p == nil") + return nil + } + scene := p.GetScene() + if scene == nil { + logger.Logger.Warn("CSFortuneMouseOpHandler p.scene == nil") + return nil + } + if !scene.HasPlayer(p) { + return nil + } + if scene.GetScenePolicy() != nil { + scene.GetScenePolicy().OnPlayerOp(scene, p, int(op.GetOpCode()), op.GetParams()) + } + return nil + } + return nil +} +func init() { + common.RegisterHandler(int(fortunemouse.FortuneMousePID_PACKET_FORTUNEMOUSE_CSFORTUNEMOUSEOP), &CSFortuneMouseOpHandler{}) + netlib.RegisterFactory(int(fortunemouse.FortuneMousePID_PACKET_FORTUNEMOUSE_CSFORTUNEMOUSEOP), &CSFortuneMouseOpPacketFactory{}) +} diff --git a/gamesrv/fortunemouse/playerdata_fortunemouse.go b/gamesrv/fortunemouse/playerdata_fortunemouse.go new file mode 100644 index 0000000..204763e --- /dev/null +++ b/gamesrv/fortunemouse/playerdata_fortunemouse.go @@ -0,0 +1,51 @@ +package fortunemouse + +import ( + "mongo.games.com/game/gamerule/fortunemouse" + "mongo.games.com/game/gamesrv/base" + "mongo.games.com/game/gamesrv/slotspkg/slots" +) + +type FortuneMousePlayerData struct { + *base.Player + leaveTime int32 //离开时间 + SlotsSession *base.SlotsSession + + BetSizeIndex int64 `json:"bsi"` //选中的单注下标 + BetLevelIndex int64 `json:"bli"` //选中的等级下标 + BetLineIndex int64 `json:"bii"` //选中的线数下标 + BetMode int64 `json:"bm,optional"` //0.常规 1.必中 + + taxCoin int64 + winCoin int64 + currentLogId string + totalBet int64 + + isRespin bool //只用于判断是否可以离开 +} + +type SpinLock struct { + ReSpinStatus int `json:"rs,omitempty"` //0.默认 1.第一次触发 2.进行中 3.结束 + //OXSpecial + NewSuperStack []int64 `json:"nss,omitempty"` +} + +func (p *FortuneMousePlayerData) init() { + p.SlotsSession = base.NewSession(uint64(p.SnId), p.Coin*fortunemouse.NowByte) +} +func (p *FortuneMousePlayerData) Clear() { + p.taxCoin = 0 + p.winCoin = 0 + p.currentLogId = "" +} + +// 需要带到world上进行数据处理 +func (p *FortuneMousePlayerData) PushPlayer() map[string]string { + cache := slots.SlotsMgrSington.PushPlayer(p.SlotsSession) + return cache +} + +// 进房的时候需要带进来 +func (p *FortuneMousePlayerData) PullPlayer(data map[string]string) { + slots.SlotsMgrSington.PullPlayer(p.SlotsSession, data) +} diff --git a/gamesrv/fortunemouse/scenedata_fortunemouse.go b/gamesrv/fortunemouse/scenedata_fortunemouse.go new file mode 100644 index 0000000..d560055 --- /dev/null +++ b/gamesrv/fortunemouse/scenedata_fortunemouse.go @@ -0,0 +1,45 @@ +package fortunemouse + +import ( + "mongo.games.com/game/gamesrv/base" + "mongo.games.com/game/gamesrv/slotspkg/assemble" +) + +type FortuneMouseSceneData struct { + *base.Scene //场景 + players map[int32]*FortuneMousePlayerData //玩家信息 + BetConfig *assemble.BetConfig +} + +func NewFortuneMouseSceneData(s *base.Scene) *FortuneMouseSceneData { + sceneEx := &FortuneMouseSceneData{ + Scene: s, + players: make(map[int32]*FortuneMousePlayerData), + } + sceneEx.Init() + return sceneEx +} +func (s *FortuneMouseSceneData) Init() { + +} + +func (s *FortuneMouseSceneData) Clear() { + //应该是水池变一次就判断修改一次 + //s.slotRateWeight = s.slotRateWeightTotal[0] +} +func (s *FortuneMouseSceneData) SceneDestroy(force bool) { + //销毁房间 + s.Scene.Destroy(force) +} + +func (s *FortuneMouseSceneData) delPlayer(SnId int32) { + if _, exist := s.players[SnId]; exist { + delete(s.players, SnId) + } +} +func (s *FortuneMouseSceneData) OnPlayerLeave(p *base.Player, reason int) { + if /*playerEx*/ _, ok := p.ExtraData.(*FortuneMousePlayerData); ok { + + } + s.delPlayer(p.SnId) +} diff --git a/gamesrv/fortunemouse/scenepolicy_fortunemouse.go b/gamesrv/fortunemouse/scenepolicy_fortunemouse.go new file mode 100644 index 0000000..c330f41 --- /dev/null +++ b/gamesrv/fortunemouse/scenepolicy_fortunemouse.go @@ -0,0 +1,585 @@ +package fortunemouse + +import ( + "encoding/json" + "mongo.games.com/game/common" + "mongo.games.com/game/gamerule/fortunemouse" + "mongo.games.com/game/gamesrv/base" + "mongo.games.com/game/gamesrv/slotspkg/assemble" + "mongo.games.com/game/gamesrv/slotspkg/slots" + "mongo.games.com/game/model" + "mongo.games.com/game/proto" + protocol "mongo.games.com/game/protocol/fortunemouse" + "mongo.games.com/game/protocol/server" + "mongo.games.com/goserver/core" + "mongo.games.com/goserver/core/logger" + "time" +) + +// //////////////////////////////////////////////////////////// +var ScenePolicyFortuneMouseSington = &ScenePolicyFortuneMouse{} + +type ScenePolicyFortuneMouse struct { + base.BaseScenePolicy + states [fortunemouse.FortuneMouseStateMax]base.SceneState +} + +// 创建场景扩展数据 +func (this *ScenePolicyFortuneMouse) CreateSceneExData(s *base.Scene) interface{} { + sceneEx := NewFortuneMouseSceneData(s) + if sceneEx != nil { + if sceneEx.GetInit() { + s.SetExtraData(sceneEx) + } + } + return sceneEx +} + +// 创建玩家扩展数据 +func (this *ScenePolicyFortuneMouse) CreatePlayerExData(s *base.Scene, p *base.Player) interface{} { + playerEx := &FortuneMousePlayerData{Player: p} + p.SetExtraData(playerEx) + return playerEx +} + +// 场景开启事件 +func (this *ScenePolicyFortuneMouse) OnStart(s *base.Scene) { + logger.Logger.Trace("(this *ScenePolicyFortuneMouse) OnStart, sceneId=", s.GetSceneId()) + sceneEx := NewFortuneMouseSceneData(s) + if sceneEx != nil { + if sceneEx.GetInit() { + s.SetExtraData(sceneEx) + s.ChangeSceneState(fortunemouse.FortuneMouseStateStart) + } + } +} + +// 场景关闭事件 +func (this *ScenePolicyFortuneMouse) OnStop(s *base.Scene) { + logger.Logger.Trace("(this *ScenePolicyFortuneMouse) OnStop , sceneId=", s.GetSceneId()) +} + +// 场景心跳事件 +func (this *ScenePolicyFortuneMouse) OnTick(s *base.Scene) { + if s == nil { + return + } + if s.GetSceneState() != nil { + s.GetSceneState().OnTick(s) + } +} + +// 玩家进入事件 +func (this *ScenePolicyFortuneMouse) OnPlayerEnter(s *base.Scene, p *base.Player) { + if s == nil || p == nil { + return + } + logger.Logger.Trace("(this *ScenePolicyFortuneMouse) OnPlayerEnter, sceneId=", s.GetSceneId(), " player=", p.Name) + if sceneEx, ok := s.GetExtraData().(*FortuneMouseSceneData); ok { + playerEx := &FortuneMousePlayerData{Player: p} + + playerEx.init() + + d := p.GameData[fortunemouse.GameDataKey] + if d != nil { + m := make(map[string]string) + json.Unmarshal(d.Data.([]byte), &m) + playerEx.PullPlayer(m) + } else { + m := make(map[string]string) + //json.Unmarshal(d.Data.([]byte), &m) + playerEx.PullPlayer(m) + } + + playerEx.SlotsSession.SetCoin(playerEx.Coin * fortunemouse.NowByte) + + playerEx.Clear() + + sceneEx.players[p.SnId] = playerEx + + p.SetExtraData(playerEx) + FortuneMouseSendRoomInfo(s, sceneEx, playerEx) + + s.FirePlayerEvent(p, base.PlayerEventEnter, nil) + } +} + +// 玩家离开事件 +func (this *ScenePolicyFortuneMouse) OnPlayerLeave(s *base.Scene, p *base.Player, reason int) { + if s == nil || p == nil { + return + } + logger.Logger.Trace("(this *ScenePolicyFortuneMouse) OnPlayerLeave, sceneId=", s.GetSceneId(), " player=", p.SnId) + if playerEx, ok := p.ExtraData.(*FortuneMousePlayerData); ok { + m := playerEx.PushPlayer() + if m != nil && len(m) > 0 { + b, err := json.Marshal(m) + if err != nil { + logger.Logger.Error("OnPlayerLeave, json.Marshal error:", err) + } else { + p.GameData[fortunemouse.GameDataKey] = &model.PlayerGameData{ + Platform: p.Platform, + SnId: p.SnId, + Id: fortunemouse.GameDataKey, + Data: b, + } + } + } + } + if sceneEx, ok := s.ExtraData.(*FortuneMouseSceneData); ok { + s.FirePlayerEvent(p, base.PlayerEventLeave, nil) + sceneEx.OnPlayerLeave(p, reason) + } +} + +// 玩家掉线 +func (this *ScenePolicyFortuneMouse) OnPlayerDropLine(s *base.Scene, p *base.Player) { + if s == nil || p == nil { + return + } + logger.Logger.Trace("(this *ScenePolicyFortuneMouse) OnPlayerDropLine, sceneId=", s.GetSceneId(), " player=", p.SnId) + s.FirePlayerEvent(p, base.PlayerEventDropLine, nil) +} + +// 玩家重连 +func (this *ScenePolicyFortuneMouse) OnPlayerRehold(s *base.Scene, p *base.Player) { + if s == nil || p == nil { + return + } + logger.Logger.Trace("(this *ScenePolicyFortuneMouse) OnPlayerRehold, sceneId=", s.GetSceneId(), " player=", p.SnId) + if sceneEx, ok := s.GetExtraData().(*FortuneMouseSceneData); ok { + if playerEx, ok := p.GetExtraData().(*FortuneMousePlayerData); ok { + FortuneMouseSendRoomInfo(s, sceneEx, playerEx) + } + } +} + +// 返回房间 +func (this *ScenePolicyFortuneMouse) OnPlayerReturn(s *base.Scene, p *base.Player) { + if s == nil || p == nil { + return + } + logger.Logger.Trace("(this *ScenePolicyFortuneMouse) OnPlayerReturn, GetSceneId()=", s.GetSceneId(), " player=", p.Name) + if sceneEx, ok := s.GetExtraData().(*FortuneMouseSceneData); ok { + if playerEx, ok := p.GetExtraData().(*FortuneMousePlayerData); ok { + //if p.IsMarkFlag(base.PlayerState_Auto) { + // p.UnmarkFlag(base.PlayerState_Auto) + // p.SyncFlag() + //} + //发送房间信息给自己 + FortuneMouseSendRoomInfo(s, sceneEx, playerEx) + s.FirePlayerEvent(p, base.PlayerEventReturn, nil) + } + } +} + +func FortuneMouseSendRoomInfo(s *base.Scene, sceneEx *FortuneMouseSceneData, playerEx *FortuneMousePlayerData) { + pack := FortuneMouseCreateRoomInfoPacket(s, sceneEx, playerEx) + logger.Logger.Trace("RoomInfo: ", pack) + playerEx.SendToClient(int(protocol.FortuneMousePID_PACKET_FORTUNEMOUSE_SCFORTUNEMOUSEROOMINFO), pack) +} +func FortuneMouseCreateRoomInfoPacket(s *base.Scene, sceneEx *FortuneMouseSceneData, playerEx *FortuneMousePlayerData) interface{} { + //房间信息 + pack := &protocol.SCFortuneMouseRoomInfo{ + RoomId: s.SceneId, + GameId: s.GameId, + RoomMode: s.SceneMode, + SceneType: s.GetSceneType(), + Params: common.CopySliceInt64ToInt32(s.Params), + NumOfGames: proto.Int(sceneEx.NumOfGames), + State: proto.Int(s.SceneState.GetState()), + ParamsEx: s.GetDBGameFree().OtherIntParams, + GameFreeId: proto.Int32(s.GetDBGameFree().Id), + //BetLimit: s.GetDBGameFree().BetLimit, + } + + //自己的信息 + if playerEx != nil { + pd := &protocol.FortuneMousePlayerData{ + SnId: proto.Int32(playerEx.SnId), + Name: proto.String(playerEx.Name), + Head: proto.Int32(playerEx.Head), + Sex: proto.Int32(playerEx.Sex), + Coin: proto.Int64(playerEx.Coin), + Pos: proto.Int(playerEx.Pos), + Flag: proto.Int(playerEx.GetFlag()), + City: proto.String(playerEx.City), + HeadOutLine: proto.Int32(playerEx.HeadOutLine), + VIP: proto.Int32(playerEx.VIP), + } + pack.Player = pd + } + + //get data + Response, err := slots.SlotsMgrSington.Enter(playerEx.SlotsSession, int64(s.GameId)) + if err == nil { + data := assemble.DataToCli(Response).(assemble.TableInfo) + pi, _ := json.Marshal(data) + pack.PlayerInfo = string(pi) + if sceneEx.BetConfig == nil { + sceneEx.BetConfig = &data.BetConfig + } + } else { + logger.Logger.Error("slots enter err:", err) + } + proto.SetDefaults(pack) + return pack +} +func (this *ScenePolicyFortuneMouse) OnPlayerOp(s *base.Scene, p *base.Player, opcode int, params []int64) bool { + if s == nil || p == nil { + return false + } + logger.Logger.Trace("(this *ScenePolicyFortuneMouse) OnPlayerOp, sceneId=", s.GetSceneId(), " player=", p.SnId, " opcode=", opcode, " params=", params) + if s.GetSceneState() != nil { + if s.GetSceneState().OnPlayerOp(s, p, opcode, params) { + p.SetLastOPTimer(time.Now()) + return true + } + return false + } + return true +} + +func (this *ScenePolicyFortuneMouse) OnPlayerEvent(s *base.Scene, p *base.Player, evtcode int, params []int64) { + if s == nil || p == nil { + return + } + logger.Logger.Trace("(this *ScenePolicyFortuneMouse) OnPlayerEvent, sceneId=", s.GetSceneId(), " player=", p.SnId, " eventcode=", evtcode, " params=", params) + if s.GetSceneState() != nil { + s.GetSceneState().OnPlayerEvent(s, p, evtcode, params) + } +} + +// 当前状态能否换桌 +func (this *ScenePolicyFortuneMouse) CanChangeCoinScene(s *base.Scene, p *base.Player) bool { + if s == nil || p == nil { + return false + } + if s.GetSceneState() != nil { + return s.GetSceneState().CanChangeCoinScene(s, p) + } + return false +} + +// 状态基类 +type SceneBaseStateFortuneMouse struct { +} + +func (this *SceneBaseStateFortuneMouse) GetTimeout(s *base.Scene) int { + if sceneEx, ok := s.GetExtraData().(*FortuneMouseSceneData); ok { + return int(time.Now().Sub(sceneEx.GetStateStartTime()) / time.Second) + } + return 0 +} + +func (this *SceneBaseStateFortuneMouse) CanChangeTo(s base.SceneState) bool { + return true +} + +// 当前状态能否换桌 +func (this *SceneBaseStateFortuneMouse) CanChangeCoinScene(s *base.Scene, p *base.Player) bool { + return true +} +func (this *SceneBaseStateFortuneMouse) OnEnter(s *base.Scene) { + if sceneEx, ok := s.GetExtraData().(*FortuneMouseSceneData); ok { + sceneEx.SetStateStartTime(time.Now()) + } +} + +func (this *SceneBaseStateFortuneMouse) OnLeave(s *base.Scene) {} +func (this *SceneBaseStateFortuneMouse) OnTick(s *base.Scene) { + if time.Now().Sub(s.GameStartTime) > time.Second*3 { + if sceneEx, ok := s.ExtraData.(*FortuneMouseSceneData); ok { + for _, p := range sceneEx.players { + if p.IsOnLine() { + p.leaveTime = 0 + continue + } + p.leaveTime++ + if p.leaveTime < 60*2 { + continue + } + //踢出玩家 + sceneEx.PlayerLeave(p.Player, common.PlayerLeaveReason_LongTimeNoOp, true) + } + } + s.GameStartTime = time.Now() + } +} +func (this *SceneBaseStateFortuneMouse) OnPlayerOp(s *base.Scene, p *base.Player, opcode int, params []int64) bool { + return false +} +func (this *SceneBaseStateFortuneMouse) OnPlayerEvent(s *base.Scene, p *base.Player, evtcode int, params []int64) { +} + +// //////////////////////////////////////////////////////////// +// 开始状态 +// //////////////////////////////////////////////////////////// +type SceneStateStartFortuneMouse struct { + SceneBaseStateFortuneMouse +} + +func (this *SceneStateStartFortuneMouse) GetState() int { + return fortunemouse.FortuneMouseStateStart +} + +func (this *SceneStateStartFortuneMouse) CanChangeTo(s base.SceneState) bool { + return false +} + +// 当前状态能否换桌 +func (this *SceneStateStartFortuneMouse) CanChangeCoinScene(s *base.Scene, p *base.Player) bool { + if playerEx, ok := p.GetExtraData().(*FortuneMousePlayerData); ok { + if playerEx.isRespin { + return false + } + } + return true +} + +func (this *SceneStateStartFortuneMouse) GetTimeout(s *base.Scene) int { + return 0 +} + +func (this *SceneStateStartFortuneMouse) OnEnter(s *base.Scene) { + this.SceneBaseStateFortuneMouse.OnEnter(s) + if sceneEx, ok := s.GetExtraData().(*FortuneMouseSceneData); ok { + sceneEx.SetGameNowTime(time.Now()) + } +} + +// 状态离开时 +func (this *SceneStateStartFortuneMouse) OnLeave(s *base.Scene) { + this.SceneBaseStateFortuneMouse.OnLeave(s) + logger.Logger.Tracef("(this *SceneStateStartFortuneMouse) OnLeave, sceneid=%v", s.GetSceneId()) +} + +// 玩家操作 +func (this *SceneStateStartFortuneMouse) OnPlayerOp(s *base.Scene, p *base.Player, opcode int, params []int64) bool { + logger.Logger.Tracef("(this *SceneStateStartFortuneMouse) OnPlayerOp, sceneid=%v params=%v", s.GetSceneId(), params) + if this.SceneBaseStateFortuneMouse.OnPlayerOp(s, p, opcode, params) { + return true + } + if sceneEx, ok := s.GetExtraData().(*FortuneMouseSceneData); ok { + if playerEx, ok := p.GetExtraData().(*FortuneMousePlayerData); ok { + switch opcode { + case fortunemouse.FortuneMousePlayerOpStart: + playerEx.Clear() + if len(params) < 3 { + pack := &protocol.SCFortuneMouseBilled{ + OpRetCode: proto.Int32(1), + } + proto.SetDefaults(pack) + logger.Logger.Trace("SCFortuneMouseBilled", pack.String()) + playerEx.SendToClient(int(protocol.FortuneMousePID_PACKET_FORTUNEMOUSE_SCFORTUNEMOUSEBILLED), pack) + return true + } + playerEx.BetSizeIndex = params[0] + playerEx.BetLevelIndex = params[1] + playerEx.BetLineIndex = params[2] + //playerEx.BetMode = params[3] + needCoin := sceneEx.BetConfig.BetSize[params[0]] * float64(sceneEx.BetConfig.BetLevel[params[1]]) * + float64(sceneEx.BetConfig.BetLines[params[2]]) + if needCoin > float64(playerEx.Coin) { + pack := &protocol.SCFortuneMouseBilled{ + OpRetCode: proto.Int32(1), + } + proto.SetDefaults(pack) + logger.Logger.Trace("SCFortuneMouseBilled:", pack.String()) + playerEx.SendToClient(int(protocol.FortuneMousePID_PACKET_FORTUNEMOUSE_SCFORTUNEMOUSEBILLED), pack) + return true + } + + //playerEx.SlotsSession.SetCoin(playerEx.Coin * fortunemouse.NowByte) + //logger.Logger.Trace("=============init dif coin", playerEx.Coin-playerEx.SlotsSession.Coin()/fortunemouse.NowByte) + + //get data + Response, err := slots.SlotsMgrSington.Play(playerEx.SlotsSession, &base.SpinReq{ + GameId: int64(sceneEx.GameId), + BetSizeIndex: playerEx.BetSizeIndex, + BetLevelIndex: playerEx.BetLevelIndex, + BetLineIndex: playerEx.BetLineIndex, + BetMode: playerEx.BetMode, + Ts: time.Now().Unix(), + }) + var gameEndStr string + var data assemble.GameEnd + if err == nil { + data = assemble.DataToCli(Response).(assemble.GameEnd) + var respinStatus int + if data.Results[0].ArrSpins[0].Special != nil { + sp, _ := json.Marshal(data.Results[0].ArrSpins[0].Special) + var spinLock SpinLock + json.Unmarshal(sp, &spinLock) + respinStatus = spinLock.ReSpinStatus + } + if respinStatus == 0 || respinStatus == 1 { + //第一次触发或者正常模式 + //logger.Logger.Trace("=============addcoin1111 ", -data.TotalBet) + playerEx.AddCoin(int64(-data.TotalBet), common.GainWay_HundredSceneLost, base.SyncFlag_ToClient, "system", s.GetSceneName()) + playerEx.totalBet = int64(data.TotalBet) + //logger.Logger.Trace("=======bet======dif++++ ", float64(playerEx.Coin)-data.BetAfterCoin) + } + var taxCoin float64 + if data.RoundReward > 0 { + //税收比例 + taxRate := sceneEx.GetDBGameFree().GetTaxRate() + if taxRate < 0 || taxRate > 10000 { + taxRate = 500 + } + taxCoin = data.RoundReward * float64(taxRate) / 10000 + data.RoundReward = data.RoundReward - taxCoin + playerEx.AddServiceFee(int64(taxCoin)) + playerEx.taxCoin = int64(taxCoin) + playerEx.winCoin = int64(data.RoundReward) + } + pi, _ := json.Marshal(data) + gameEndStr = string(pi) + if respinStatus == 0 || respinStatus == 3 { + //logger.Logger.Trace("===win==========addcoin222 ", data.RoundReward) + playerEx.AddCoin(int64(data.RoundReward), common.GainWay_HundredSceneWin, 0, "system", s.GetSceneName()) + //logger.Logger.Trace("=======win======dif++++ ", float64(playerEx.Coin)-data.FinalCoin) + //免费游戏结束或者正常模式 + sceneEx.StaticsLaba(&base.StaticLabaParam{ + SnId: playerEx.SnId, + Gain: int64(data.RoundReward - data.TotalBet), + GainTax: int64(taxCoin), + IsAddTimes: true, + }) + } + if respinStatus == 0 || respinStatus == 3 { + playerEx.isRespin = false + } else { + playerEx.isRespin = true + } + } else { + logger.Logger.Error("slots Play err:", err) + } + + playerEx.SlotsSession.SetCoin(int64(data.FinalCoin) * fortunemouse.NowByte) + + //logger.Logger.Trace("======end=======init dif coin", playerEx.Coin-playerEx.SlotsSession.Coin()/fortunemouse.NowByte) + + if playerEx.Coin != int64(data.FinalCoin) { + logger.Logger.Error("==========playerEx.Coin != data.FinalCoin==============", (float64(playerEx.Coin)-data.FinalCoin)/10000) + } + pack := &protocol.SCFortuneMouseBilled{ + OpRetCode: proto.Int32(0), + GameEndStr: proto.String(gameEndStr), + } + proto.SetDefaults(pack) + logger.Logger.Trace("SCFortuneMouseBilled", pack.String()) + playerEx.SendToClient(int(protocol.FortuneMousePID_PACKET_FORTUNEMOUSE_SCFORTUNEMOUSEBILLED), pack) + + // 记录本次操作 + FortuneMouseAndSaveLog(sceneEx, playerEx, data) + } + } + } + return true +} + +// 玩家事件 +func (this *SceneStateStartFortuneMouse) OnPlayerEvent(s *base.Scene, p *base.Player, evtcode int, params []int64) { + logger.Logger.Trace("(this *SceneStateStartFortuneMouse) OnPlayerEvent, sceneId=", s.GetSceneId(), " player=", p.SnId, " evtcode=", evtcode) + this.SceneBaseStateFortuneMouse.OnPlayerEvent(s, p, evtcode, params) +} + +func (this *SceneStateStartFortuneMouse) OnTick(s *base.Scene) { + this.SceneBaseStateFortuneMouse.OnTick(s) +} + +// ////////////////////////////////////////////////////////////////////////////// +func (this *ScenePolicyFortuneMouse) RegisteSceneState(state base.SceneState) { + if state == nil { + return + } + stateid := state.GetState() + if stateid < 0 || stateid >= fortunemouse.FortuneMouseStateMax { + return + } + this.states[stateid] = state +} + +func (this *ScenePolicyFortuneMouse) GetSceneState(s *base.Scene, stateid int) base.SceneState { + if stateid >= 0 && stateid < fortunemouse.FortuneMouseStateMax { + return this.states[stateid] + } + return nil +} +func FortuneMouseAndSaveLog(sceneEx *FortuneMouseSceneData, playerEx *FortuneMousePlayerData, data assemble.GameEnd) { + if !playerEx.IsRob { + data.SnId = playerEx.SnId + if data.Results[0].FreeStatus != 1 && data.Results[0].FreeNumMax != 0 { + data.TotalBet = 0 + } + info, err := model.MarshalGameNoteByROLL(data) + if err == nil { + logid, _ := model.AutoIncGameLogId() + playerEx.currentLogId = logid + sceneEx.SaveGameDetailedLog(logid, info, &base.GameDetailedParam{}) + var totalin, totalout int64 + if data.Results[0].FreeStatus == 1 || data.Results[0].FreeNumMax == 0 { + totalin = playerEx.totalBet + } + if data.Results[0].FreeStatus == 3 || data.Results[0].FreeNumMax == 0 { + totalout = int64(data.RoundReward) + playerEx.taxCoin + } + validFlow := totalin + totalout + validBet := common.AbsI64(totalin - totalout) + logParam := &base.SaveGamePlayerListLogParam{ + Platform: playerEx.Platform, + Channel: playerEx.Channel, + Promoter: playerEx.BeUnderAgentCode, + PackageTag: playerEx.PackageID, + InviterId: playerEx.InviterId, + LogId: logid, + TotalIn: totalin, + TotalOut: totalout, + TaxCoin: playerEx.taxCoin, + BetAmount: playerEx.totalBet, + WinAmountNoAnyTax: totalout - totalin - playerEx.taxCoin, + ValidBet: validBet, + ValidFlow: validFlow, + IsFirstGame: sceneEx.IsPlayerFirst(playerEx.Player), + } + sceneEx.SaveGamePlayerListLog(playerEx.SnId, logParam) + } + } + + //统计输下注金币数 + if !sceneEx.Testing && !playerEx.IsRob { + playerBet := &server.PlayerData{ + SnId: proto.Int32(playerEx.SnId), + Bet: proto.Int64(playerEx.CurrentBet), + Gain: proto.Int64(int64(data.RoundReward) + playerEx.taxCoin), + Tax: proto.Int64(playerEx.taxCoin), + Coin: proto.Int64(playerEx.GetCoin()), + GameCoinTs: proto.Int64(playerEx.GameCoinTs), + } + gwPlayerBet := &server.GWPlayerData{ + SceneId: sceneEx.SceneId, + GameFreeId: proto.Int32(sceneEx.GetDBGameFree().GetId()), + } + gwPlayerBet.Datas = append(gwPlayerBet.Datas, playerBet) + sceneEx.SyncPlayerDatas(&base.PlayerDataParam{ + HasRobotGaming: false, + Data: gwPlayerBet, + }) + } + + playerEx.taxCoin = 0 + playerEx.winCoin = 0 + + if sceneEx.CheckNeedDestroy() && data.Results[0].FreeNum <= 0 { + sceneEx.SceneDestroy(true) + } +} +func init() { + //主状态 + ScenePolicyFortuneMouseSington.RegisteSceneState(&SceneStateStartFortuneMouse{}) + core.RegisteHook(core.HOOK_BEFORE_START, func() error { + base.RegisteScenePolicy(common.GameId_FortuneMouse, fortunemouse.RoomMode_Classic, ScenePolicyFortuneMouseSington) + return nil + }) +} diff --git a/protocol/cashmania/cashmania.pb.go b/protocol/cashmania/cashmania.pb.go new file mode 100644 index 0000000..623796b --- /dev/null +++ b/protocol/cashmania/cashmania.pb.go @@ -0,0 +1,799 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.27.1-devel +// protoc v3.19.4 +// source: protocol/cashmania/cashmania.proto + +package cashmania + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +//cashmania +//龙 +type CashManiaPID int32 + +const ( + CashManiaPID_PACKET_CASHMANIA_ZERO CashManiaPID = 0 // 弃用消息号 + CashManiaPID_PACKET_CASHMANIA_SCCASHMANIAROOMINFO CashManiaPID = 5650 //房间信息 + CashManiaPID_PACKET_CASHMANIA_CSCASHMANIAOP CashManiaPID = 5651 + CashManiaPID_PACKET_CASHMANIA_SCCASHMANIAOP CashManiaPID = 5652 + CashManiaPID_PACKET_CASHMANIA_SCCASHMANIAROOMSTATE CashManiaPID = 5653 + CashManiaPID_PACKET_CASHMANIA_SCCASHMANIABILLED CashManiaPID = 5654 +) + +// Enum value maps for CashManiaPID. +var ( + CashManiaPID_name = map[int32]string{ + 0: "PACKET_CASHMANIA_ZERO", + 5650: "PACKET_CASHMANIA_SCCASHMANIAROOMINFO", + 5651: "PACKET_CASHMANIA_CSCASHMANIAOP", + 5652: "PACKET_CASHMANIA_SCCASHMANIAOP", + 5653: "PACKET_CASHMANIA_SCCASHMANIAROOMSTATE", + 5654: "PACKET_CASHMANIA_SCCASHMANIABILLED", + } + CashManiaPID_value = map[string]int32{ + "PACKET_CASHMANIA_ZERO": 0, + "PACKET_CASHMANIA_SCCASHMANIAROOMINFO": 5650, + "PACKET_CASHMANIA_CSCASHMANIAOP": 5651, + "PACKET_CASHMANIA_SCCASHMANIAOP": 5652, + "PACKET_CASHMANIA_SCCASHMANIAROOMSTATE": 5653, + "PACKET_CASHMANIA_SCCASHMANIABILLED": 5654, + } +) + +func (x CashManiaPID) Enum() *CashManiaPID { + p := new(CashManiaPID) + *p = x + return p +} + +func (x CashManiaPID) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (CashManiaPID) Descriptor() protoreflect.EnumDescriptor { + return file_protocol_cashmania_cashmania_proto_enumTypes[0].Descriptor() +} + +func (CashManiaPID) Type() protoreflect.EnumType { + return &file_protocol_cashmania_cashmania_proto_enumTypes[0] +} + +func (x CashManiaPID) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use CashManiaPID.Descriptor instead. +func (CashManiaPID) EnumDescriptor() ([]byte, []int) { + return file_protocol_cashmania_cashmania_proto_rawDescGZIP(), []int{0} +} + +type CashManiaPlayerData struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Name string `protobuf:"bytes,1,opt,name=Name,proto3" json:"Name,omitempty"` //名字 + SnId int32 `protobuf:"varint,2,opt,name=SnId,proto3" json:"SnId,omitempty"` //账号 + Head int32 `protobuf:"varint,3,opt,name=Head,proto3" json:"Head,omitempty"` //头像 + Sex int32 `protobuf:"varint,4,opt,name=Sex,proto3" json:"Sex,omitempty"` //性别 + Coin int64 `protobuf:"varint,5,opt,name=Coin,proto3" json:"Coin,omitempty"` //金币 + Pos int32 `protobuf:"varint,6,opt,name=Pos,proto3" json:"Pos,omitempty"` //座位位置 + Flag int32 `protobuf:"varint,7,opt,name=Flag,proto3" json:"Flag,omitempty"` //二进制标记 + Params []string `protobuf:"bytes,8,rep,name=Params,proto3" json:"Params,omitempty"` //其他数据 如:ip 等 + City string `protobuf:"bytes,9,opt,name=City,proto3" json:"City,omitempty"` //城市 + HeadOutLine int32 `protobuf:"varint,10,opt,name=HeadOutLine,proto3" json:"HeadOutLine,omitempty"` //头像框 + VIP int32 `protobuf:"varint,11,opt,name=VIP,proto3" json:"VIP,omitempty"` +} + +func (x *CashManiaPlayerData) Reset() { + *x = CashManiaPlayerData{} + if protoimpl.UnsafeEnabled { + mi := &file_protocol_cashmania_cashmania_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CashManiaPlayerData) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CashManiaPlayerData) ProtoMessage() {} + +func (x *CashManiaPlayerData) ProtoReflect() protoreflect.Message { + mi := &file_protocol_cashmania_cashmania_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CashManiaPlayerData.ProtoReflect.Descriptor instead. +func (*CashManiaPlayerData) Descriptor() ([]byte, []int) { + return file_protocol_cashmania_cashmania_proto_rawDescGZIP(), []int{0} +} + +func (x *CashManiaPlayerData) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *CashManiaPlayerData) GetSnId() int32 { + if x != nil { + return x.SnId + } + return 0 +} + +func (x *CashManiaPlayerData) GetHead() int32 { + if x != nil { + return x.Head + } + return 0 +} + +func (x *CashManiaPlayerData) GetSex() int32 { + if x != nil { + return x.Sex + } + return 0 +} + +func (x *CashManiaPlayerData) GetCoin() int64 { + if x != nil { + return x.Coin + } + return 0 +} + +func (x *CashManiaPlayerData) GetPos() int32 { + if x != nil { + return x.Pos + } + return 0 +} + +func (x *CashManiaPlayerData) GetFlag() int32 { + if x != nil { + return x.Flag + } + return 0 +} + +func (x *CashManiaPlayerData) GetParams() []string { + if x != nil { + return x.Params + } + return nil +} + +func (x *CashManiaPlayerData) GetCity() string { + if x != nil { + return x.City + } + return "" +} + +func (x *CashManiaPlayerData) GetHeadOutLine() int32 { + if x != nil { + return x.HeadOutLine + } + return 0 +} + +func (x *CashManiaPlayerData) GetVIP() int32 { + if x != nil { + return x.VIP + } + return 0 +} + +//房间信息 +//PACKET_FORTUNEMOUSE_SCFORTUNEMOUSEROOMINFO +type SCCashManiaRoomInfo struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + RoomId int32 `protobuf:"varint,1,opt,name=RoomId,proto3" json:"RoomId,omitempty"` //房间id + GameFreeId int32 `protobuf:"varint,2,opt,name=GameFreeId,proto3" json:"GameFreeId,omitempty"` + GameId int32 `protobuf:"varint,3,opt,name=GameId,proto3" json:"GameId,omitempty"` //游戏id + RoomMode int32 `protobuf:"varint,4,opt,name=RoomMode,proto3" json:"RoomMode,omitempty"` //游戏模式 + Params []int32 `protobuf:"varint,5,rep,packed,name=Params,proto3" json:"Params,omitempty"` //规则参数 + NumOfGames int32 `protobuf:"varint,6,opt,name=NumOfGames,proto3" json:"NumOfGames,omitempty"` //当前第几局 + State int32 `protobuf:"varint,7,opt,name=State,proto3" json:"State,omitempty"` //房间当前状态 + ParamsEx []int64 `protobuf:"varint,8,rep,packed,name=ParamsEx,proto3" json:"ParamsEx,omitempty"` //其他参数 + SceneType int32 `protobuf:"varint,9,opt,name=SceneType,proto3" json:"SceneType,omitempty"` //房间模式 + Player *CashManiaPlayerData `protobuf:"bytes,10,opt,name=Player,proto3" json:"Player,omitempty"` //房间内的玩家信息 + PlayerInfo string `protobuf:"bytes,11,opt,name=PlayerInfo,proto3" json:"PlayerInfo,omitempty"` +} + +func (x *SCCashManiaRoomInfo) Reset() { + *x = SCCashManiaRoomInfo{} + if protoimpl.UnsafeEnabled { + mi := &file_protocol_cashmania_cashmania_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SCCashManiaRoomInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SCCashManiaRoomInfo) ProtoMessage() {} + +func (x *SCCashManiaRoomInfo) ProtoReflect() protoreflect.Message { + mi := &file_protocol_cashmania_cashmania_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SCCashManiaRoomInfo.ProtoReflect.Descriptor instead. +func (*SCCashManiaRoomInfo) Descriptor() ([]byte, []int) { + return file_protocol_cashmania_cashmania_proto_rawDescGZIP(), []int{1} +} + +func (x *SCCashManiaRoomInfo) GetRoomId() int32 { + if x != nil { + return x.RoomId + } + return 0 +} + +func (x *SCCashManiaRoomInfo) GetGameFreeId() int32 { + if x != nil { + return x.GameFreeId + } + return 0 +} + +func (x *SCCashManiaRoomInfo) GetGameId() int32 { + if x != nil { + return x.GameId + } + return 0 +} + +func (x *SCCashManiaRoomInfo) GetRoomMode() int32 { + if x != nil { + return x.RoomMode + } + return 0 +} + +func (x *SCCashManiaRoomInfo) GetParams() []int32 { + if x != nil { + return x.Params + } + return nil +} + +func (x *SCCashManiaRoomInfo) GetNumOfGames() int32 { + if x != nil { + return x.NumOfGames + } + return 0 +} + +func (x *SCCashManiaRoomInfo) GetState() int32 { + if x != nil { + return x.State + } + return 0 +} + +func (x *SCCashManiaRoomInfo) GetParamsEx() []int64 { + if x != nil { + return x.ParamsEx + } + return nil +} + +func (x *SCCashManiaRoomInfo) GetSceneType() int32 { + if x != nil { + return x.SceneType + } + return 0 +} + +func (x *SCCashManiaRoomInfo) GetPlayer() *CashManiaPlayerData { + if x != nil { + return x.Player + } + return nil +} + +func (x *SCCashManiaRoomInfo) GetPlayerInfo() string { + if x != nil { + return x.PlayerInfo + } + return "" +} + +//玩家操作 +//PACKET_FORTUNEMOUSE_CSFORTUNEMOUSEOP +type CSCashManiaOp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + OpCode int32 `protobuf:"varint,1,opt,name=OpCode,proto3" json:"OpCode,omitempty"` //操作码 0.spin + Params []int64 `protobuf:"varint,2,rep,packed,name=Params,proto3" json:"Params,omitempty"` //操作参数 下注索引编号 +} + +func (x *CSCashManiaOp) Reset() { + *x = CSCashManiaOp{} + if protoimpl.UnsafeEnabled { + mi := &file_protocol_cashmania_cashmania_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CSCashManiaOp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CSCashManiaOp) ProtoMessage() {} + +func (x *CSCashManiaOp) ProtoReflect() protoreflect.Message { + mi := &file_protocol_cashmania_cashmania_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CSCashManiaOp.ProtoReflect.Descriptor instead. +func (*CSCashManiaOp) Descriptor() ([]byte, []int) { + return file_protocol_cashmania_cashmania_proto_rawDescGZIP(), []int{2} +} + +func (x *CSCashManiaOp) GetOpCode() int32 { + if x != nil { + return x.OpCode + } + return 0 +} + +func (x *CSCashManiaOp) GetParams() []int64 { + if x != nil { + return x.Params + } + return nil +} + +//玩家操作返回 +//PACKET_FORTUNEMOUSE_SCFORTUNEMOUSEOP +type SCCashManiaOp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + OpCode int32 `protobuf:"varint,1,opt,name=OpCode,proto3" json:"OpCode,omitempty"` //操作码 + OpRetCode int32 `protobuf:"varint,2,opt,name=OpRetCode,proto3" json:"OpRetCode,omitempty"` //操作结果 1.金币不足 2.低于该值不能押注 + Params []int64 `protobuf:"varint,3,rep,packed,name=Params,proto3" json:"Params,omitempty"` //操作参数 +} + +func (x *SCCashManiaOp) Reset() { + *x = SCCashManiaOp{} + if protoimpl.UnsafeEnabled { + mi := &file_protocol_cashmania_cashmania_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SCCashManiaOp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SCCashManiaOp) ProtoMessage() {} + +func (x *SCCashManiaOp) ProtoReflect() protoreflect.Message { + mi := &file_protocol_cashmania_cashmania_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SCCashManiaOp.ProtoReflect.Descriptor instead. +func (*SCCashManiaOp) Descriptor() ([]byte, []int) { + return file_protocol_cashmania_cashmania_proto_rawDescGZIP(), []int{3} +} + +func (x *SCCashManiaOp) GetOpCode() int32 { + if x != nil { + return x.OpCode + } + return 0 +} + +func (x *SCCashManiaOp) GetOpRetCode() int32 { + if x != nil { + return x.OpRetCode + } + return 0 +} + +func (x *SCCashManiaOp) GetParams() []int64 { + if x != nil { + return x.Params + } + return nil +} + +//房间状态 +//PACKET_FORTUNEMOUSE_SCFORTUNEMOUSEROOMSTATE +type SCCashManiaRoomState struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + State int32 `protobuf:"varint,1,opt,name=State,proto3" json:"State,omitempty"` //房间当前状态 + SubState int32 `protobuf:"varint,2,opt,name=SubState,proto3" json:"SubState,omitempty"` //房间当前子状态 + Params []int32 `protobuf:"varint,3,rep,packed,name=Params,proto3" json:"Params,omitempty"` //状态参数 +} + +func (x *SCCashManiaRoomState) Reset() { + *x = SCCashManiaRoomState{} + if protoimpl.UnsafeEnabled { + mi := &file_protocol_cashmania_cashmania_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SCCashManiaRoomState) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SCCashManiaRoomState) ProtoMessage() {} + +func (x *SCCashManiaRoomState) ProtoReflect() protoreflect.Message { + mi := &file_protocol_cashmania_cashmania_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SCCashManiaRoomState.ProtoReflect.Descriptor instead. +func (*SCCashManiaRoomState) Descriptor() ([]byte, []int) { + return file_protocol_cashmania_cashmania_proto_rawDescGZIP(), []int{4} +} + +func (x *SCCashManiaRoomState) GetState() int32 { + if x != nil { + return x.State + } + return 0 +} + +func (x *SCCashManiaRoomState) GetSubState() int32 { + if x != nil { + return x.SubState + } + return 0 +} + +func (x *SCCashManiaRoomState) GetParams() []int32 { + if x != nil { + return x.Params + } + return nil +} + +//PACKET_FORTUNEMOUSE_SCFORTUNEMOUSEBILLED +type SCCashManiaBilled struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + OpRetCode int32 `protobuf:"varint,1,opt,name=OpRetCode,proto3" json:"OpRetCode,omitempty"` //0.spin成功 1.spin失败 + GameEndStr string `protobuf:"bytes,2,opt,name=GameEndStr,proto3" json:"GameEndStr,omitempty"` +} + +func (x *SCCashManiaBilled) Reset() { + *x = SCCashManiaBilled{} + if protoimpl.UnsafeEnabled { + mi := &file_protocol_cashmania_cashmania_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SCCashManiaBilled) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SCCashManiaBilled) ProtoMessage() {} + +func (x *SCCashManiaBilled) ProtoReflect() protoreflect.Message { + mi := &file_protocol_cashmania_cashmania_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SCCashManiaBilled.ProtoReflect.Descriptor instead. +func (*SCCashManiaBilled) Descriptor() ([]byte, []int) { + return file_protocol_cashmania_cashmania_proto_rawDescGZIP(), []int{5} +} + +func (x *SCCashManiaBilled) GetOpRetCode() int32 { + if x != nil { + return x.OpRetCode + } + return 0 +} + +func (x *SCCashManiaBilled) GetGameEndStr() string { + if x != nil { + return x.GameEndStr + } + return "" +} + +var File_protocol_cashmania_cashmania_proto protoreflect.FileDescriptor + +var file_protocol_cashmania_cashmania_proto_rawDesc = []byte{ + 0x0a, 0x22, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x63, 0x61, 0x73, 0x68, 0x6d, + 0x61, 0x6e, 0x69, 0x61, 0x2f, 0x63, 0x61, 0x73, 0x68, 0x6d, 0x61, 0x6e, 0x69, 0x61, 0x2e, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x09, 0x63, 0x61, 0x73, 0x68, 0x6d, 0x61, 0x6e, 0x69, 0x61, 0x22, + 0xfd, 0x01, 0x0a, 0x13, 0x43, 0x61, 0x73, 0x68, 0x4d, 0x61, 0x6e, 0x69, 0x61, 0x50, 0x6c, 0x61, + 0x79, 0x65, 0x72, 0x44, 0x61, 0x74, 0x61, 0x12, 0x12, 0x0a, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x53, + 0x6e, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x53, 0x6e, 0x49, 0x64, 0x12, + 0x12, 0x0a, 0x04, 0x48, 0x65, 0x61, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x48, + 0x65, 0x61, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x53, 0x65, 0x78, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, + 0x52, 0x03, 0x53, 0x65, 0x78, 0x12, 0x12, 0x0a, 0x04, 0x43, 0x6f, 0x69, 0x6e, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x03, 0x52, 0x04, 0x43, 0x6f, 0x69, 0x6e, 0x12, 0x10, 0x0a, 0x03, 0x50, 0x6f, 0x73, + 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x50, 0x6f, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x46, + 0x6c, 0x61, 0x67, 0x18, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x46, 0x6c, 0x61, 0x67, 0x12, + 0x16, 0x0a, 0x06, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x09, 0x52, + 0x06, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x43, 0x69, 0x74, 0x79, 0x18, + 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x43, 0x69, 0x74, 0x79, 0x12, 0x20, 0x0a, 0x0b, 0x48, + 0x65, 0x61, 0x64, 0x4f, 0x75, 0x74, 0x4c, 0x69, 0x6e, 0x65, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x05, + 0x52, 0x0b, 0x48, 0x65, 0x61, 0x64, 0x4f, 0x75, 0x74, 0x4c, 0x69, 0x6e, 0x65, 0x12, 0x10, 0x0a, + 0x03, 0x56, 0x49, 0x50, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x56, 0x49, 0x50, 0x22, + 0xe1, 0x02, 0x0a, 0x13, 0x53, 0x43, 0x43, 0x61, 0x73, 0x68, 0x4d, 0x61, 0x6e, 0x69, 0x61, 0x52, + 0x6f, 0x6f, 0x6d, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x16, 0x0a, 0x06, 0x52, 0x6f, 0x6f, 0x6d, 0x49, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x52, 0x6f, 0x6f, 0x6d, 0x49, 0x64, 0x12, + 0x1e, 0x0a, 0x0a, 0x47, 0x61, 0x6d, 0x65, 0x46, 0x72, 0x65, 0x65, 0x49, 0x64, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x05, 0x52, 0x0a, 0x47, 0x61, 0x6d, 0x65, 0x46, 0x72, 0x65, 0x65, 0x49, 0x64, 0x12, + 0x16, 0x0a, 0x06, 0x47, 0x61, 0x6d, 0x65, 0x49, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, + 0x06, 0x47, 0x61, 0x6d, 0x65, 0x49, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x52, 0x6f, 0x6f, 0x6d, 0x4d, + 0x6f, 0x64, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x52, 0x6f, 0x6f, 0x6d, 0x4d, + 0x6f, 0x64, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x18, 0x05, 0x20, + 0x03, 0x28, 0x05, 0x52, 0x06, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x4e, + 0x75, 0x6d, 0x4f, 0x66, 0x47, 0x61, 0x6d, 0x65, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, + 0x0a, 0x4e, 0x75, 0x6d, 0x4f, 0x66, 0x47, 0x61, 0x6d, 0x65, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x53, + 0x74, 0x61, 0x74, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x53, 0x74, 0x61, 0x74, + 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x45, 0x78, 0x18, 0x08, 0x20, + 0x03, 0x28, 0x03, 0x52, 0x08, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x45, 0x78, 0x12, 0x1c, 0x0a, + 0x09, 0x53, 0x63, 0x65, 0x6e, 0x65, 0x54, 0x79, 0x70, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x05, + 0x52, 0x09, 0x53, 0x63, 0x65, 0x6e, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x36, 0x0a, 0x06, 0x50, + 0x6c, 0x61, 0x79, 0x65, 0x72, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x63, 0x61, + 0x73, 0x68, 0x6d, 0x61, 0x6e, 0x69, 0x61, 0x2e, 0x43, 0x61, 0x73, 0x68, 0x4d, 0x61, 0x6e, 0x69, + 0x61, 0x50, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x44, 0x61, 0x74, 0x61, 0x52, 0x06, 0x50, 0x6c, 0x61, + 0x79, 0x65, 0x72, 0x12, 0x1e, 0x0a, 0x0a, 0x50, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x49, 0x6e, 0x66, + 0x6f, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x50, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x49, + 0x6e, 0x66, 0x6f, 0x22, 0x3f, 0x0a, 0x0d, 0x43, 0x53, 0x43, 0x61, 0x73, 0x68, 0x4d, 0x61, 0x6e, + 0x69, 0x61, 0x4f, 0x70, 0x12, 0x16, 0x0a, 0x06, 0x4f, 0x70, 0x43, 0x6f, 0x64, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x4f, 0x70, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x16, 0x0a, 0x06, + 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x03, 0x52, 0x06, 0x50, 0x61, + 0x72, 0x61, 0x6d, 0x73, 0x22, 0x5d, 0x0a, 0x0d, 0x53, 0x43, 0x43, 0x61, 0x73, 0x68, 0x4d, 0x61, + 0x6e, 0x69, 0x61, 0x4f, 0x70, 0x12, 0x16, 0x0a, 0x06, 0x4f, 0x70, 0x43, 0x6f, 0x64, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x4f, 0x70, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x1c, 0x0a, + 0x09, 0x4f, 0x70, 0x52, 0x65, 0x74, 0x43, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, + 0x52, 0x09, 0x4f, 0x70, 0x52, 0x65, 0x74, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x50, + 0x61, 0x72, 0x61, 0x6d, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x03, 0x52, 0x06, 0x50, 0x61, 0x72, + 0x61, 0x6d, 0x73, 0x22, 0x60, 0x0a, 0x14, 0x53, 0x43, 0x43, 0x61, 0x73, 0x68, 0x4d, 0x61, 0x6e, + 0x69, 0x61, 0x52, 0x6f, 0x6f, 0x6d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x53, + 0x74, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x53, 0x74, 0x61, 0x74, + 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x53, 0x75, 0x62, 0x53, 0x74, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x05, 0x52, 0x08, 0x53, 0x75, 0x62, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x16, 0x0a, + 0x06, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x05, 0x52, 0x06, 0x50, + 0x61, 0x72, 0x61, 0x6d, 0x73, 0x22, 0x51, 0x0a, 0x11, 0x53, 0x43, 0x43, 0x61, 0x73, 0x68, 0x4d, + 0x61, 0x6e, 0x69, 0x61, 0x42, 0x69, 0x6c, 0x6c, 0x65, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x4f, 0x70, + 0x52, 0x65, 0x74, 0x43, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x4f, + 0x70, 0x52, 0x65, 0x74, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x47, 0x61, 0x6d, 0x65, + 0x45, 0x6e, 0x64, 0x53, 0x74, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x47, 0x61, + 0x6d, 0x65, 0x45, 0x6e, 0x64, 0x53, 0x74, 0x72, 0x2a, 0xf3, 0x01, 0x0a, 0x0c, 0x43, 0x61, 0x73, + 0x68, 0x4d, 0x61, 0x6e, 0x69, 0x61, 0x50, 0x49, 0x44, 0x12, 0x19, 0x0a, 0x15, 0x50, 0x41, 0x43, + 0x4b, 0x45, 0x54, 0x5f, 0x43, 0x41, 0x53, 0x48, 0x4d, 0x41, 0x4e, 0x49, 0x41, 0x5f, 0x5a, 0x45, + 0x52, 0x4f, 0x10, 0x00, 0x12, 0x29, 0x0a, 0x24, 0x50, 0x41, 0x43, 0x4b, 0x45, 0x54, 0x5f, 0x43, + 0x41, 0x53, 0x48, 0x4d, 0x41, 0x4e, 0x49, 0x41, 0x5f, 0x53, 0x43, 0x43, 0x41, 0x53, 0x48, 0x4d, + 0x41, 0x4e, 0x49, 0x41, 0x52, 0x4f, 0x4f, 0x4d, 0x49, 0x4e, 0x46, 0x4f, 0x10, 0x92, 0x2c, 0x12, + 0x23, 0x0a, 0x1e, 0x50, 0x41, 0x43, 0x4b, 0x45, 0x54, 0x5f, 0x43, 0x41, 0x53, 0x48, 0x4d, 0x41, + 0x4e, 0x49, 0x41, 0x5f, 0x43, 0x53, 0x43, 0x41, 0x53, 0x48, 0x4d, 0x41, 0x4e, 0x49, 0x41, 0x4f, + 0x50, 0x10, 0x93, 0x2c, 0x12, 0x23, 0x0a, 0x1e, 0x50, 0x41, 0x43, 0x4b, 0x45, 0x54, 0x5f, 0x43, + 0x41, 0x53, 0x48, 0x4d, 0x41, 0x4e, 0x49, 0x41, 0x5f, 0x53, 0x43, 0x43, 0x41, 0x53, 0x48, 0x4d, + 0x41, 0x4e, 0x49, 0x41, 0x4f, 0x50, 0x10, 0x94, 0x2c, 0x12, 0x2a, 0x0a, 0x25, 0x50, 0x41, 0x43, + 0x4b, 0x45, 0x54, 0x5f, 0x43, 0x41, 0x53, 0x48, 0x4d, 0x41, 0x4e, 0x49, 0x41, 0x5f, 0x53, 0x43, + 0x43, 0x41, 0x53, 0x48, 0x4d, 0x41, 0x4e, 0x49, 0x41, 0x52, 0x4f, 0x4f, 0x4d, 0x53, 0x54, 0x41, + 0x54, 0x45, 0x10, 0x95, 0x2c, 0x12, 0x27, 0x0a, 0x22, 0x50, 0x41, 0x43, 0x4b, 0x45, 0x54, 0x5f, + 0x43, 0x41, 0x53, 0x48, 0x4d, 0x41, 0x4e, 0x49, 0x41, 0x5f, 0x53, 0x43, 0x43, 0x41, 0x53, 0x48, + 0x4d, 0x41, 0x4e, 0x49, 0x41, 0x42, 0x49, 0x4c, 0x4c, 0x45, 0x44, 0x10, 0x96, 0x2c, 0x42, 0x29, + 0x5a, 0x27, 0x6d, 0x6f, 0x6e, 0x67, 0x6f, 0x2e, 0x67, 0x61, 0x6d, 0x65, 0x73, 0x2e, 0x63, 0x6f, + 0x6d, 0x2f, 0x67, 0x61, 0x6d, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, + 0x63, 0x61, 0x73, 0x68, 0x6d, 0x61, 0x6e, 0x69, 0x61, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x33, +} + +var ( + file_protocol_cashmania_cashmania_proto_rawDescOnce sync.Once + file_protocol_cashmania_cashmania_proto_rawDescData = file_protocol_cashmania_cashmania_proto_rawDesc +) + +func file_protocol_cashmania_cashmania_proto_rawDescGZIP() []byte { + file_protocol_cashmania_cashmania_proto_rawDescOnce.Do(func() { + file_protocol_cashmania_cashmania_proto_rawDescData = protoimpl.X.CompressGZIP(file_protocol_cashmania_cashmania_proto_rawDescData) + }) + return file_protocol_cashmania_cashmania_proto_rawDescData +} + +var file_protocol_cashmania_cashmania_proto_enumTypes = make([]protoimpl.EnumInfo, 1) +var file_protocol_cashmania_cashmania_proto_msgTypes = make([]protoimpl.MessageInfo, 6) +var file_protocol_cashmania_cashmania_proto_goTypes = []interface{}{ + (CashManiaPID)(0), // 0: cashmania.CashManiaPID + (*CashManiaPlayerData)(nil), // 1: cashmania.CashManiaPlayerData + (*SCCashManiaRoomInfo)(nil), // 2: cashmania.SCCashManiaRoomInfo + (*CSCashManiaOp)(nil), // 3: cashmania.CSCashManiaOp + (*SCCashManiaOp)(nil), // 4: cashmania.SCCashManiaOp + (*SCCashManiaRoomState)(nil), // 5: cashmania.SCCashManiaRoomState + (*SCCashManiaBilled)(nil), // 6: cashmania.SCCashManiaBilled +} +var file_protocol_cashmania_cashmania_proto_depIdxs = []int32{ + 1, // 0: cashmania.SCCashManiaRoomInfo.Player:type_name -> cashmania.CashManiaPlayerData + 1, // [1:1] is the sub-list for method output_type + 1, // [1:1] is the sub-list for method input_type + 1, // [1:1] is the sub-list for extension type_name + 1, // [1:1] is the sub-list for extension extendee + 0, // [0:1] is the sub-list for field type_name +} + +func init() { file_protocol_cashmania_cashmania_proto_init() } +func file_protocol_cashmania_cashmania_proto_init() { + if File_protocol_cashmania_cashmania_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_protocol_cashmania_cashmania_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CashManiaPlayerData); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_protocol_cashmania_cashmania_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SCCashManiaRoomInfo); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_protocol_cashmania_cashmania_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CSCashManiaOp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_protocol_cashmania_cashmania_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SCCashManiaOp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_protocol_cashmania_cashmania_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SCCashManiaRoomState); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_protocol_cashmania_cashmania_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SCCashManiaBilled); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_protocol_cashmania_cashmania_proto_rawDesc, + NumEnums: 1, + NumMessages: 6, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_protocol_cashmania_cashmania_proto_goTypes, + DependencyIndexes: file_protocol_cashmania_cashmania_proto_depIdxs, + EnumInfos: file_protocol_cashmania_cashmania_proto_enumTypes, + MessageInfos: file_protocol_cashmania_cashmania_proto_msgTypes, + }.Build() + File_protocol_cashmania_cashmania_proto = out.File + file_protocol_cashmania_cashmania_proto_rawDesc = nil + file_protocol_cashmania_cashmania_proto_goTypes = nil + file_protocol_cashmania_cashmania_proto_depIdxs = nil +} diff --git a/protocol/cashmania/cashmania.proto b/protocol/cashmania/cashmania.proto new file mode 100644 index 0000000..fe0d37e --- /dev/null +++ b/protocol/cashmania/cashmania.proto @@ -0,0 +1,68 @@ +syntax = "proto3"; +package cashmania; +option go_package = "mongo.games.com/game/protocol/cashmania"; + +//cashmania +//龙 +enum CashManiaPID { + PACKET_CASHMANIA_ZERO = 0;// 弃用消息号 + PACKET_CASHMANIA_SCCASHMANIAROOMINFO = 5650; //房间信息 + PACKET_CASHMANIA_CSCASHMANIAOP = 5651; + PACKET_CASHMANIA_SCCASHMANIAOP = 5652; + PACKET_CASHMANIA_SCCASHMANIAROOMSTATE = 5653; + PACKET_CASHMANIA_SCCASHMANIABILLED = 5654; +} + +message CashManiaPlayerData { + string Name = 1; //名字 + int32 SnId = 2; //账号 + int32 Head = 3; //头像 + int32 Sex = 4; //性别 + int64 Coin = 5; //金币 + int32 Pos = 6; //座位位置 + int32 Flag = 7; //二进制标记 + repeated string Params = 8; //其他数据 如:ip 等 + string City = 9; //城市 + int32 HeadOutLine = 10; //头像框 + int32 VIP = 11; +} +//房间信息 +//PACKET_FORTUNEMOUSE_SCFORTUNEMOUSEROOMINFO +message SCCashManiaRoomInfo { + int32 RoomId = 1; //房间id + int32 GameFreeId = 2; + int32 GameId = 3; //游戏id + int32 RoomMode = 4; //游戏模式 + repeated int32 Params = 5; //规则参数 + int32 NumOfGames = 6; //当前第几局 + int32 State = 7; //房间当前状态 + repeated int64 ParamsEx = 8; //其他参数 + int32 SceneType = 9; //房间模式 + CashManiaPlayerData Player = 10; //房间内的玩家信息 + string PlayerInfo = 11; +} +//玩家操作 +//PACKET_FORTUNEMOUSE_CSFORTUNEMOUSEOP +message CSCashManiaOp { + int32 OpCode = 1; //操作码 0.spin + repeated int64 Params = 2; //操作参数 下注索引编号 +} +//玩家操作返回 +//PACKET_FORTUNEMOUSE_SCFORTUNEMOUSEOP +message SCCashManiaOp { + int32 OpCode = 1; //操作码 + int32 OpRetCode = 2; //操作结果 1.金币不足 2.低于该值不能押注 + repeated int64 Params = 3; //操作参数 +} +//房间状态 +//PACKET_FORTUNEMOUSE_SCFORTUNEMOUSEROOMSTATE +message SCCashManiaRoomState { + int32 State = 1; //房间当前状态 + int32 SubState = 2; //房间当前子状态 + repeated int32 Params = 3; //状态参数 +} +//PACKET_FORTUNEMOUSE_SCFORTUNEMOUSEBILLED +message SCCashManiaBilled{ + int32 OpRetCode = 1;//0.spin成功 1.spin失败 + string GameEndStr = 2; +} \ No newline at end of file diff --git a/protocol/doc.md b/protocol/doc.md index 2dd90d6..e8d8f01 100644 --- a/protocol/doc.md +++ b/protocol/doc.md @@ -159,31 +159,39 @@ ### samloc.proto - 5550~5569 -### thirteen.protp +### thirteen.proto - 5570~5580 -### smallrocket.protp +### smallrocket.proto - 5581~5599 -### fortunedragon.prot +### fortunedragon.proto - 5600~5609 -### fortunerabbit.prot +### fortunerabbit.proto - 5610~5619 -### fortuneox.prot +### fortuneox.proto - 5620~5629 -### fortunetiger.prot +### fortunetiger.proto - 5630~5639 -### fortunemouse.prot +### fortunemouse.proto - 5640~5649 +### cashmania.proto + +- 5650~5659 + +### gatesofolympus.proto + +- 5660~5669 + ### game.proto(玩家离开) - 8000~8099 \ No newline at end of file diff --git a/protocol/gatesofolympus/gatesofolympus.pb.go b/protocol/gatesofolympus/gatesofolympus.pb.go new file mode 100644 index 0000000..2d4df78 --- /dev/null +++ b/protocol/gatesofolympus/gatesofolympus.pb.go @@ -0,0 +1,806 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.27.1-devel +// protoc v3.19.4 +// source: protocol/gatesofolympus/gatesofolympus.proto + +package gatesofolympus + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +//gatesofolympus +//龙 +type GatesOfOlympusPID int32 + +const ( + GatesOfOlympusPID_PACKET_GATESOFOLYMPUS_ZERO GatesOfOlympusPID = 0 // 弃用消息号 + GatesOfOlympusPID_PACKET_GATESOFOLYMPUS_SCGATESOFOLYMPUSROOMINFO GatesOfOlympusPID = 5660 //房间信息 + GatesOfOlympusPID_PACKET_GATESOFOLYMPUS_CSGATESOFOLYMPUSOP GatesOfOlympusPID = 5661 + GatesOfOlympusPID_PACKET_GATESOFOLYMPUS_SCGATESOFOLYMPUSOP GatesOfOlympusPID = 5662 + GatesOfOlympusPID_PACKET_GATESOFOLYMPUS_SCGATESOFOLYMPUSROOMSTATE GatesOfOlympusPID = 5663 + GatesOfOlympusPID_PACKET_GATESOFOLYMPUS_SCGATESOFOLYMPUSBILLED GatesOfOlympusPID = 5664 +) + +// Enum value maps for GatesOfOlympusPID. +var ( + GatesOfOlympusPID_name = map[int32]string{ + 0: "PACKET_GATESOFOLYMPUS_ZERO", + 5660: "PACKET_GATESOFOLYMPUS_SCGATESOFOLYMPUSROOMINFO", + 5661: "PACKET_GATESOFOLYMPUS_CSGATESOFOLYMPUSOP", + 5662: "PACKET_GATESOFOLYMPUS_SCGATESOFOLYMPUSOP", + 5663: "PACKET_GATESOFOLYMPUS_SCGATESOFOLYMPUSROOMSTATE", + 5664: "PACKET_GATESOFOLYMPUS_SCGATESOFOLYMPUSBILLED", + } + GatesOfOlympusPID_value = map[string]int32{ + "PACKET_GATESOFOLYMPUS_ZERO": 0, + "PACKET_GATESOFOLYMPUS_SCGATESOFOLYMPUSROOMINFO": 5660, + "PACKET_GATESOFOLYMPUS_CSGATESOFOLYMPUSOP": 5661, + "PACKET_GATESOFOLYMPUS_SCGATESOFOLYMPUSOP": 5662, + "PACKET_GATESOFOLYMPUS_SCGATESOFOLYMPUSROOMSTATE": 5663, + "PACKET_GATESOFOLYMPUS_SCGATESOFOLYMPUSBILLED": 5664, + } +) + +func (x GatesOfOlympusPID) Enum() *GatesOfOlympusPID { + p := new(GatesOfOlympusPID) + *p = x + return p +} + +func (x GatesOfOlympusPID) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (GatesOfOlympusPID) Descriptor() protoreflect.EnumDescriptor { + return file_protocol_gatesofolympus_gatesofolympus_proto_enumTypes[0].Descriptor() +} + +func (GatesOfOlympusPID) Type() protoreflect.EnumType { + return &file_protocol_gatesofolympus_gatesofolympus_proto_enumTypes[0] +} + +func (x GatesOfOlympusPID) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use GatesOfOlympusPID.Descriptor instead. +func (GatesOfOlympusPID) EnumDescriptor() ([]byte, []int) { + return file_protocol_gatesofolympus_gatesofolympus_proto_rawDescGZIP(), []int{0} +} + +type GatesOfOlympusPlayerData struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Name string `protobuf:"bytes,1,opt,name=Name,proto3" json:"Name,omitempty"` //名字 + SnId int32 `protobuf:"varint,2,opt,name=SnId,proto3" json:"SnId,omitempty"` //账号 + Head int32 `protobuf:"varint,3,opt,name=Head,proto3" json:"Head,omitempty"` //头像 + Sex int32 `protobuf:"varint,4,opt,name=Sex,proto3" json:"Sex,omitempty"` //性别 + Coin int64 `protobuf:"varint,5,opt,name=Coin,proto3" json:"Coin,omitempty"` //金币 + Pos int32 `protobuf:"varint,6,opt,name=Pos,proto3" json:"Pos,omitempty"` //座位位置 + Flag int32 `protobuf:"varint,7,opt,name=Flag,proto3" json:"Flag,omitempty"` //二进制标记 + Params []string `protobuf:"bytes,8,rep,name=Params,proto3" json:"Params,omitempty"` //其他数据 如:ip 等 + City string `protobuf:"bytes,9,opt,name=City,proto3" json:"City,omitempty"` //城市 + HeadOutLine int32 `protobuf:"varint,10,opt,name=HeadOutLine,proto3" json:"HeadOutLine,omitempty"` //头像框 + VIP int32 `protobuf:"varint,11,opt,name=VIP,proto3" json:"VIP,omitempty"` +} + +func (x *GatesOfOlympusPlayerData) Reset() { + *x = GatesOfOlympusPlayerData{} + if protoimpl.UnsafeEnabled { + mi := &file_protocol_gatesofolympus_gatesofolympus_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GatesOfOlympusPlayerData) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GatesOfOlympusPlayerData) ProtoMessage() {} + +func (x *GatesOfOlympusPlayerData) ProtoReflect() protoreflect.Message { + mi := &file_protocol_gatesofolympus_gatesofolympus_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GatesOfOlympusPlayerData.ProtoReflect.Descriptor instead. +func (*GatesOfOlympusPlayerData) Descriptor() ([]byte, []int) { + return file_protocol_gatesofolympus_gatesofolympus_proto_rawDescGZIP(), []int{0} +} + +func (x *GatesOfOlympusPlayerData) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *GatesOfOlympusPlayerData) GetSnId() int32 { + if x != nil { + return x.SnId + } + return 0 +} + +func (x *GatesOfOlympusPlayerData) GetHead() int32 { + if x != nil { + return x.Head + } + return 0 +} + +func (x *GatesOfOlympusPlayerData) GetSex() int32 { + if x != nil { + return x.Sex + } + return 0 +} + +func (x *GatesOfOlympusPlayerData) GetCoin() int64 { + if x != nil { + return x.Coin + } + return 0 +} + +func (x *GatesOfOlympusPlayerData) GetPos() int32 { + if x != nil { + return x.Pos + } + return 0 +} + +func (x *GatesOfOlympusPlayerData) GetFlag() int32 { + if x != nil { + return x.Flag + } + return 0 +} + +func (x *GatesOfOlympusPlayerData) GetParams() []string { + if x != nil { + return x.Params + } + return nil +} + +func (x *GatesOfOlympusPlayerData) GetCity() string { + if x != nil { + return x.City + } + return "" +} + +func (x *GatesOfOlympusPlayerData) GetHeadOutLine() int32 { + if x != nil { + return x.HeadOutLine + } + return 0 +} + +func (x *GatesOfOlympusPlayerData) GetVIP() int32 { + if x != nil { + return x.VIP + } + return 0 +} + +//房间信息 +//PACKET_FORTUNEMOUSE_SCFORTUNEMOUSEROOMINFO +type SCGatesOfOlympusRoomInfo struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + RoomId int32 `protobuf:"varint,1,opt,name=RoomId,proto3" json:"RoomId,omitempty"` //房间id + GameFreeId int32 `protobuf:"varint,2,opt,name=GameFreeId,proto3" json:"GameFreeId,omitempty"` + GameId int32 `protobuf:"varint,3,opt,name=GameId,proto3" json:"GameId,omitempty"` //游戏id + RoomMode int32 `protobuf:"varint,4,opt,name=RoomMode,proto3" json:"RoomMode,omitempty"` //游戏模式 + Params []int32 `protobuf:"varint,5,rep,packed,name=Params,proto3" json:"Params,omitempty"` //规则参数 + NumOfGames int32 `protobuf:"varint,6,opt,name=NumOfGames,proto3" json:"NumOfGames,omitempty"` //当前第几局 + State int32 `protobuf:"varint,7,opt,name=State,proto3" json:"State,omitempty"` //房间当前状态 + ParamsEx []int64 `protobuf:"varint,8,rep,packed,name=ParamsEx,proto3" json:"ParamsEx,omitempty"` //其他参数 + SceneType int32 `protobuf:"varint,9,opt,name=SceneType,proto3" json:"SceneType,omitempty"` //房间模式 + Player *GatesOfOlympusPlayerData `protobuf:"bytes,10,opt,name=Player,proto3" json:"Player,omitempty"` //房间内的玩家信息 + PlayerInfo string `protobuf:"bytes,11,opt,name=PlayerInfo,proto3" json:"PlayerInfo,omitempty"` +} + +func (x *SCGatesOfOlympusRoomInfo) Reset() { + *x = SCGatesOfOlympusRoomInfo{} + if protoimpl.UnsafeEnabled { + mi := &file_protocol_gatesofolympus_gatesofolympus_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SCGatesOfOlympusRoomInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SCGatesOfOlympusRoomInfo) ProtoMessage() {} + +func (x *SCGatesOfOlympusRoomInfo) ProtoReflect() protoreflect.Message { + mi := &file_protocol_gatesofolympus_gatesofolympus_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SCGatesOfOlympusRoomInfo.ProtoReflect.Descriptor instead. +func (*SCGatesOfOlympusRoomInfo) Descriptor() ([]byte, []int) { + return file_protocol_gatesofolympus_gatesofolympus_proto_rawDescGZIP(), []int{1} +} + +func (x *SCGatesOfOlympusRoomInfo) GetRoomId() int32 { + if x != nil { + return x.RoomId + } + return 0 +} + +func (x *SCGatesOfOlympusRoomInfo) GetGameFreeId() int32 { + if x != nil { + return x.GameFreeId + } + return 0 +} + +func (x *SCGatesOfOlympusRoomInfo) GetGameId() int32 { + if x != nil { + return x.GameId + } + return 0 +} + +func (x *SCGatesOfOlympusRoomInfo) GetRoomMode() int32 { + if x != nil { + return x.RoomMode + } + return 0 +} + +func (x *SCGatesOfOlympusRoomInfo) GetParams() []int32 { + if x != nil { + return x.Params + } + return nil +} + +func (x *SCGatesOfOlympusRoomInfo) GetNumOfGames() int32 { + if x != nil { + return x.NumOfGames + } + return 0 +} + +func (x *SCGatesOfOlympusRoomInfo) GetState() int32 { + if x != nil { + return x.State + } + return 0 +} + +func (x *SCGatesOfOlympusRoomInfo) GetParamsEx() []int64 { + if x != nil { + return x.ParamsEx + } + return nil +} + +func (x *SCGatesOfOlympusRoomInfo) GetSceneType() int32 { + if x != nil { + return x.SceneType + } + return 0 +} + +func (x *SCGatesOfOlympusRoomInfo) GetPlayer() *GatesOfOlympusPlayerData { + if x != nil { + return x.Player + } + return nil +} + +func (x *SCGatesOfOlympusRoomInfo) GetPlayerInfo() string { + if x != nil { + return x.PlayerInfo + } + return "" +} + +//玩家操作 +//PACKET_FORTUNEMOUSE_CSFORTUNEMOUSEOP +type CSGatesOfOlympusOp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + OpCode int32 `protobuf:"varint,1,opt,name=OpCode,proto3" json:"OpCode,omitempty"` //操作码 0.spin + Params []int64 `protobuf:"varint,2,rep,packed,name=Params,proto3" json:"Params,omitempty"` //操作参数 下注索引编号 +} + +func (x *CSGatesOfOlympusOp) Reset() { + *x = CSGatesOfOlympusOp{} + if protoimpl.UnsafeEnabled { + mi := &file_protocol_gatesofolympus_gatesofolympus_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CSGatesOfOlympusOp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CSGatesOfOlympusOp) ProtoMessage() {} + +func (x *CSGatesOfOlympusOp) ProtoReflect() protoreflect.Message { + mi := &file_protocol_gatesofolympus_gatesofolympus_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use CSGatesOfOlympusOp.ProtoReflect.Descriptor instead. +func (*CSGatesOfOlympusOp) Descriptor() ([]byte, []int) { + return file_protocol_gatesofolympus_gatesofolympus_proto_rawDescGZIP(), []int{2} +} + +func (x *CSGatesOfOlympusOp) GetOpCode() int32 { + if x != nil { + return x.OpCode + } + return 0 +} + +func (x *CSGatesOfOlympusOp) GetParams() []int64 { + if x != nil { + return x.Params + } + return nil +} + +//玩家操作返回 +//PACKET_FORTUNEMOUSE_SCFORTUNEMOUSEOP +type SCGatesOfOlympusOp struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + OpCode int32 `protobuf:"varint,1,opt,name=OpCode,proto3" json:"OpCode,omitempty"` //操作码 + OpRetCode int32 `protobuf:"varint,2,opt,name=OpRetCode,proto3" json:"OpRetCode,omitempty"` //操作结果 1.金币不足 2.低于该值不能押注 + Params []int64 `protobuf:"varint,3,rep,packed,name=Params,proto3" json:"Params,omitempty"` //操作参数 +} + +func (x *SCGatesOfOlympusOp) Reset() { + *x = SCGatesOfOlympusOp{} + if protoimpl.UnsafeEnabled { + mi := &file_protocol_gatesofolympus_gatesofolympus_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SCGatesOfOlympusOp) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SCGatesOfOlympusOp) ProtoMessage() {} + +func (x *SCGatesOfOlympusOp) ProtoReflect() protoreflect.Message { + mi := &file_protocol_gatesofolympus_gatesofolympus_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SCGatesOfOlympusOp.ProtoReflect.Descriptor instead. +func (*SCGatesOfOlympusOp) Descriptor() ([]byte, []int) { + return file_protocol_gatesofolympus_gatesofolympus_proto_rawDescGZIP(), []int{3} +} + +func (x *SCGatesOfOlympusOp) GetOpCode() int32 { + if x != nil { + return x.OpCode + } + return 0 +} + +func (x *SCGatesOfOlympusOp) GetOpRetCode() int32 { + if x != nil { + return x.OpRetCode + } + return 0 +} + +func (x *SCGatesOfOlympusOp) GetParams() []int64 { + if x != nil { + return x.Params + } + return nil +} + +//房间状态 +//PACKET_FORTUNEMOUSE_SCFORTUNEMOUSEROOMSTATE +type SCGatesOfOlympusRoomState struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + State int32 `protobuf:"varint,1,opt,name=State,proto3" json:"State,omitempty"` //房间当前状态 + SubState int32 `protobuf:"varint,2,opt,name=SubState,proto3" json:"SubState,omitempty"` //房间当前子状态 + Params []int32 `protobuf:"varint,3,rep,packed,name=Params,proto3" json:"Params,omitempty"` //状态参数 +} + +func (x *SCGatesOfOlympusRoomState) Reset() { + *x = SCGatesOfOlympusRoomState{} + if protoimpl.UnsafeEnabled { + mi := &file_protocol_gatesofolympus_gatesofolympus_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SCGatesOfOlympusRoomState) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SCGatesOfOlympusRoomState) ProtoMessage() {} + +func (x *SCGatesOfOlympusRoomState) ProtoReflect() protoreflect.Message { + mi := &file_protocol_gatesofolympus_gatesofolympus_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SCGatesOfOlympusRoomState.ProtoReflect.Descriptor instead. +func (*SCGatesOfOlympusRoomState) Descriptor() ([]byte, []int) { + return file_protocol_gatesofolympus_gatesofolympus_proto_rawDescGZIP(), []int{4} +} + +func (x *SCGatesOfOlympusRoomState) GetState() int32 { + if x != nil { + return x.State + } + return 0 +} + +func (x *SCGatesOfOlympusRoomState) GetSubState() int32 { + if x != nil { + return x.SubState + } + return 0 +} + +func (x *SCGatesOfOlympusRoomState) GetParams() []int32 { + if x != nil { + return x.Params + } + return nil +} + +//PACKET_FORTUNEMOUSE_SCFORTUNEMOUSEBILLED +type SCGatesOfOlympusBilled struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + OpRetCode int32 `protobuf:"varint,1,opt,name=OpRetCode,proto3" json:"OpRetCode,omitempty"` //0.spin成功 1.spin失败 + GameEndStr string `protobuf:"bytes,2,opt,name=GameEndStr,proto3" json:"GameEndStr,omitempty"` +} + +func (x *SCGatesOfOlympusBilled) Reset() { + *x = SCGatesOfOlympusBilled{} + if protoimpl.UnsafeEnabled { + mi := &file_protocol_gatesofolympus_gatesofolympus_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SCGatesOfOlympusBilled) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SCGatesOfOlympusBilled) ProtoMessage() {} + +func (x *SCGatesOfOlympusBilled) ProtoReflect() protoreflect.Message { + mi := &file_protocol_gatesofolympus_gatesofolympus_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SCGatesOfOlympusBilled.ProtoReflect.Descriptor instead. +func (*SCGatesOfOlympusBilled) Descriptor() ([]byte, []int) { + return file_protocol_gatesofolympus_gatesofolympus_proto_rawDescGZIP(), []int{5} +} + +func (x *SCGatesOfOlympusBilled) GetOpRetCode() int32 { + if x != nil { + return x.OpRetCode + } + return 0 +} + +func (x *SCGatesOfOlympusBilled) GetGameEndStr() string { + if x != nil { + return x.GameEndStr + } + return "" +} + +var File_protocol_gatesofolympus_gatesofolympus_proto protoreflect.FileDescriptor + +var file_protocol_gatesofolympus_gatesofolympus_proto_rawDesc = []byte{ + 0x0a, 0x2c, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2f, 0x67, 0x61, 0x74, 0x65, 0x73, + 0x6f, 0x66, 0x6f, 0x6c, 0x79, 0x6d, 0x70, 0x75, 0x73, 0x2f, 0x67, 0x61, 0x74, 0x65, 0x73, 0x6f, + 0x66, 0x6f, 0x6c, 0x79, 0x6d, 0x70, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0e, + 0x67, 0x61, 0x74, 0x65, 0x73, 0x6f, 0x66, 0x6f, 0x6c, 0x79, 0x6d, 0x70, 0x75, 0x73, 0x22, 0x82, + 0x02, 0x0a, 0x18, 0x47, 0x61, 0x74, 0x65, 0x73, 0x4f, 0x66, 0x4f, 0x6c, 0x79, 0x6d, 0x70, 0x75, + 0x73, 0x50, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x44, 0x61, 0x74, 0x61, 0x12, 0x12, 0x0a, 0x04, 0x4e, + 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x12, + 0x12, 0x0a, 0x04, 0x53, 0x6e, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x53, + 0x6e, 0x49, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x48, 0x65, 0x61, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x05, 0x52, 0x04, 0x48, 0x65, 0x61, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x53, 0x65, 0x78, 0x18, 0x04, + 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x53, 0x65, 0x78, 0x12, 0x12, 0x0a, 0x04, 0x43, 0x6f, 0x69, + 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x43, 0x6f, 0x69, 0x6e, 0x12, 0x10, 0x0a, + 0x03, 0x50, 0x6f, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, 0x50, 0x6f, 0x73, 0x12, + 0x12, 0x0a, 0x04, 0x46, 0x6c, 0x61, 0x67, 0x18, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x04, 0x46, + 0x6c, 0x61, 0x67, 0x12, 0x16, 0x0a, 0x06, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x18, 0x08, 0x20, + 0x03, 0x28, 0x09, 0x52, 0x06, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x43, + 0x69, 0x74, 0x79, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x43, 0x69, 0x74, 0x79, 0x12, + 0x20, 0x0a, 0x0b, 0x48, 0x65, 0x61, 0x64, 0x4f, 0x75, 0x74, 0x4c, 0x69, 0x6e, 0x65, 0x18, 0x0a, + 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x48, 0x65, 0x61, 0x64, 0x4f, 0x75, 0x74, 0x4c, 0x69, 0x6e, + 0x65, 0x12, 0x10, 0x0a, 0x03, 0x56, 0x49, 0x50, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x05, 0x52, 0x03, + 0x56, 0x49, 0x50, 0x22, 0xf0, 0x02, 0x0a, 0x18, 0x53, 0x43, 0x47, 0x61, 0x74, 0x65, 0x73, 0x4f, + 0x66, 0x4f, 0x6c, 0x79, 0x6d, 0x70, 0x75, 0x73, 0x52, 0x6f, 0x6f, 0x6d, 0x49, 0x6e, 0x66, 0x6f, + 0x12, 0x16, 0x0a, 0x06, 0x52, 0x6f, 0x6f, 0x6d, 0x49, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, + 0x52, 0x06, 0x52, 0x6f, 0x6f, 0x6d, 0x49, 0x64, 0x12, 0x1e, 0x0a, 0x0a, 0x47, 0x61, 0x6d, 0x65, + 0x46, 0x72, 0x65, 0x65, 0x49, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x47, 0x61, + 0x6d, 0x65, 0x46, 0x72, 0x65, 0x65, 0x49, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x47, 0x61, 0x6d, 0x65, + 0x49, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x47, 0x61, 0x6d, 0x65, 0x49, 0x64, + 0x12, 0x1a, 0x0a, 0x08, 0x52, 0x6f, 0x6f, 0x6d, 0x4d, 0x6f, 0x64, 0x65, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x05, 0x52, 0x08, 0x52, 0x6f, 0x6f, 0x6d, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x16, 0x0a, 0x06, + 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x05, 0x52, 0x06, 0x50, 0x61, + 0x72, 0x61, 0x6d, 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x4e, 0x75, 0x6d, 0x4f, 0x66, 0x47, 0x61, 0x6d, + 0x65, 0x73, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x4e, 0x75, 0x6d, 0x4f, 0x66, 0x47, + 0x61, 0x6d, 0x65, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x53, 0x74, 0x61, 0x74, 0x65, 0x18, 0x07, 0x20, + 0x01, 0x28, 0x05, 0x52, 0x05, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x50, 0x61, + 0x72, 0x61, 0x6d, 0x73, 0x45, 0x78, 0x18, 0x08, 0x20, 0x03, 0x28, 0x03, 0x52, 0x08, 0x50, 0x61, + 0x72, 0x61, 0x6d, 0x73, 0x45, 0x78, 0x12, 0x1c, 0x0a, 0x09, 0x53, 0x63, 0x65, 0x6e, 0x65, 0x54, + 0x79, 0x70, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x53, 0x63, 0x65, 0x6e, 0x65, + 0x54, 0x79, 0x70, 0x65, 0x12, 0x40, 0x0a, 0x06, 0x50, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x18, 0x0a, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x67, 0x61, 0x74, 0x65, 0x73, 0x6f, 0x66, 0x6f, 0x6c, + 0x79, 0x6d, 0x70, 0x75, 0x73, 0x2e, 0x47, 0x61, 0x74, 0x65, 0x73, 0x4f, 0x66, 0x4f, 0x6c, 0x79, + 0x6d, 0x70, 0x75, 0x73, 0x50, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x44, 0x61, 0x74, 0x61, 0x52, 0x06, + 0x50, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x12, 0x1e, 0x0a, 0x0a, 0x50, 0x6c, 0x61, 0x79, 0x65, 0x72, + 0x49, 0x6e, 0x66, 0x6f, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x50, 0x6c, 0x61, 0x79, + 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x22, 0x44, 0x0a, 0x12, 0x43, 0x53, 0x47, 0x61, 0x74, 0x65, + 0x73, 0x4f, 0x66, 0x4f, 0x6c, 0x79, 0x6d, 0x70, 0x75, 0x73, 0x4f, 0x70, 0x12, 0x16, 0x0a, 0x06, + 0x4f, 0x70, 0x43, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x06, 0x4f, 0x70, + 0x43, 0x6f, 0x64, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x18, 0x02, + 0x20, 0x03, 0x28, 0x03, 0x52, 0x06, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x22, 0x62, 0x0a, 0x12, + 0x53, 0x43, 0x47, 0x61, 0x74, 0x65, 0x73, 0x4f, 0x66, 0x4f, 0x6c, 0x79, 0x6d, 0x70, 0x75, 0x73, + 0x4f, 0x70, 0x12, 0x16, 0x0a, 0x06, 0x4f, 0x70, 0x43, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x05, 0x52, 0x06, 0x4f, 0x70, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x4f, 0x70, + 0x52, 0x65, 0x74, 0x43, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x4f, + 0x70, 0x52, 0x65, 0x74, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x50, 0x61, 0x72, 0x61, + 0x6d, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x03, 0x52, 0x06, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, + 0x22, 0x65, 0x0a, 0x19, 0x53, 0x43, 0x47, 0x61, 0x74, 0x65, 0x73, 0x4f, 0x66, 0x4f, 0x6c, 0x79, + 0x6d, 0x70, 0x75, 0x73, 0x52, 0x6f, 0x6f, 0x6d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x14, 0x0a, + 0x05, 0x53, 0x74, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52, 0x05, 0x53, 0x74, + 0x61, 0x74, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x53, 0x75, 0x62, 0x53, 0x74, 0x61, 0x74, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x53, 0x75, 0x62, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, + 0x16, 0x0a, 0x06, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x05, 0x52, + 0x06, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x73, 0x22, 0x56, 0x0a, 0x16, 0x53, 0x43, 0x47, 0x61, 0x74, + 0x65, 0x73, 0x4f, 0x66, 0x4f, 0x6c, 0x79, 0x6d, 0x70, 0x75, 0x73, 0x42, 0x69, 0x6c, 0x6c, 0x65, + 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x4f, 0x70, 0x52, 0x65, 0x74, 0x43, 0x6f, 0x64, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x4f, 0x70, 0x52, 0x65, 0x74, 0x43, 0x6f, 0x64, 0x65, 0x12, + 0x1e, 0x0a, 0x0a, 0x47, 0x61, 0x6d, 0x65, 0x45, 0x6e, 0x64, 0x53, 0x74, 0x72, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x0a, 0x47, 0x61, 0x6d, 0x65, 0x45, 0x6e, 0x64, 0x53, 0x74, 0x72, 0x2a, + 0xaf, 0x02, 0x0a, 0x11, 0x47, 0x61, 0x74, 0x65, 0x73, 0x4f, 0x66, 0x4f, 0x6c, 0x79, 0x6d, 0x70, + 0x75, 0x73, 0x50, 0x49, 0x44, 0x12, 0x1e, 0x0a, 0x1a, 0x50, 0x41, 0x43, 0x4b, 0x45, 0x54, 0x5f, + 0x47, 0x41, 0x54, 0x45, 0x53, 0x4f, 0x46, 0x4f, 0x4c, 0x59, 0x4d, 0x50, 0x55, 0x53, 0x5f, 0x5a, + 0x45, 0x52, 0x4f, 0x10, 0x00, 0x12, 0x33, 0x0a, 0x2e, 0x50, 0x41, 0x43, 0x4b, 0x45, 0x54, 0x5f, + 0x47, 0x41, 0x54, 0x45, 0x53, 0x4f, 0x46, 0x4f, 0x4c, 0x59, 0x4d, 0x50, 0x55, 0x53, 0x5f, 0x53, + 0x43, 0x47, 0x41, 0x54, 0x45, 0x53, 0x4f, 0x46, 0x4f, 0x4c, 0x59, 0x4d, 0x50, 0x55, 0x53, 0x52, + 0x4f, 0x4f, 0x4d, 0x49, 0x4e, 0x46, 0x4f, 0x10, 0x9c, 0x2c, 0x12, 0x2d, 0x0a, 0x28, 0x50, 0x41, + 0x43, 0x4b, 0x45, 0x54, 0x5f, 0x47, 0x41, 0x54, 0x45, 0x53, 0x4f, 0x46, 0x4f, 0x4c, 0x59, 0x4d, + 0x50, 0x55, 0x53, 0x5f, 0x43, 0x53, 0x47, 0x41, 0x54, 0x45, 0x53, 0x4f, 0x46, 0x4f, 0x4c, 0x59, + 0x4d, 0x50, 0x55, 0x53, 0x4f, 0x50, 0x10, 0x9d, 0x2c, 0x12, 0x2d, 0x0a, 0x28, 0x50, 0x41, 0x43, + 0x4b, 0x45, 0x54, 0x5f, 0x47, 0x41, 0x54, 0x45, 0x53, 0x4f, 0x46, 0x4f, 0x4c, 0x59, 0x4d, 0x50, + 0x55, 0x53, 0x5f, 0x53, 0x43, 0x47, 0x41, 0x54, 0x45, 0x53, 0x4f, 0x46, 0x4f, 0x4c, 0x59, 0x4d, + 0x50, 0x55, 0x53, 0x4f, 0x50, 0x10, 0x9e, 0x2c, 0x12, 0x34, 0x0a, 0x2f, 0x50, 0x41, 0x43, 0x4b, + 0x45, 0x54, 0x5f, 0x47, 0x41, 0x54, 0x45, 0x53, 0x4f, 0x46, 0x4f, 0x4c, 0x59, 0x4d, 0x50, 0x55, + 0x53, 0x5f, 0x53, 0x43, 0x47, 0x41, 0x54, 0x45, 0x53, 0x4f, 0x46, 0x4f, 0x4c, 0x59, 0x4d, 0x50, + 0x55, 0x53, 0x52, 0x4f, 0x4f, 0x4d, 0x53, 0x54, 0x41, 0x54, 0x45, 0x10, 0x9f, 0x2c, 0x12, 0x31, + 0x0a, 0x2c, 0x50, 0x41, 0x43, 0x4b, 0x45, 0x54, 0x5f, 0x47, 0x41, 0x54, 0x45, 0x53, 0x4f, 0x46, + 0x4f, 0x4c, 0x59, 0x4d, 0x50, 0x55, 0x53, 0x5f, 0x53, 0x43, 0x47, 0x41, 0x54, 0x45, 0x53, 0x4f, + 0x46, 0x4f, 0x4c, 0x59, 0x4d, 0x50, 0x55, 0x53, 0x42, 0x49, 0x4c, 0x4c, 0x45, 0x44, 0x10, 0xa0, + 0x2c, 0x42, 0x2e, 0x5a, 0x2c, 0x6d, 0x6f, 0x6e, 0x67, 0x6f, 0x2e, 0x67, 0x61, 0x6d, 0x65, 0x73, + 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x61, 0x6d, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, + 0x6f, 0x6c, 0x2f, 0x67, 0x61, 0x74, 0x65, 0x73, 0x6f, 0x66, 0x6f, 0x6c, 0x79, 0x6d, 0x70, 0x75, + 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_protocol_gatesofolympus_gatesofolympus_proto_rawDescOnce sync.Once + file_protocol_gatesofolympus_gatesofolympus_proto_rawDescData = file_protocol_gatesofolympus_gatesofolympus_proto_rawDesc +) + +func file_protocol_gatesofolympus_gatesofolympus_proto_rawDescGZIP() []byte { + file_protocol_gatesofolympus_gatesofolympus_proto_rawDescOnce.Do(func() { + file_protocol_gatesofolympus_gatesofolympus_proto_rawDescData = protoimpl.X.CompressGZIP(file_protocol_gatesofolympus_gatesofolympus_proto_rawDescData) + }) + return file_protocol_gatesofolympus_gatesofolympus_proto_rawDescData +} + +var file_protocol_gatesofolympus_gatesofolympus_proto_enumTypes = make([]protoimpl.EnumInfo, 1) +var file_protocol_gatesofolympus_gatesofolympus_proto_msgTypes = make([]protoimpl.MessageInfo, 6) +var file_protocol_gatesofolympus_gatesofolympus_proto_goTypes = []interface{}{ + (GatesOfOlympusPID)(0), // 0: gatesofolympus.GatesOfOlympusPID + (*GatesOfOlympusPlayerData)(nil), // 1: gatesofolympus.GatesOfOlympusPlayerData + (*SCGatesOfOlympusRoomInfo)(nil), // 2: gatesofolympus.SCGatesOfOlympusRoomInfo + (*CSGatesOfOlympusOp)(nil), // 3: gatesofolympus.CSGatesOfOlympusOp + (*SCGatesOfOlympusOp)(nil), // 4: gatesofolympus.SCGatesOfOlympusOp + (*SCGatesOfOlympusRoomState)(nil), // 5: gatesofolympus.SCGatesOfOlympusRoomState + (*SCGatesOfOlympusBilled)(nil), // 6: gatesofolympus.SCGatesOfOlympusBilled +} +var file_protocol_gatesofolympus_gatesofolympus_proto_depIdxs = []int32{ + 1, // 0: gatesofolympus.SCGatesOfOlympusRoomInfo.Player:type_name -> gatesofolympus.GatesOfOlympusPlayerData + 1, // [1:1] is the sub-list for method output_type + 1, // [1:1] is the sub-list for method input_type + 1, // [1:1] is the sub-list for extension type_name + 1, // [1:1] is the sub-list for extension extendee + 0, // [0:1] is the sub-list for field type_name +} + +func init() { file_protocol_gatesofolympus_gatesofolympus_proto_init() } +func file_protocol_gatesofolympus_gatesofolympus_proto_init() { + if File_protocol_gatesofolympus_gatesofolympus_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_protocol_gatesofolympus_gatesofolympus_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*GatesOfOlympusPlayerData); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_protocol_gatesofolympus_gatesofolympus_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SCGatesOfOlympusRoomInfo); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_protocol_gatesofolympus_gatesofolympus_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CSGatesOfOlympusOp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_protocol_gatesofolympus_gatesofolympus_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SCGatesOfOlympusOp); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_protocol_gatesofolympus_gatesofolympus_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SCGatesOfOlympusRoomState); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_protocol_gatesofolympus_gatesofolympus_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SCGatesOfOlympusBilled); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_protocol_gatesofolympus_gatesofolympus_proto_rawDesc, + NumEnums: 1, + NumMessages: 6, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_protocol_gatesofolympus_gatesofolympus_proto_goTypes, + DependencyIndexes: file_protocol_gatesofolympus_gatesofolympus_proto_depIdxs, + EnumInfos: file_protocol_gatesofolympus_gatesofolympus_proto_enumTypes, + MessageInfos: file_protocol_gatesofolympus_gatesofolympus_proto_msgTypes, + }.Build() + File_protocol_gatesofolympus_gatesofolympus_proto = out.File + file_protocol_gatesofolympus_gatesofolympus_proto_rawDesc = nil + file_protocol_gatesofolympus_gatesofolympus_proto_goTypes = nil + file_protocol_gatesofolympus_gatesofolympus_proto_depIdxs = nil +} diff --git a/protocol/gatesofolympus/gatesofolympus.proto b/protocol/gatesofolympus/gatesofolympus.proto new file mode 100644 index 0000000..ef76923 --- /dev/null +++ b/protocol/gatesofolympus/gatesofolympus.proto @@ -0,0 +1,68 @@ +syntax = "proto3"; +package gatesofolympus; +option go_package = "mongo.games.com/game/protocol/gatesofolympus"; + +//gatesofolympus +//龙 +enum GatesOfOlympusPID { + PACKET_GATESOFOLYMPUS_ZERO = 0;// 弃用消息号 + PACKET_GATESOFOLYMPUS_SCGATESOFOLYMPUSROOMINFO = 5660; //房间信息 + PACKET_GATESOFOLYMPUS_CSGATESOFOLYMPUSOP = 5661; + PACKET_GATESOFOLYMPUS_SCGATESOFOLYMPUSOP = 5662; + PACKET_GATESOFOLYMPUS_SCGATESOFOLYMPUSROOMSTATE = 5663; + PACKET_GATESOFOLYMPUS_SCGATESOFOLYMPUSBILLED = 5664; +} + +message GatesOfOlympusPlayerData { + string Name = 1; //名字 + int32 SnId = 2; //账号 + int32 Head = 3; //头像 + int32 Sex = 4; //性别 + int64 Coin = 5; //金币 + int32 Pos = 6; //座位位置 + int32 Flag = 7; //二进制标记 + repeated string Params = 8; //其他数据 如:ip 等 + string City = 9; //城市 + int32 HeadOutLine = 10; //头像框 + int32 VIP = 11; +} +//房间信息 +//PACKET_FORTUNEMOUSE_SCFORTUNEMOUSEROOMINFO +message SCGatesOfOlympusRoomInfo { + int32 RoomId = 1; //房间id + int32 GameFreeId = 2; + int32 GameId = 3; //游戏id + int32 RoomMode = 4; //游戏模式 + repeated int32 Params = 5; //规则参数 + int32 NumOfGames = 6; //当前第几局 + int32 State = 7; //房间当前状态 + repeated int64 ParamsEx = 8; //其他参数 + int32 SceneType = 9; //房间模式 + GatesOfOlympusPlayerData Player = 10; //房间内的玩家信息 + string PlayerInfo = 11; +} +//玩家操作 +//PACKET_FORTUNEMOUSE_CSFORTUNEMOUSEOP +message CSGatesOfOlympusOp { + int32 OpCode = 1; //操作码 0.spin + repeated int64 Params = 2; //操作参数 下注索引编号 +} +//玩家操作返回 +//PACKET_FORTUNEMOUSE_SCFORTUNEMOUSEOP +message SCGatesOfOlympusOp { + int32 OpCode = 1; //操作码 + int32 OpRetCode = 2; //操作结果 1.金币不足 2.低于该值不能押注 + repeated int64 Params = 3; //操作参数 +} +//房间状态 +//PACKET_FORTUNEMOUSE_SCFORTUNEMOUSEROOMSTATE +message SCGatesOfOlympusRoomState { + int32 State = 1; //房间当前状态 + int32 SubState = 2; //房间当前子状态 + repeated int32 Params = 3; //状态参数 +} +//PACKET_FORTUNEMOUSE_SCFORTUNEMOUSEBILLED +message SCGatesOfOlympusBilled{ + int32 OpRetCode = 1;//0.spin成功 1.spin失败 + string GameEndStr = 2; +} \ No newline at end of file From 83db9ddddc8a2db64b661069b0a1b14cbbdebe21 Mon Sep 17 00:00:00 2001 From: tomas Date: Mon, 2 Dec 2024 10:44:26 +0800 Subject: [PATCH 08/41] =?UTF-8?q?fix=20ox=20=E8=90=A5=E6=94=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gamesrv/fortunemouse/scenepolicy_fortunemouse.go | 13 ++++++++++--- gamesrv/fortuneox/scenepolicy_fortuneox.go | 4 ++-- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/gamesrv/fortunemouse/scenepolicy_fortunemouse.go b/gamesrv/fortunemouse/scenepolicy_fortunemouse.go index c330f41..9c1998b 100644 --- a/gamesrv/fortunemouse/scenepolicy_fortunemouse.go +++ b/gamesrv/fortunemouse/scenepolicy_fortunemouse.go @@ -510,7 +510,14 @@ func (this *ScenePolicyFortuneMouse) GetSceneState(s *base.Scene, stateid int) b func FortuneMouseAndSaveLog(sceneEx *FortuneMouseSceneData, playerEx *FortuneMousePlayerData, data assemble.GameEnd) { if !playerEx.IsRob { data.SnId = playerEx.SnId - if data.Results[0].FreeStatus != 1 && data.Results[0].FreeNumMax != 0 { + var respinStatus int + if data.Results[0].ArrSpins[0].Special != nil { + sp, _ := json.Marshal(data.Results[0].ArrSpins[0].Special) + var spinLock SpinLock + json.Unmarshal(sp, &spinLock) + respinStatus = spinLock.ReSpinStatus + } + if respinStatus == 0 || respinStatus == 1 { data.TotalBet = 0 } info, err := model.MarshalGameNoteByROLL(data) @@ -519,10 +526,10 @@ func FortuneMouseAndSaveLog(sceneEx *FortuneMouseSceneData, playerEx *FortuneMou playerEx.currentLogId = logid sceneEx.SaveGameDetailedLog(logid, info, &base.GameDetailedParam{}) var totalin, totalout int64 - if data.Results[0].FreeStatus == 1 || data.Results[0].FreeNumMax == 0 { + if respinStatus == 0 || respinStatus == 1 { totalin = playerEx.totalBet } - if data.Results[0].FreeStatus == 3 || data.Results[0].FreeNumMax == 0 { + if respinStatus == 0 || respinStatus == 3 { totalout = int64(data.RoundReward) + playerEx.taxCoin } validFlow := totalin + totalout diff --git a/gamesrv/fortuneox/scenepolicy_fortuneox.go b/gamesrv/fortuneox/scenepolicy_fortuneox.go index 80de922..bc66c0e 100644 --- a/gamesrv/fortuneox/scenepolicy_fortuneox.go +++ b/gamesrv/fortuneox/scenepolicy_fortuneox.go @@ -517,7 +517,7 @@ func FortuneOxAndSaveLog(sceneEx *FortuneOxSceneData, playerEx *FortuneOxPlayerD json.Unmarshal(sp, &spinLock) respinStatus = spinLock.ReSpinStatus } - if respinStatus != 0 && respinStatus != 1 { + if respinStatus == 0 || respinStatus == 1 { data.TotalBet = 0 } @@ -527,7 +527,7 @@ func FortuneOxAndSaveLog(sceneEx *FortuneOxSceneData, playerEx *FortuneOxPlayerD playerEx.currentLogId = logid sceneEx.SaveGameDetailedLog(logid, info, &base.GameDetailedParam{}) var totalin, totalout int64 - if respinStatus == 1 { + if respinStatus == 0 || respinStatus == 1 { totalin = playerEx.totalBet } if respinStatus == 0 || respinStatus == 3 { From fe88981e9d69b90e4f72e2b28afcb15824c6563f Mon Sep 17 00:00:00 2001 From: sk <123456@qq.com> Date: Mon, 2 Dec 2024 13:06:07 +0800 Subject: [PATCH 09/41] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E7=89=8C=E5=B1=80?= =?UTF-8?q?=E8=AE=B0=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gamesrv/avengers/scenepolicy_avengers.go | 27 +- gamesrv/base/player.go | 56 ++- gamesrv/base/scene.go | 353 ++++++++++-------- gamesrv/caishen/scenepolicy_caishen.go | 26 +- gamesrv/chess/scene.go | 1 + gamesrv/chess/scenepolicy.go | 26 +- gamesrv/clawdoll/scenepolicy_clawdoll.go | 40 +- .../easterisland/scenepolicy_easterisland.go | 26 +- gamesrv/fishing/playerdata_fishing.go | 25 +- .../scenepolicy_fortunedragon.go | 27 +- gamesrv/fortuneox/scenepolicy_fortuneox.go | 29 +- .../scenepolicy_fortunerabbit.go | 29 +- .../fortunetiger/scenepolicy_fortunetiger.go | 29 +- gamesrv/fruits/scenedata_fruits.go | 38 +- gamesrv/iceage/scenepolicy_iceage.go | 26 +- gamesrv/richblessed/scenedata_richblessed.go | 38 +- gamesrv/smallrocket/scene.go | 2 + gamesrv/smallrocket/scenepolicy.go | 59 ++- gamesrv/tamquoc/scenepolicy_tamquoc.go | 26 +- gamesrv/thirteen/scenepolicy.go | 49 ++- gamesrv/tienlen/scenepolicy_tienlen.go | 32 +- model/dataevent.go | 43 --- model/gamelogtype.go | 2 + model/gameplayerlistlog.go | 4 +- 24 files changed, 556 insertions(+), 457 deletions(-) diff --git a/gamesrv/avengers/scenepolicy_avengers.go b/gamesrv/avengers/scenepolicy_avengers.go index b73f65c..c9334c3 100644 --- a/gamesrv/avengers/scenepolicy_avengers.go +++ b/gamesrv/avengers/scenepolicy_avengers.go @@ -934,31 +934,30 @@ func AvengersCheckAndSaveLog(sceneEx *AvengersSceneData, playerEx *AvengersPlaye if err == nil { logid, _ := model.AutoIncGameLogId() playerEx.currentLogId = logid - sceneEx.SaveGameDetailedLog(logid, info, &base.GameDetailedParam{}) + sceneEx.SaveGameDetailedLog(&base.SaveGameDetailedParam{ + LogId: logid, + Detail: info, + GameTime: 1, + }) totalin := int64(playerEx.RollGameType.BaseResult.TotalBet) totalout := playerEx.RollGameType.BaseResult.ChangeCoin + playerEx.taxCoin + totalin - validFlow := totalin + totalout - validBet := common.AbsI64(totalin - totalout) - logParam := &base.SaveGamePlayerListLogParam{ - Platform: playerEx.Platform, - Channel: playerEx.Channel, - Promoter: playerEx.BeUnderAgentCode, - PackageTag: playerEx.PackageID, - InviterId: playerEx.InviterId, + sceneEx.SaveGamePlayerListLog(&base.SaveGamePlayerListLogParam{ LogId: logid, + Platform: playerEx.Platform, + Snid: playerEx.SnId, + Channel: playerEx.Channel, + ChannelId: playerEx.ChannelId, TotalIn: totalin, TotalOut: totalout, TaxCoin: playerEx.taxCoin, BetAmount: int64(playerEx.RollGameType.BaseResult.TotalBet), WinAmountNoAnyTax: playerEx.RollGameType.BaseResult.ChangeCoin, - ValidBet: validBet, - ValidFlow: validFlow, - IsFirstGame: sceneEx.IsPlayerFirst(playerEx.Player), + IsFirstGame: false, IsFree: playerEx.RollGameType.BaseResult.IsFree, WinSmallGame: playerEx.RollGameType.BaseResult.WinSmallGame, WinTotal: playerEx.RollGameType.BaseResult.WinTotal, - } - sceneEx.SaveGamePlayerListLog(playerEx.SnId, logParam) + GameTime: 1, + }) } } } diff --git a/gamesrv/base/player.go b/gamesrv/base/player.go index 53d263d..5f47a55 100644 --- a/gamesrv/base/player.go +++ b/gamesrv/base/player.go @@ -2,6 +2,7 @@ package base import ( "fmt" + "github.com/jinzhu/now" "math" "math/rand" "time" @@ -621,7 +622,14 @@ func (this *Player) AddRankScore(rankType int32, num int64) { } } -func (this *Player) ReportGameEvent(tax, taxex, changeCoin, validbet, validFlow, in, out int64) { +type ReportGameEventParam struct { + Tax int64 // 税收 + Change int64 // 净输赢,正负值,不带税收 + In, Out int64 // 投入,产出(税前) + GameTime int64 // 游戏时长,秒 +} + +func (this *Player) ReportGameEvent(param *ReportGameEventParam) { // 记录玩家 首次参与该场次的游戏时间 游戏次数 var gameFirstTime, gameFreeFirstTime time.Time var gameTimes, gameFreeTimes int64 @@ -638,12 +646,46 @@ func (this *Player) ReportGameEvent(tax, taxex, changeCoin, validbet, validFlow, gameFreeTimes = dataGame.Statics.GameTimes } - gamingTime := int32(time.Now().Sub(this.scene.GameNowTime).Seconds()) - mq.Write(model.CreatePlayerGameRecEvent(this.SnId, tax, taxex, changeCoin, validbet, validFlow, in, out, - this.scene.GameId, this.scene.GetGameFreeId(), int32(this.scene.GameMode), - this.scene.GetRecordId(), this.Channel, this.ChannelId, this.BeUnderAgentCode, this.Platform, this.City, this.DeviceOS, - this.CreateTime, gamingTime, gameFirstTime, gameFreeFirstTime, gameTimes, gameFreeTimes, this.LastLoginTime, - this.TelephonePromoter, this.DeviceId), mq.BackGameRecord) + isNew := int32(0) + tCreateDay := now.New(this.CreateTime.Local()).BeginningOfDay() + if now.BeginningOfDay().Equal(tCreateDay) { + isNew = 1 + } + + if param.GameTime < 0 { + param.GameTime = int64(time.Now().Sub(this.scene.GameNowTime).Seconds()) + } + if param.GameTime < 0 { + param.GameTime = 0 + } + + log := &model.PlayerGameRecEvent{ + Platform: this.Platform, + RecordId: this.scene.GetRecordId(), + SnId: this.GetSnId(), + Channel: this.Channel, + ChannelId: this.ChannelId, + City: this.City, + OS: this.DeviceOS, + GameId: this.scene.GameId, + ModeId: this.scene.GameMode, + Tax: param.Tax, + Amount: param.Change, + CreateTime: this.CreateTime.Unix(), + CreateDayTime: tCreateDay.Unix(), + Out: param.Out, + In: param.In, + IsNew: isNew, + GameFreeID: this.scene.GetGameFreeId(), + GamingTime: int32(param.GameTime), + FirstTime: gameFirstTime.Unix(), + PlayTimes: gameTimes, + FirstGameTime: gameFreeFirstTime.Unix(), + PlayGameTimes: gameFreeTimes, + LastLoginTime: this.LastLoginTime.Unix(), + DeviceId: this.DeviceId, + } + mq.Write(log, mq.BackGameRecord) } // 汇总玩家该次游戏总产生的税收 diff --git a/gamesrv/base/scene.go b/gamesrv/base/scene.go index a0ca96f..cb10fac 100644 --- a/gamesrv/base/scene.go +++ b/gamesrv/base/scene.go @@ -2,6 +2,7 @@ package base import ( "fmt" + "github.com/globalsign/mgo/bson" "math" "math/rand" "strconv" @@ -87,7 +88,8 @@ type Scene struct { SystemCoinOut int64 //本局游戏机器人营收 机器人赢:正值 机器人输:负值 ChessRank []int32 RealCtrl bool - CycleID string + CycleID string // 房卡场多轮对局id + LogId string // 游戏每局id } func NewScene(args *CreateSceneParam) *Scene { @@ -160,75 +162,104 @@ func (this *Scene) GetGameFreeId() int32 { 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 { - return int(this.WGCreateScene.GetPlayerNum()) + 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 } @@ -236,42 +267,55 @@ func (this *Scene) GetParams() []int64 { 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 } @@ -1403,112 +1447,6 @@ func (this *Scene) ClearAutoPlayer() { } } -type GameDetailedParam struct { - Trend20Lately string //最近20局开奖结果 - CtrlType int - PlayerPool map[int]int - CycleId string -} - -// 保存详细游戏日志 -func (this *Scene) SaveGameDetailedLog(logid string, gamedetailednote string, gameDetailedParam *GameDetailedParam) { - if this != nil { - if !this.Testing { //测试场屏蔽掉 - trend20Lately := gameDetailedParam.Trend20Lately - baseScore := this.GetDBGameFree().GetBaseScore() - if common.IsLocalGame(int(this.GameId)) { - baseScore = this.BaseScore - } - if this.IsCoinScene() { - mapPlatform := make(map[string]bool) - for _, p := range this.Players { - if _, ok := mapPlatform[p.Platform]; !ok { - mapPlatform[p.Platform] = true - log := model.NewGameDetailedLogEx(logid, int32(this.GameId), int32(this.SceneId), - this.GetDBGameFree().GetGameMode(), this.GetDBGameFree().Id, int32(len(this.Players)), - int32(time.Now().Unix()-this.GameNowTime.Unix()), baseScore, - gamedetailednote, p.Platform, this.ClubId, this.RoomId, this.CpCtx, GameDetailedVer[int(this.GameId)], trend20Lately, - gameDetailedParam.CtrlType, gameDetailedParam.PlayerPool, gameDetailedParam.CycleId) - if log != nil { - if this.IsMatchScene() { - log.MatchId = this.GetMatch().GetMatchSortId() - } - if this.IsCustom() { - log.CycleId = this.CycleID - } - mq.Write(log) - } - } - } - } else { - log := model.NewGameDetailedLogEx(logid, int32(this.GameId), int32(this.SceneId), - this.GetDBGameFree().GetGameMode(), this.GetDBGameFree().Id, int32(len(this.Players)), - int32(time.Now().Unix()-this.GameNowTime.Unix()), baseScore, - gamedetailednote, this.Platform, this.ClubId, this.RoomId, this.CpCtx, GameDetailedVer[int(this.GameId)], trend20Lately, - gameDetailedParam.CtrlType, gameDetailedParam.PlayerPool, gameDetailedParam.CycleId) - if log != nil { - if this.IsMatchScene() { - log.MatchId = this.GetMatch().GetMatchSortId() - } - if this.IsCustom() { - log.CycleId = this.CycleID - } - newLog := new(model.GameDetailedLog) - *newLog = *log - mq.Write(log) - } - } - } - } -} - -type SaveGamePlayerListLogParam struct { - Platform string //平台 - Channel string //渠道 - Promoter string //推广员 - PackageTag string //包标识 - InviterId int32 //邀请人 - LogId string //日志id - TotalIn int64 //总投入 - TotalOut int64 //总产出 - TaxCoin int64 //总税收 - ClubPumpCoin int64 //俱乐部抽水 - BetAmount int64 //下注量 - WinAmountNoAnyTax int64 //税后赢取额(净利润,正负值) - ValidBet int64 //有效下注 - ValidFlow int64 //有效流水 - IsFirstGame bool //是否第一次游戏 - IsLeave bool //是否中途离开,用于金花,德州可以中途离开游戏使用 - IsFree bool //拉霸专用 是否免费 - WinSmallGame int64 //拉霸专用 小游戏奖励 - WinTotal int64 //拉霸专用 本局输赢 - PlayerName string //玩家名字 - CycleId string // 房卡场对局id -} - -func GetSaveGamePlayerListLogParam(platform, channel, promoter, packageTag, logid string, - inviterId int32, totalin, totalout, taxCoin, clubPumpCoin, betAmount, winAmountNoAnyTax, validBet, validFlow int64, - isFirstGame, isLeave bool) *SaveGamePlayerListLogParam { - return &SaveGamePlayerListLogParam{ - Platform: platform, - Channel: channel, - Promoter: promoter, - PackageTag: packageTag, - InviterId: inviterId, - LogId: logid, - TotalIn: totalin, - TotalOut: totalout, - TaxCoin: taxCoin, - ClubPumpCoin: clubPumpCoin, - BetAmount: betAmount, - WinAmountNoAnyTax: winAmountNoAnyTax, - ValidBet: validBet, - ValidFlow: validFlow, - IsFirstGame: isFirstGame, - IsLeave: isLeave, - } -} - func (this *Scene) SaveFriendRecord(snid int32, isWin int32, billCoin int64, baseScore int32) { if this.SceneMode == common.SceneModePrivate { return @@ -1519,55 +1457,160 @@ func (this *Scene) SaveFriendRecord(snid int32, isWin int32, billCoin int64, bas } } -// 保存玩家和GameDetailedLog的映射表 -func (this *Scene) SaveGamePlayerListLog(snid int32, param *SaveGamePlayerListLogParam) { - if this != nil { - if !this.Testing { //测试场屏蔽掉 龙虎两边都压,totalin和totalout都=0,这个条件去掉 - //统计流水值 - playerEx := this.GetPlayer(snid) - //有些结算的时候,玩家已经退场,不要用是否在游戏,0709,修改为扣税后数值 - if playerEx != nil && !param.IsLeave && !playerEx.IsRob && (param.IsFree || param.TotalIn != 0 || param.TotalOut != 0) { - totalFlow := param.ValidFlow * int64(this.GetDBGameFree().GetBetWaterRate()) / 100 - playerEx.TotalConvertibleFlow += totalFlow - playerEx.TotalFlow += totalFlow - playerEx.ValidCacheBetTotal += param.ValidBet - //报表统计 - //playerEx.SaveReportForm(int(this.GetDBGameFree().GetGameClass()), this.SceneMode, this.KeyGameId, - // param.WinAmountNoAnyTax, totalFlow, param.ValidBet) - //分配利润 - ProfitDistribution(playerEx, param.TaxCoin, param.ClubPumpCoin, totalFlow) - //上报游戏事件 - playerEx.ReportGameEvent(param.TaxCoin, param.ClubPumpCoin, param.WinAmountNoAnyTax, param.ValidBet, totalFlow, param.TotalIn, param.TotalOut) - } +type SaveGameDetailedParam struct { + LogId string // 日志id + Detail string // 游戏详细信息 + GameTime int64 // 游戏时长 + Trend20Lately string // 最近20局开奖结果 + CtrlType int // 调控类型 1控赢 2控输 + PlayerPool map[int]int // 个人水池分 +} - roomType := int32(this.SceneMode) - if this.GameId == common.GameId_Avengers || - this.GameId == common.GameId_CaiShen || - this.GameId == common.GameId_EasterIsland || - this.GameId == common.GameId_IceAge || - this.GameId == common.GameId_TamQuoc { //复仇者联盟强制为0,所有场次操作记录放一起 - roomType = 0 - } - baseScore := this.GetDBGameFree().GetBaseScore() - if common.IsLocalGame(int(this.GameId)) { - baseScore = this.BaseScore - } - - Name := param.PlayerName - if playerEx != nil { - Name = param.PlayerName - } - - log := model.NewGamePlayerListLogEx(snid, param.LogId, param.Platform, param.Channel, param.Promoter, param.PackageTag, - this.GameId, baseScore, this.SceneId, int32(this.GetGameMode()), - this.GetGameFreeId(), param.TotalIn, param.TotalOut, this.ClubId, this.RoomId, param.TaxCoin, param.ClubPumpCoin, roomType, - param.BetAmount, param.WinAmountNoAnyTax, this.KeyGameId, Name, this.GetDBGameFree().GetGameClass(), - param.IsFirstGame, this.GetMatch().GetMatchSortId(), int64(this.GetMatch().GetMatchType()), param.IsFree, param.WinSmallGame, param.WinTotal, param.CycleId) - if log != nil { - mq.Write(log) - } - } +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 { diff --git a/gamesrv/caishen/scenepolicy_caishen.go b/gamesrv/caishen/scenepolicy_caishen.go index cf4ba08..aa21249 100644 --- a/gamesrv/caishen/scenepolicy_caishen.go +++ b/gamesrv/caishen/scenepolicy_caishen.go @@ -1023,31 +1023,31 @@ func CaiShenCheckAndSaveLog(sceneEx *CaiShenSceneData, playerEx *CaiShenPlayerDa if err == nil { logid, _ := model.AutoIncGameLogId() playerEx.currentLogId = logid - sceneEx.SaveGameDetailedLog(logid, info, &base.GameDetailedParam{}) + sceneEx.SaveGameDetailedLog(&base.SaveGameDetailedParam{ + LogId: logid, + Detail: info, + GameTime: 1, + }) totalin := int64(playerEx.RollGameType.BaseResult.TotalBet) totalout := playerEx.RollGameType.BaseResult.ChangeCoin + playerEx.taxCoin + totalin - validFlow := totalin + totalout - validBet := common.AbsI64(totalin - totalout) - logParam := &base.SaveGamePlayerListLogParam{ - Platform: playerEx.Platform, - Channel: playerEx.Channel, - Promoter: playerEx.BeUnderAgentCode, - PackageTag: playerEx.PackageID, - InviterId: playerEx.InviterId, + sceneEx.SaveGamePlayerListLog(&base.SaveGamePlayerListLogParam{ LogId: logid, + Platform: playerEx.Platform, + Snid: playerEx.SnId, + PlayerName: playerEx.Name, + Channel: playerEx.Channel, + ChannelId: playerEx.ChannelId, TotalIn: totalin, TotalOut: totalout, TaxCoin: playerEx.taxCoin, BetAmount: int64(playerEx.RollGameType.BaseResult.TotalBet), WinAmountNoAnyTax: playerEx.RollGameType.BaseResult.ChangeCoin, - ValidBet: validBet, - ValidFlow: validFlow, IsFirstGame: sceneEx.IsPlayerFirst(playerEx.Player), IsFree: playerEx.RollGameType.BaseResult.IsFree, WinSmallGame: playerEx.RollGameType.BaseResult.WinSmallGame, WinTotal: playerEx.RollGameType.BaseResult.WinTotal, - } - sceneEx.SaveGamePlayerListLog(playerEx.SnId, logParam) + GameTime: 1, + }) } } } diff --git a/gamesrv/chess/scene.go b/gamesrv/chess/scene.go index ad40fdf..00ba0dc 100644 --- a/gamesrv/chess/scene.go +++ b/gamesrv/chess/scene.go @@ -767,6 +767,7 @@ func (e *SceneEx) ToBilled(p1, p2 *PlayerEx, isWin int) (*chesstitians.Chesstiti UserIcon: p1.Head, Platform: p1.Platform, Channel: p1.Channel, + ChannelId: p1.ChannelId, Promoter: p1.BeUnderAgentCode, PackageTag: p1.PackageID, InviterId: p1.InviterId, diff --git a/gamesrv/chess/scenepolicy.go b/gamesrv/chess/scenepolicy.go index 95084c5..116ecdd 100644 --- a/gamesrv/chess/scenepolicy.go +++ b/gamesrv/chess/scenepolicy.go @@ -1298,9 +1298,6 @@ func (this *SceneStateBilled) OnEnter(s *base.Scene) { } else { totalout += (o_player.GainCoin + o_player.GainTaxCoin) } - - validFlow := totalin + totalout - validBet := common.AbsI64(totalin - totalout) sceneEx.SaveFriendRecord(o_player.UserId, o_player.IsWin, o_player.GainCoin, sceneEx.GetBaseScore()) // 游戏数据统计 @@ -1313,16 +1310,29 @@ func (this *SceneStateBilled) OnEnter(s *base.Scene) { }) // 玩家游戏记录 - sceneEx.SaveGamePlayerListLog(o_player.UserId, - base.GetSaveGamePlayerListLogParam(o_player.Platform, o_player.Channel, o_player.Promoter, - o_player.PackageTag, logid, o_player.InviterId, totalin, totalout, o_player.GainTaxCoin, - 0, 0, o_player.GainCoin, validBet, validFlow, o_player.IsFirst, o_player.IsLeave)) + sceneEx.SaveGamePlayerListLog(&base.SaveGamePlayerListLogParam{ + LogId: logid, + Platform: o_player.Platform, + Snid: o_player.UserId, + PlayerName: "", + Channel: o_player.Channel, + ChannelId: o_player.ChannelId, + TotalIn: totalin, + TotalOut: totalout, + TaxCoin: o_player.GainTaxCoin, + BetAmount: 0, + WinAmountNoAnyTax: o_player.GainCoin, + IsFirstGame: o_player.IsFirst, + }) isSave = true } } if isSave { // 牌局记录 - sceneEx.SaveGameDetailedLog(logid, info, &base.GameDetailedParam{}) + sceneEx.SaveGameDetailedLog(&base.SaveGameDetailedParam{ + LogId: logid, + Detail: info, + }) } } sceneEx.NotifySceneRoundPause() diff --git a/gamesrv/clawdoll/scenepolicy_clawdoll.go b/gamesrv/clawdoll/scenepolicy_clawdoll.go index 6b2d895..ce712e3 100644 --- a/gamesrv/clawdoll/scenepolicy_clawdoll.go +++ b/gamesrv/clawdoll/scenepolicy_clawdoll.go @@ -781,34 +781,28 @@ func (this *StateBilled) OnEnter(s *base.Scene) { sceneEx.logid, _ = model.AutoIncGameLogId() info, err := model.MarshalGameNoteByHUNDRED(LogBaseResult) if err == nil { - sceneEx.SaveGameDetailedLog(sceneEx.logid, info, &base.GameDetailedParam{}) + sceneEx.SaveGameDetailedLog(&base.SaveGameDetailedParam{ + LogId: sceneEx.logid, + Detail: info, + }) } TotalBetValue := 0 totalin := int64(TotalBetValue) totalout := playerEx.gainCoin - validFlow := totalin + totalout - validBet := common.AbsI64(totalin - totalout) - logParam := &base.SaveGamePlayerListLogParam{ - Platform: playerEx.Platform, - Channel: playerEx.Channel, - Promoter: playerEx.BeUnderAgentCode, - PackageTag: playerEx.PackageID, - InviterId: playerEx.InviterId, - LogId: sceneEx.logid, - TotalIn: totalin, - TotalOut: totalout, - TaxCoin: playerEx.taxCoin, - BetAmount: int64(TotalBetValue), - WinAmountNoAnyTax: playerEx.gainCoin, - ValidBet: validBet, - ValidFlow: validFlow, - IsFirstGame: sceneEx.IsPlayerFirst(playerEx.Player), - IsFree: false, - WinSmallGame: 0, - WinTotal: 0, - } - sceneEx.SaveGamePlayerListLog(playerEx.SnId, logParam) + sceneEx.SaveGamePlayerListLog(&base.SaveGamePlayerListLogParam{ + LogId: sceneEx.logid, + Platform: playerEx.Platform, + Snid: playerEx.SnId, + PlayerName: playerEx.Name, + Channel: playerEx.Channel, + ChannelId: playerEx.ChannelId, + TotalIn: totalin, + TotalOut: totalout, + TaxCoin: playerEx.taxCoin, + BetAmount: int64(TotalBetValue), + IsFirstGame: sceneEx.IsPlayerFirst(playerEx.Player), + }) } playerEx.lastIsWin = playerEx.IsWin diff --git a/gamesrv/easterisland/scenepolicy_easterisland.go b/gamesrv/easterisland/scenepolicy_easterisland.go index 2474ad4..677d88b 100644 --- a/gamesrv/easterisland/scenepolicy_easterisland.go +++ b/gamesrv/easterisland/scenepolicy_easterisland.go @@ -892,31 +892,31 @@ func EasterIslandCheckAndSaveLog(sceneEx *EasterIslandSceneData, playerEx *Easte if err == nil { logid, _ := model.AutoIncGameLogId() playerEx.currentLogId = logid - sceneEx.SaveGameDetailedLog(logid, info, &base.GameDetailedParam{}) + sceneEx.SaveGameDetailedLog(&base.SaveGameDetailedParam{ + LogId: logid, + Detail: info, + GameTime: 1, + }) totalin := int64(playerEx.RollGameType.BaseResult.TotalBet) totalout := playerEx.RollGameType.BaseResult.ChangeCoin + playerEx.taxCoin + totalin - validFlow := totalin + totalout - validBet := common.AbsI64(totalin - totalout) - logParam := &base.SaveGamePlayerListLogParam{ - Platform: playerEx.Platform, - Channel: playerEx.Channel, - Promoter: playerEx.BeUnderAgentCode, - PackageTag: playerEx.PackageID, - InviterId: playerEx.InviterId, + sceneEx.SaveGamePlayerListLog(&base.SaveGamePlayerListLogParam{ LogId: logid, + Platform: playerEx.Platform, + Snid: playerEx.SnId, + PlayerName: playerEx.Name, + Channel: playerEx.Channel, + ChannelId: playerEx.ChannelId, TotalIn: totalin, TotalOut: totalout, TaxCoin: playerEx.taxCoin, BetAmount: int64(playerEx.RollGameType.BaseResult.TotalBet), WinAmountNoAnyTax: playerEx.RollGameType.BaseResult.ChangeCoin, - ValidBet: validBet, - ValidFlow: validFlow, IsFirstGame: sceneEx.IsPlayerFirst(playerEx.Player), IsFree: playerEx.RollGameType.BaseResult.IsFree, WinSmallGame: playerEx.RollGameType.BaseResult.WinSmallGame, WinTotal: playerEx.RollGameType.BaseResult.WinTotal, - } - sceneEx.SaveGamePlayerListLog(playerEx.SnId, logParam) + GameTime: 1, + }) } } } diff --git a/gamesrv/fishing/playerdata_fishing.go b/gamesrv/fishing/playerdata_fishing.go index cad0291..8e244fa 100644 --- a/gamesrv/fishing/playerdata_fishing.go +++ b/gamesrv/fishing/playerdata_fishing.go @@ -262,13 +262,24 @@ func (this *FishingPlayerData) SaveDetailedLog(s *base.Scene) { info, err := model.MarshalGameNoteByFISH(&fd) if err == nil { logid, _ := model.AutoIncGameLogId() - validFlow := totalin + totalout - validBet := common.AbsI64(totalin - totalout) - param := base.GetSaveGamePlayerListLogParam(this.Platform, this.Channel, this.BeUnderAgentCode, this.PackageID, logid, - this.InviterId, totalin, totalout, int64(this.sTaxCoin), 0, totalin, - totalout, validFlow, validBet, sceneEx.IsPlayerFirst(this.Player), false) - sceneEx.SaveGamePlayerListLog(this.SnId, param) - sceneEx.SaveGameDetailedLog(logid, info, &base.GameDetailedParam{}) + sceneEx.SaveGamePlayerListLog(&base.SaveGamePlayerListLogParam{ + LogId: logid, + Platform: this.Platform, + Snid: this.SnId, + PlayerName: this.Name, + Channel: this.Channel, + ChannelId: this.ChannelId, + TotalIn: totalin, + TotalOut: totalout, + TaxCoin: int64(this.sTaxCoin), + BetAmount: totalin, + WinAmountNoAnyTax: totalout, + IsFirstGame: sceneEx.IsPlayerFirst(this.Player), + }) + sceneEx.SaveGameDetailedLog(&base.SaveGameDetailedParam{ + LogId: logid, + Detail: info, + }) } pack := &server_proto.GWFishRecord{ diff --git a/gamesrv/fortunedragon/scenepolicy_fortunedragon.go b/gamesrv/fortunedragon/scenepolicy_fortunedragon.go index c5fc2d8..cea24a8 100644 --- a/gamesrv/fortunedragon/scenepolicy_fortunedragon.go +++ b/gamesrv/fortunedragon/scenepolicy_fortunedragon.go @@ -512,7 +512,11 @@ func FortuneDragonAndSaveLog(sceneEx *FortuneDragonSceneData, playerEx *FortuneD if err == nil { logid, _ := model.AutoIncGameLogId() playerEx.currentLogId = logid - sceneEx.SaveGameDetailedLog(logid, info, &base.GameDetailedParam{}) + sceneEx.SaveGameDetailedLog(&base.SaveGameDetailedParam{ + LogId: logid, + Detail: info, + GameTime: 1, + }) var totalin, totalout int64 if data.Results[0].FreeStatus == 1 || data.Results[0].FreeNumMax == 0 { totalin = playerEx.totalBet @@ -520,25 +524,22 @@ func FortuneDragonAndSaveLog(sceneEx *FortuneDragonSceneData, playerEx *FortuneD if data.Results[0].FreeStatus == 3 || data.Results[0].FreeNumMax == 0 { totalout = int64(data.RoundReward) + playerEx.taxCoin } - validFlow := totalin + totalout - validBet := common.AbsI64(totalin - totalout) - logParam := &base.SaveGamePlayerListLogParam{ - Platform: playerEx.Platform, - Channel: playerEx.Channel, - Promoter: playerEx.BeUnderAgentCode, - PackageTag: playerEx.PackageID, - InviterId: playerEx.InviterId, + sceneEx.SaveGamePlayerListLog(&base.SaveGamePlayerListLogParam{ LogId: logid, + Platform: playerEx.Platform, + Snid: playerEx.SnId, + PlayerName: playerEx.Name, + Channel: playerEx.Channel, + ChannelId: playerEx.ChannelId, TotalIn: totalin, TotalOut: totalout, TaxCoin: playerEx.taxCoin, BetAmount: totalin, WinAmountNoAnyTax: totalout - totalin - playerEx.taxCoin, - ValidBet: validBet, - ValidFlow: validFlow, IsFirstGame: sceneEx.IsPlayerFirst(playerEx.Player), - } - sceneEx.SaveGamePlayerListLog(playerEx.SnId, logParam) + IsFree: playerEx.isFree, + GameTime: 1, + }) } } diff --git a/gamesrv/fortuneox/scenepolicy_fortuneox.go b/gamesrv/fortuneox/scenepolicy_fortuneox.go index 1e05719..f204c1c 100644 --- a/gamesrv/fortuneox/scenepolicy_fortuneox.go +++ b/gamesrv/fortuneox/scenepolicy_fortuneox.go @@ -517,7 +517,11 @@ func FortuneOxAndSaveLog(sceneEx *FortuneOxSceneData, playerEx *FortuneOxPlayerD if err == nil { logid, _ := model.AutoIncGameLogId() playerEx.currentLogId = logid - sceneEx.SaveGameDetailedLog(logid, info, &base.GameDetailedParam{}) + sceneEx.SaveGameDetailedLog(&base.SaveGameDetailedParam{ + LogId: logid, + Detail: info, + GameTime: 1, + }) var totalin, totalout int64 if data.Results[0].FreeStatus == 1 || data.Results[0].FreeNumMax == 0 { totalin = playerEx.totalBet @@ -525,25 +529,22 @@ func FortuneOxAndSaveLog(sceneEx *FortuneOxSceneData, playerEx *FortuneOxPlayerD if data.Results[0].FreeStatus == 3 || data.Results[0].FreeNumMax == 0 { totalout = int64(data.RoundReward) + playerEx.taxCoin } - validFlow := totalin + totalout - validBet := common.AbsI64(totalin - totalout) - logParam := &base.SaveGamePlayerListLogParam{ - Platform: playerEx.Platform, - Channel: playerEx.Channel, - Promoter: playerEx.BeUnderAgentCode, - PackageTag: playerEx.PackageID, - InviterId: playerEx.InviterId, + sceneEx.SaveGamePlayerListLog(&base.SaveGamePlayerListLogParam{ LogId: logid, + Platform: playerEx.Platform, + Snid: playerEx.SnId, + PlayerName: playerEx.Name, + Channel: playerEx.Channel, + ChannelId: playerEx.ChannelId, TotalIn: totalin, TotalOut: totalout, TaxCoin: playerEx.taxCoin, - BetAmount: playerEx.totalBet, + BetAmount: totalin, WinAmountNoAnyTax: totalout - totalin - playerEx.taxCoin, - ValidBet: validBet, - ValidFlow: validFlow, IsFirstGame: sceneEx.IsPlayerFirst(playerEx.Player), - } - sceneEx.SaveGamePlayerListLog(playerEx.SnId, logParam) + IsFree: totalin == 0, + GameTime: 1, + }) } } diff --git a/gamesrv/fortunerabbit/scenepolicy_fortunerabbit.go b/gamesrv/fortunerabbit/scenepolicy_fortunerabbit.go index 13e788c..738ba3b 100644 --- a/gamesrv/fortunerabbit/scenepolicy_fortunerabbit.go +++ b/gamesrv/fortunerabbit/scenepolicy_fortunerabbit.go @@ -511,7 +511,11 @@ func FortuneRabbitAndSaveLog(sceneEx *FortuneRabbitSceneData, playerEx *FortuneR if err == nil { logid, _ := model.AutoIncGameLogId() playerEx.currentLogId = logid - sceneEx.SaveGameDetailedLog(logid, info, &base.GameDetailedParam{}) + sceneEx.SaveGameDetailedLog(&base.SaveGameDetailedParam{ + LogId: logid, + Detail: info, + GameTime: 1, + }) var totalin, totalout int64 if data.Results[0].FreeStatus == 1 || data.Results[0].FreeNumMax == 0 { totalin = playerEx.totalBet @@ -519,25 +523,22 @@ func FortuneRabbitAndSaveLog(sceneEx *FortuneRabbitSceneData, playerEx *FortuneR if data.Results[0].FreeStatus == 3 || data.Results[0].FreeNumMax == 0 { totalout = int64(data.RoundReward) + playerEx.taxCoin } - validFlow := totalin + totalout - validBet := common.AbsI64(totalin - totalout) - logParam := &base.SaveGamePlayerListLogParam{ - Platform: playerEx.Platform, - Channel: playerEx.Channel, - Promoter: playerEx.BeUnderAgentCode, - PackageTag: playerEx.PackageID, - InviterId: playerEx.InviterId, + sceneEx.SaveGamePlayerListLog(&base.SaveGamePlayerListLogParam{ LogId: logid, + Platform: playerEx.Platform, + Snid: playerEx.SnId, + PlayerName: playerEx.Name, + Channel: playerEx.Channel, + ChannelId: playerEx.ChannelId, TotalIn: totalin, TotalOut: totalout, TaxCoin: playerEx.taxCoin, - BetAmount: playerEx.totalBet, + BetAmount: totalin, WinAmountNoAnyTax: totalout - totalin - playerEx.taxCoin, - ValidBet: validBet, - ValidFlow: validFlow, IsFirstGame: sceneEx.IsPlayerFirst(playerEx.Player), - } - sceneEx.SaveGamePlayerListLog(playerEx.SnId, logParam) + IsFree: playerEx.isFree, + GameTime: 1, + }) } } diff --git a/gamesrv/fortunetiger/scenepolicy_fortunetiger.go b/gamesrv/fortunetiger/scenepolicy_fortunetiger.go index 9edc6be..2c5c11d 100644 --- a/gamesrv/fortunetiger/scenepolicy_fortunetiger.go +++ b/gamesrv/fortunetiger/scenepolicy_fortunetiger.go @@ -514,7 +514,11 @@ func FortuneTigerAndSaveLog(sceneEx *FortuneTigerSceneData, playerEx *FortuneTig if err == nil { logid, _ := model.AutoIncGameLogId() playerEx.currentLogId = logid - sceneEx.SaveGameDetailedLog(logid, info, &base.GameDetailedParam{}) + sceneEx.SaveGameDetailedLog(&base.SaveGameDetailedParam{ + LogId: logid, + Detail: info, + GameTime: 1, + }) var totalin, totalout int64 if data.Results[0].FreeStatus == 1 || data.Results[0].FreeNumMax == 0 { totalin = playerEx.totalBet @@ -522,25 +526,22 @@ func FortuneTigerAndSaveLog(sceneEx *FortuneTigerSceneData, playerEx *FortuneTig if data.Results[0].FreeStatus == 3 || data.Results[0].FreeNumMax == 0 { totalout = int64(data.RoundReward) + playerEx.taxCoin } - validFlow := totalin + totalout - validBet := common.AbsI64(totalin - totalout) - logParam := &base.SaveGamePlayerListLogParam{ - Platform: playerEx.Platform, - Channel: playerEx.Channel, - Promoter: playerEx.BeUnderAgentCode, - PackageTag: playerEx.PackageID, - InviterId: playerEx.InviterId, + sceneEx.SaveGamePlayerListLog(&base.SaveGamePlayerListLogParam{ LogId: logid, + Platform: playerEx.Platform, + Snid: playerEx.SnId, + PlayerName: playerEx.Name, + Channel: playerEx.Channel, + ChannelId: playerEx.ChannelId, TotalIn: totalin, TotalOut: totalout, TaxCoin: playerEx.taxCoin, - BetAmount: playerEx.totalBet, + BetAmount: totalin, WinAmountNoAnyTax: totalout - totalin - playerEx.taxCoin, - ValidBet: validBet, - ValidFlow: validFlow, IsFirstGame: sceneEx.IsPlayerFirst(playerEx.Player), - } - sceneEx.SaveGamePlayerListLog(playerEx.SnId, logParam) + IsFree: totalin == 0, + GameTime: 1, + }) } } diff --git a/gamesrv/fruits/scenedata_fruits.go b/gamesrv/fruits/scenedata_fruits.go index 94f20de..8280e92 100644 --- a/gamesrv/fruits/scenedata_fruits.go +++ b/gamesrv/fruits/scenedata_fruits.go @@ -326,7 +326,11 @@ func (s *FruitsSceneData) SaveLog(p *FruitsPlayerData, isOffline int) { info, err := model.MarshalGameNoteByROLL(&FruitsType) if err == nil { logId, _ := model.AutoIncGameLogId() - s.SaveGameDetailedLog(logId, info, &base.GameDetailedParam{}) + s.SaveGameDetailedLog(&base.SaveGameDetailedParam{ + LogId: logId, + Detail: info, + GameTime: 1, + }) //水池上下文环境s s.CpCtx = p.cpCtx var totalIn, totalOut int64 @@ -336,22 +340,22 @@ func (s *FruitsSceneData) SaveLog(p *FruitsPlayerData, isOffline int) { if nowGetCoin > 0 && isF { totalOut = p.Coin - p.startCoin + betCoin /*+ p.taxCoin*/ } - s.SaveGamePlayerListLog(p.SnId, - &base.SaveGamePlayerListLogParam{ - Platform: p.Platform, - Channel: p.Channel, - Promoter: p.BeUnderAgentCode, - PackageTag: p.PackageID, - InviterId: p.InviterId, - LogId: logId, - TotalIn: totalIn, - TotalOut: totalOut, - TaxCoin: p.taxCoin, - ClubPumpCoin: 0, - BetAmount: totalIn, - WinAmountNoAnyTax: p.Coin - p.startCoin, - IsFirstGame: s.IsPlayerFirst(p.Player), - }) + s.SaveGamePlayerListLog(&base.SaveGamePlayerListLogParam{ + LogId: logId, + Platform: p.Platform, + Snid: p.SnId, + PlayerName: p.Name, + Channel: p.Channel, + ChannelId: p.ChannelId, + TotalIn: totalIn, + TotalOut: totalOut, + TaxCoin: p.taxCoin, + BetAmount: totalIn, + WinAmountNoAnyTax: p.Coin - p.startCoin, + IsFirstGame: s.IsPlayerFirst(p.Player), + IsFree: totalIn == 0, + GameTime: 1, + }) } s.GameNowTime = time.Now() if s.CheckNeedDestroy() && p.freeTimes == 0 && p.maryFreeTimes == 0 { diff --git a/gamesrv/iceage/scenepolicy_iceage.go b/gamesrv/iceage/scenepolicy_iceage.go index be0ebff..787d74f 100644 --- a/gamesrv/iceage/scenepolicy_iceage.go +++ b/gamesrv/iceage/scenepolicy_iceage.go @@ -942,31 +942,31 @@ func IceAgeCheckAndSaveLog(sceneEx *IceAgeSceneData, playerEx *IceAgePlayerData) if err == nil { logid, _ := model.AutoIncGameLogId() playerEx.currentLogId = logid - sceneEx.SaveGameDetailedLog(logid, info, &base.GameDetailedParam{}) + sceneEx.SaveGameDetailedLog(&base.SaveGameDetailedParam{ + LogId: logid, + Detail: info, + GameTime: 1, + }) totalin := int64(playerEx.RollGameType.BaseResult.TotalBet) totalout := playerEx.RollGameType.BaseResult.ChangeCoin + playerEx.taxCoin + totalin - validFlow := totalin + totalout - validBet := common.AbsI64(totalin - totalout) - logParam := &base.SaveGamePlayerListLogParam{ - Platform: playerEx.Platform, - Channel: playerEx.Channel, - Promoter: playerEx.BeUnderAgentCode, - PackageTag: playerEx.PackageID, - InviterId: playerEx.InviterId, + sceneEx.SaveGamePlayerListLog(&base.SaveGamePlayerListLogParam{ LogId: logid, + Platform: playerEx.Platform, + Snid: playerEx.SnId, + PlayerName: playerEx.Name, + Channel: playerEx.Channel, + ChannelId: playerEx.ChannelId, TotalIn: totalin, TotalOut: totalout, TaxCoin: playerEx.taxCoin, BetAmount: int64(playerEx.RollGameType.BaseResult.TotalBet), WinAmountNoAnyTax: playerEx.RollGameType.BaseResult.ChangeCoin, - ValidBet: validBet, - ValidFlow: validFlow, IsFirstGame: sceneEx.IsPlayerFirst(playerEx.Player), IsFree: playerEx.RollGameType.BaseResult.IsFree, WinSmallGame: playerEx.RollGameType.BaseResult.WinSmallGame, WinTotal: playerEx.RollGameType.BaseResult.WinTotal, - } - sceneEx.SaveGamePlayerListLog(playerEx.SnId, logParam) + GameTime: 1, + }) } } } diff --git a/gamesrv/richblessed/scenedata_richblessed.go b/gamesrv/richblessed/scenedata_richblessed.go index 9d31d45..957fc1c 100644 --- a/gamesrv/richblessed/scenedata_richblessed.go +++ b/gamesrv/richblessed/scenedata_richblessed.go @@ -348,7 +348,11 @@ func (s *RichBlessedSceneData) SaveLog(p *RichBlessedPlayerData, isOffline int) info, err := model.MarshalGameNoteByROLL(&RichBlessed) if err == nil { logId, _ := model.AutoIncGameLogId() - s.SaveGameDetailedLog(logId, info, &base.GameDetailedParam{}) + s.SaveGameDetailedLog(&base.SaveGameDetailedParam{ + LogId: logId, + Detail: info, + GameTime: 1, + }) //水池上下文环境s s.CpCtx = p.cpCtx var totalIn, totalOut int64 @@ -358,22 +362,22 @@ func (s *RichBlessedSceneData) SaveLog(p *RichBlessedPlayerData, isOffline int) if nowGetCoin > 0 { totalOut = p.Coin - p.startCoin + betCoin /*+ p.taxCoin*/ } - s.SaveGamePlayerListLog(p.SnId, - &base.SaveGamePlayerListLogParam{ - Platform: p.Platform, - Channel: p.Channel, - Promoter: p.BeUnderAgentCode, - PackageTag: p.PackageID, - InviterId: p.InviterId, - LogId: logId, - TotalIn: totalIn, - TotalOut: totalOut, - TaxCoin: p.taxCoin, - ClubPumpCoin: 0, - BetAmount: totalIn, - WinAmountNoAnyTax: p.Coin - p.startCoin, - IsFirstGame: s.IsPlayerFirst(p.Player), - }) + s.SaveGamePlayerListLog(&base.SaveGamePlayerListLogParam{ + LogId: logId, + Platform: p.Platform, + Snid: p.SnId, + PlayerName: p.Name, + Channel: p.Channel, + ChannelId: p.ChannelId, + TotalIn: totalIn, + TotalOut: totalOut, + TaxCoin: p.taxCoin, + BetAmount: totalIn, + WinAmountNoAnyTax: p.Coin - p.startCoin, + IsFirstGame: s.IsPlayerFirst(p.Player), + IsFree: totalIn == 0, + GameTime: 1, + }) } s.GameNowTime = time.Now() if s.CheckNeedDestroy() && p.freeTimes == 0 { diff --git a/gamesrv/smallrocket/scene.go b/gamesrv/smallrocket/scene.go index d7fec18..d329343 100644 --- a/gamesrv/smallrocket/scene.go +++ b/gamesrv/smallrocket/scene.go @@ -33,6 +33,7 @@ type PlayerData struct { Platform string //平台 Channel string //渠道信息 + ChannelId string PackageID string //推广包标识 对应客户端的packagetag flag int } @@ -333,6 +334,7 @@ func (this *SceneEx) BackupPlayer(p *PlayerEx, isBilled bool) { flag: p.GetFlag(), Platform: p.Platform, Channel: p.Channel, + ChannelId: p.ChannelId, PackageID: p.PackageID, CurIsWin: p.CurIsWin, Name: p.Name, diff --git a/gamesrv/smallrocket/scenepolicy.go b/gamesrv/smallrocket/scenepolicy.go index d690fda..cfe3367 100644 --- a/gamesrv/smallrocket/scenepolicy.go +++ b/gamesrv/smallrocket/scenepolicy.go @@ -1166,33 +1166,28 @@ func (this *StateBilled) OnEnter(s *base.Scene) { if !playerEx.IsRob { info, err := model.MarshalGameNoteByHUNDRED(LogBaseResult) if err == nil { - sceneEx.SaveGameDetailedLog(sceneEx.logid, info, &base.GameDetailedParam{}) + sceneEx.SaveGameDetailedLog(&base.SaveGameDetailedParam{ + LogId: sceneEx.logid, + Detail: info, + }) } totalin := int64(TotalBetValue) totalout := playerEx.gainCoin - validFlow := totalin + totalout - validBet := common.AbsI64(totalin - totalout) - logParam := &base.SaveGamePlayerListLogParam{ - Platform: playerEx.Platform, - Channel: playerEx.Channel, - Promoter: playerEx.BeUnderAgentCode, - PackageTag: playerEx.PackageID, - InviterId: playerEx.InviterId, + sceneEx.SaveGamePlayerListLog(&base.SaveGamePlayerListLogParam{ LogId: sceneEx.logid, + Platform: playerEx.Platform, + Snid: playerEx.SnId, + PlayerName: playerEx.Name, + Channel: playerEx.Channel, + ChannelId: playerEx.ChannelId, TotalIn: totalin, TotalOut: totalout, TaxCoin: playerEx.taxCoin, BetAmount: int64(TotalBetValue), WinAmountNoAnyTax: playerEx.gainCoin, - ValidBet: validBet, - ValidFlow: validFlow, - IsFirstGame: sceneEx.IsPlayerFirst(playerEx.Player), - IsFree: false, - WinSmallGame: 0, - WinTotal: 0, - } - sceneEx.SaveGamePlayerListLog(playerEx.SnId, logParam) + IsFirstGame: s.IsPlayerFirst(playerEx.Player), + }) } } @@ -1248,34 +1243,30 @@ func (this *StateBilled) OnEnter(s *base.Scene) { if !playerEx.IsRob { info, err := model.MarshalGameNoteByHUNDRED(LogBaseResult) if err == nil { - sceneEx.SaveGameDetailedLog(sceneEx.logid, info, &base.GameDetailedParam{}) + sceneEx.SaveGameDetailedLog(&base.SaveGameDetailedParam{ + LogId: sceneEx.logid, + Detail: info, + }) } totalin := int64(TotalBetValue) totalout := playerEx.gainCoin - validFlow := totalin + totalout - validBet := common.AbsI64(totalin - totalout) - logParam := &base.SaveGamePlayerListLogParam{ - Platform: playerEx.Platform, - Channel: playerEx.Channel, - Promoter: playerEx.BeUnderAgentCode, - PackageTag: playerEx.PackageID, - InviterId: playerEx.InviterId, + //validFlow := totalin + totalout + //validBet := common.AbsI64(totalin - totalout) + sceneEx.SaveGamePlayerListLog(&base.SaveGamePlayerListLogParam{ LogId: sceneEx.logid, + Platform: playerEx.Platform, + Snid: playerEx.SnId, + PlayerName: playerEx.Name, + Channel: playerEx.Channel, + ChannelId: playerEx.ChannelId, TotalIn: totalin, TotalOut: totalout, TaxCoin: playerEx.taxCoin, BetAmount: int64(TotalBetValue), WinAmountNoAnyTax: playerEx.gainCoin, - ValidBet: validBet, - ValidFlow: validFlow, IsFirstGame: playerEx.IsPlayerFirst, - IsFree: false, - WinSmallGame: 0, - WinTotal: 0, - PlayerName: playerEx.Name, - } - sceneEx.SaveGamePlayerListLog(playerEx.SnId, logParam) + }) } } } diff --git a/gamesrv/tamquoc/scenepolicy_tamquoc.go b/gamesrv/tamquoc/scenepolicy_tamquoc.go index a3495d7..2a57d3b 100644 --- a/gamesrv/tamquoc/scenepolicy_tamquoc.go +++ b/gamesrv/tamquoc/scenepolicy_tamquoc.go @@ -778,31 +778,31 @@ func TamQuocCheckAndSaveLog(sceneEx *TamQuocSceneData, playerEx *TamQuocPlayerDa if err == nil { logid, _ := model.AutoIncGameLogId() playerEx.currentLogId = logid - sceneEx.SaveGameDetailedLog(logid, info, &base.GameDetailedParam{}) + sceneEx.SaveGameDetailedLog(&base.SaveGameDetailedParam{ + LogId: logid, + Detail: info, + GameTime: 1, + }) totalin := int64(playerEx.RollGameType.BaseResult.TotalBet) totalout := playerEx.RollGameType.BaseResult.ChangeCoin + playerEx.taxCoin + totalin - validFlow := totalin + totalout - validBet := common.AbsI64(totalin - totalout) - logParam := &base.SaveGamePlayerListLogParam{ - Platform: playerEx.Platform, - Channel: playerEx.Channel, - Promoter: playerEx.BeUnderAgentCode, - PackageTag: playerEx.PackageID, - InviterId: playerEx.InviterId, + sceneEx.SaveGamePlayerListLog(&base.SaveGamePlayerListLogParam{ LogId: logid, + Platform: playerEx.Platform, + Snid: playerEx.SnId, + PlayerName: playerEx.Name, + Channel: playerEx.Channel, + ChannelId: playerEx.ChannelId, TotalIn: totalin, TotalOut: totalout, TaxCoin: playerEx.taxCoin, BetAmount: int64(playerEx.RollGameType.BaseResult.TotalBet), WinAmountNoAnyTax: playerEx.RollGameType.BaseResult.ChangeCoin, - ValidBet: validBet, - ValidFlow: validFlow, IsFirstGame: sceneEx.IsPlayerFirst(playerEx.Player), IsFree: playerEx.RollGameType.BaseResult.IsFree, WinSmallGame: playerEx.RollGameType.BaseResult.WinSmallGame, WinTotal: playerEx.RollGameType.BaseResult.WinTotal, - } - sceneEx.SaveGamePlayerListLog(playerEx.SnId, logParam) + GameTime: 1, + }) } } } diff --git a/gamesrv/thirteen/scenepolicy.go b/gamesrv/thirteen/scenepolicy.go index 775faa0..b7a3fd9 100644 --- a/gamesrv/thirteen/scenepolicy.go +++ b/gamesrv/thirteen/scenepolicy.go @@ -181,11 +181,22 @@ func (this *PolicyThirteen) OnPlayerLeave(s *base.Scene, p *base.Player, reason } else { totalin -= playerEx.gainCoin } - validFlow := totalin + totalout - validBet := common.AbsI64(totalin - totalout) - sceneEx.SaveGamePlayerListLog(playerEx.SnId, base.GetSaveGamePlayerListLogParam(playerEx.Platform, playerEx.Channel, playerEx.BeUnderAgentCode, - playerEx.PackageID, sceneEx.logid, playerEx.InviterId, totalin, totalout, playerEx.taxCoin, - 0, 0, playerEx.gainCoin, validBet, validFlow, sceneEx.IsPlayerFirst(sceneEx.GetPlayer(playerEx.SnId)), false)) + //validFlow := totalin + totalout + //validBet := common.AbsI64(totalin - totalout) + sceneEx.SaveGamePlayerListLog(&base.SaveGamePlayerListLogParam{ + LogId: sceneEx.logid, + Platform: playerEx.Platform, + Snid: playerEx.SnId, + PlayerName: playerEx.Name, + Channel: playerEx.Channel, + ChannelId: playerEx.ChannelId, + TotalIn: totalin, + TotalOut: totalout, + TaxCoin: playerEx.taxCoin, + BetAmount: 0, + WinAmountNoAnyTax: playerEx.gainCoin, + IsFirstGame: sceneEx.IsPlayerFirst(sceneEx.GetPlayer(playerEx.SnId)), + }) sceneEx.Statistics(&base.StaticParam{ SnId: playerEx.SnId, @@ -1390,11 +1401,20 @@ func (this *StateBilled) OnEnter(s *base.Scene) { } else { totalin -= o_player.gainCoin } - validFlow := totalin + totalout - validBet := common.AbsI64(totalin - totalout) - sceneEx.SaveGamePlayerListLog(o_player.SnId, base.GetSaveGamePlayerListLogParam(o_player.Platform, o_player.Channel, o_player.BeUnderAgentCode, - o_player.PackageID, sceneEx.logid, o_player.InviterId, totalin, totalout, o_player.taxCoin, - 0, 0, o_player.gainCoin, validBet, validFlow, p.IsFirst, false)) + sceneEx.SaveGamePlayerListLog(&base.SaveGamePlayerListLogParam{ + LogId: sceneEx.logid, + Platform: o_player.Platform, + Snid: o_player.SnId, + PlayerName: o_player.Name, + Channel: o_player.Channel, + ChannelId: o_player.ChannelId, + TotalIn: totalin, + TotalOut: totalout, + TaxCoin: o_player.taxCoin, + BetAmount: 0, + WinAmountNoAnyTax: o_player.gainCoin, + IsFirstGame: p.IsFirst, + }) } } } @@ -1453,10 +1473,11 @@ func (this *StateBilled) OnEnter(s *base.Scene) { thirteenWaterType.PlayerCount = len(person) info, err := model.MarshalGameNoteByFIGHT(&thirteenWaterType) if err == nil { - sceneEx.SaveGameDetailedLog(sceneEx.logid, info, &base.GameDetailedParam{ - Trend20Lately: "", - CtrlType: sceneEx.ctrlType, - PlayerPool: playerPool, + sceneEx.SaveGameDetailedLog(&base.SaveGameDetailedParam{ + LogId: sceneEx.logid, + Detail: info, + CtrlType: sceneEx.ctrlType, + PlayerPool: playerPool, }) } } diff --git a/gamesrv/tienlen/scenepolicy_tienlen.go b/gamesrv/tienlen/scenepolicy_tienlen.go index 5a249ae..2f29da4 100644 --- a/gamesrv/tienlen/scenepolicy_tienlen.go +++ b/gamesrv/tienlen/scenepolicy_tienlen.go @@ -1737,6 +1737,7 @@ func (this *SceneBilledStateTienLen) OnEnter(s *base.Scene) { UserIcon: playerEx.Head, Platform: playerEx.Platform, Channel: playerEx.Channel, + ChannelId: playerEx.ChannelId, Promoter: playerEx.BeUnderAgentCode, PackageTag: playerEx.PackageID, InviterId: playerEx.InviterId, @@ -1888,6 +1889,7 @@ func (this *SceneBilledStateTienLen) OnEnter(s *base.Scene) { UserIcon: losePlayer.Head, Platform: losePlayer.Platform, Channel: losePlayer.Channel, + ChannelId: losePlayer.ChannelId, Promoter: losePlayer.BeUnderAgentCode, PackageTag: losePlayer.PackageID, InviterId: losePlayer.InviterId, @@ -2030,6 +2032,7 @@ func (this *SceneBilledStateTienLen) OnEnter(s *base.Scene) { UserIcon: lastWinPlayer.Head, Platform: lastWinPlayer.Platform, Channel: lastWinPlayer.Channel, + ChannelId: lastWinPlayer.ChannelId, Promoter: lastWinPlayer.BeUnderAgentCode, PackageTag: lastWinPlayer.PackageID, InviterId: lastWinPlayer.InviterId, @@ -2141,6 +2144,7 @@ func (this *SceneBilledStateTienLen) OnEnter(s *base.Scene) { UserIcon: playerEx.Head, Platform: playerEx.Platform, Channel: playerEx.Channel, + ChannelId: playerEx.ChannelId, Promoter: playerEx.BeUnderAgentCode, PackageTag: playerEx.PackageID, InviterId: playerEx.InviterId, @@ -2246,6 +2250,7 @@ func (this *SceneBilledStateTienLen) OnEnter(s *base.Scene) { UserIcon: playerEx.Head, Platform: playerEx.Platform, Channel: playerEx.Channel, + ChannelId: playerEx.ChannelId, Promoter: playerEx.BeUnderAgentCode, PackageTag: playerEx.PackageID, InviterId: playerEx.InviterId, @@ -2397,6 +2402,7 @@ func (this *SceneBilledStateTienLen) OnEnter(s *base.Scene) { UserIcon: playerEx.Head, Platform: playerEx.Platform, Channel: playerEx.Channel, + ChannelId: playerEx.ChannelId, Promoter: playerEx.BeUnderAgentCode, PackageTag: playerEx.PackageID, InviterId: playerEx.InviterId, @@ -2527,6 +2533,7 @@ func (this *SceneBilledStateTienLen) OnEnter(s *base.Scene) { UserIcon: playerEx.Head, Platform: playerEx.Platform, Channel: playerEx.Channel, + ChannelId: playerEx.ChannelId, Promoter: playerEx.BeUnderAgentCode, PackageTag: playerEx.PackageID, InviterId: playerEx.InviterId, @@ -2729,8 +2736,6 @@ func (this *SceneBilledStateTienLen) OnEnter(s *base.Scene) { playerEx.UpdatePigBankCoin(o_player.GainCoin) } - validFlow := totalin + totalout - validBet := common.AbsI64(totalin - totalout) sceneEx.SaveFriendRecord(o_player.UserId, o_player.IsWin, o_player.BillCoin, sceneEx.GetBaseScore()) // 玩家数据统计 @@ -2752,20 +2757,29 @@ func (this *SceneBilledStateTienLen) OnEnter(s *base.Scene) { }) // 保存玩家游戏记录 - param := base.GetSaveGamePlayerListLogParam(o_player.Platform, o_player.Channel, o_player.Promoter, - o_player.PackageTag, sceneEx.recordId, o_player.InviterId, totalin, totalout, o_player.BillTaxCoin, - 0, 0, o_player.GainCoin+o_player.BombCoin, validBet, validFlow, o_player.IsFirst, o_player.IsLeave) - param.CycleId = sceneEx.CycleID - sceneEx.SaveGamePlayerListLog(o_player.UserId, param) + sceneEx.SaveGamePlayerListLog(&base.SaveGamePlayerListLogParam{ + LogId: sceneEx.recordId, + Platform: o_player.Platform, + Snid: o_player.UserId, + Channel: o_player.Channel, + ChannelId: o_player.ChannelId, + TotalIn: totalin, + TotalOut: totalout, + TaxCoin: o_player.BillTaxCoin, + BetAmount: 0, + WinAmountNoAnyTax: o_player.GainCoin + o_player.BombCoin, + IsFirstGame: o_player.IsFirst, + }) } } if isSave { // 牌局记录 - sceneEx.SaveGameDetailedLog(sceneEx.recordId, info, &base.GameDetailedParam{ + sceneEx.SaveGameDetailedLog(&base.SaveGameDetailedParam{ + LogId: sceneEx.recordId, + Detail: info, Trend20Lately: "", CtrlType: sceneEx.ctrlType, PlayerPool: tienlenType.PlayerPool, - CycleId: sceneEx.CycleID, }) } } diff --git a/model/dataevent.go b/model/dataevent.go index 3cb9070..b3d138f 100644 --- a/model/dataevent.go +++ b/model/dataevent.go @@ -275,49 +275,6 @@ type PlayerGameRecEvent struct { ChannelId string //推广渠道id } -func CreatePlayerGameRecEvent(snid int32, tax, taxex, amount, validbet, validflow, in, out int64, gameid, gameFreeId, modeid int32, recordId, channel, channelId, promoter, - platform, city, os string, createDayTime time.Time, gamingTime int32, firstGameFreeTime, firstGameTime time.Time, - playGameFreeTimes, playerGameTimes int64, lastLoginTime time.Time, teleponePromoter int32, deviceId string) *PlayerGameRecEvent { - isNewbie := int32(0) - tCreateDay := now.New(createDayTime).BeginningOfDay() - if now.BeginningOfDay().Equal(tCreateDay) { - isNewbie = 1 - } - if gamingTime < 0 { - gamingTime = 0 - } - return &PlayerGameRecEvent{RecordId: recordId, - SnId: snid, - Channel: channel, - Promoter: promoter, - TelephonePromoter: teleponePromoter, - Platform: platform, - City: city, - OS: os, - GameId: gameid, - ModeId: modeid, - Tax: tax, - //Taxex: taxex, - Amount: amount, - ValidBet: validbet, - ValidFlow: validflow, - In: in, - Out: out, - CreateTime: time.Now().Local().Unix(), - CreateDayTime: tCreateDay.Local().Unix(), - IsNew: isNewbie, - GameFreeID: gameFreeId, - GamingTime: gamingTime, - FirstTime: firstGameFreeTime.Unix(), - FirstGameTime: firstGameTime.Unix(), - PlayTimes: playGameFreeTimes, - PlayGameTimes: playerGameTimes, - LastLoginTime: lastLoginTime.Unix(), - DeviceId: deviceId, - ChannelId: channelId, - } -} - // 玩家游戏记录 //type PlayerGameRecPayEvent struct { // SnId int32 //用户ID diff --git a/model/gamelogtype.go b/model/gamelogtype.go index 0d9b998..4ca1a01 100644 --- a/model/gamelogtype.go +++ b/model/gamelogtype.go @@ -1536,6 +1536,7 @@ type TienLenPerson struct { UserIcon int32 //玩家头像 Platform string `json:"-"` Channel string `json:"-"` + ChannelId string `json:"-"` Promoter string `json:"-"` PackageTag string `json:"-"` InviterId int32 `json:"-"` @@ -1581,6 +1582,7 @@ type ChesstitiansPerson struct { UserIcon int32 //玩家头像 Platform string `json:"-"` Channel string `json:"-"` + ChannelId string `json:"-"` Promoter string `json:"-"` PackageTag string `json:"-"` InviterId int32 `json:"-"` diff --git a/model/gameplayerlistlog.go b/model/gameplayerlistlog.go index 4441b2d..9d06b23 100644 --- a/model/gameplayerlistlog.go +++ b/model/gameplayerlistlog.go @@ -51,7 +51,7 @@ type GamePlayerListLog struct { GameClass int32 //游戏类型 1棋牌 2电子 3百人 4捕鱼 5视讯 6彩票 7体育 MatchId int64 MatchType int64 //0.普通场 1.锦标赛 2.冠军赛 3.vip专属 - Ts int32 + Ts int64 IsFree bool //拉霸专用 是否免费 WinSmallGame int64 //拉霸专用 小游戏奖励 WinTotal int64 //拉霸专用 输赢 @@ -95,7 +95,7 @@ func NewGamePlayerListLogEx(snid int32, gamedetailedlogid string, platform, chan cl.WinSmallGame = winSmallGame cl.WinTotal = winTotal tNow := time.Now() - cl.Ts = int32(tNow.Unix()) + cl.Ts = tNow.Unix() cl.Time = tNow cl.MatchId = matchid cl.MatchType = matchType From fbc14799c11131c7f625d373c813b8410762e9eb Mon Sep 17 00:00:00 2001 From: sk <123456@qq.com> Date: Mon, 2 Dec 2024 13:44:26 +0800 Subject: [PATCH 10/41] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E7=89=8C=E5=B1=80?= =?UTF-8?q?=E8=AE=B0=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gamesrv/avengers/scenepolicy_avengers.go | 4 ++-- gamesrv/caishen/scenepolicy_caishen.go | 4 ++-- gamesrv/easterisland/scenepolicy_easterisland.go | 4 ++-- gamesrv/fortunedragon/scenepolicy_fortunedragon.go | 5 +++-- gamesrv/fortuneox/scenepolicy_fortuneox.go | 5 +++-- gamesrv/fortunerabbit/scenepolicy_fortunerabbit.go | 5 +++-- gamesrv/fortunetiger/scenepolicy_fortunetiger.go | 5 +++-- gamesrv/fruits/scenedata_fruits.go | 4 ++-- gamesrv/iceage/scenepolicy_iceage.go | 4 ++-- gamesrv/richblessed/scenedata_richblessed.go | 4 ++-- gamesrv/tamquoc/scenepolicy_tamquoc.go | 4 ++-- 11 files changed, 26 insertions(+), 22 deletions(-) diff --git a/gamesrv/avengers/scenepolicy_avengers.go b/gamesrv/avengers/scenepolicy_avengers.go index c9334c3..abb1ed2 100644 --- a/gamesrv/avengers/scenepolicy_avengers.go +++ b/gamesrv/avengers/scenepolicy_avengers.go @@ -937,7 +937,7 @@ func AvengersCheckAndSaveLog(sceneEx *AvengersSceneData, playerEx *AvengersPlaye sceneEx.SaveGameDetailedLog(&base.SaveGameDetailedParam{ LogId: logid, Detail: info, - GameTime: 1, + GameTime: 2, }) totalin := int64(playerEx.RollGameType.BaseResult.TotalBet) totalout := playerEx.RollGameType.BaseResult.ChangeCoin + playerEx.taxCoin + totalin @@ -956,7 +956,7 @@ func AvengersCheckAndSaveLog(sceneEx *AvengersSceneData, playerEx *AvengersPlaye IsFree: playerEx.RollGameType.BaseResult.IsFree, WinSmallGame: playerEx.RollGameType.BaseResult.WinSmallGame, WinTotal: playerEx.RollGameType.BaseResult.WinTotal, - GameTime: 1, + GameTime: 2, }) } } diff --git a/gamesrv/caishen/scenepolicy_caishen.go b/gamesrv/caishen/scenepolicy_caishen.go index aa21249..b227c93 100644 --- a/gamesrv/caishen/scenepolicy_caishen.go +++ b/gamesrv/caishen/scenepolicy_caishen.go @@ -1026,7 +1026,7 @@ func CaiShenCheckAndSaveLog(sceneEx *CaiShenSceneData, playerEx *CaiShenPlayerDa sceneEx.SaveGameDetailedLog(&base.SaveGameDetailedParam{ LogId: logid, Detail: info, - GameTime: 1, + GameTime: 2, }) totalin := int64(playerEx.RollGameType.BaseResult.TotalBet) totalout := playerEx.RollGameType.BaseResult.ChangeCoin + playerEx.taxCoin + totalin @@ -1046,7 +1046,7 @@ func CaiShenCheckAndSaveLog(sceneEx *CaiShenSceneData, playerEx *CaiShenPlayerDa IsFree: playerEx.RollGameType.BaseResult.IsFree, WinSmallGame: playerEx.RollGameType.BaseResult.WinSmallGame, WinTotal: playerEx.RollGameType.BaseResult.WinTotal, - GameTime: 1, + GameTime: 2, }) } } diff --git a/gamesrv/easterisland/scenepolicy_easterisland.go b/gamesrv/easterisland/scenepolicy_easterisland.go index 677d88b..0b19dde 100644 --- a/gamesrv/easterisland/scenepolicy_easterisland.go +++ b/gamesrv/easterisland/scenepolicy_easterisland.go @@ -895,7 +895,7 @@ func EasterIslandCheckAndSaveLog(sceneEx *EasterIslandSceneData, playerEx *Easte sceneEx.SaveGameDetailedLog(&base.SaveGameDetailedParam{ LogId: logid, Detail: info, - GameTime: 1, + GameTime: 2, }) totalin := int64(playerEx.RollGameType.BaseResult.TotalBet) totalout := playerEx.RollGameType.BaseResult.ChangeCoin + playerEx.taxCoin + totalin @@ -915,7 +915,7 @@ func EasterIslandCheckAndSaveLog(sceneEx *EasterIslandSceneData, playerEx *Easte IsFree: playerEx.RollGameType.BaseResult.IsFree, WinSmallGame: playerEx.RollGameType.BaseResult.WinSmallGame, WinTotal: playerEx.RollGameType.BaseResult.WinTotal, - GameTime: 1, + GameTime: 2, }) } } diff --git a/gamesrv/fortunedragon/scenepolicy_fortunedragon.go b/gamesrv/fortunedragon/scenepolicy_fortunedragon.go index cea24a8..59b2784 100644 --- a/gamesrv/fortunedragon/scenepolicy_fortunedragon.go +++ b/gamesrv/fortunedragon/scenepolicy_fortunedragon.go @@ -407,6 +407,7 @@ func (this *SceneStateStartFortuneDragon) OnPlayerOp(s *base.Scene, p *base.Play var gameEndStr string var data assemble.GameEnd if err == nil { + s.SetGameNowTime(time.Now()) data = assemble.DataToCli(Response).(assemble.GameEnd) if data.Results[0].FreeStatus == 1 || data.Results[0].FreeNumMax == 0 { //logger.Logger.Trace("=====================AddCoin=====TotalBet===", -data.TotalBet) @@ -515,7 +516,7 @@ func FortuneDragonAndSaveLog(sceneEx *FortuneDragonSceneData, playerEx *FortuneD sceneEx.SaveGameDetailedLog(&base.SaveGameDetailedParam{ LogId: logid, Detail: info, - GameTime: 1, + GameTime: 2, }) var totalin, totalout int64 if data.Results[0].FreeStatus == 1 || data.Results[0].FreeNumMax == 0 { @@ -538,7 +539,7 @@ func FortuneDragonAndSaveLog(sceneEx *FortuneDragonSceneData, playerEx *FortuneD WinAmountNoAnyTax: totalout - totalin - playerEx.taxCoin, IsFirstGame: sceneEx.IsPlayerFirst(playerEx.Player), IsFree: playerEx.isFree, - GameTime: 1, + GameTime: 2, }) } } diff --git a/gamesrv/fortuneox/scenepolicy_fortuneox.go b/gamesrv/fortuneox/scenepolicy_fortuneox.go index f204c1c..0cc788d 100644 --- a/gamesrv/fortuneox/scenepolicy_fortuneox.go +++ b/gamesrv/fortuneox/scenepolicy_fortuneox.go @@ -405,6 +405,7 @@ func (this *SceneStateStartFortuneOx) OnPlayerOp(s *base.Scene, p *base.Player, var gameEndStr string var data assemble.GameEnd if err == nil { + s.SetGameNowTime(time.Now()) data = assemble.DataToCli(Response).(assemble.GameEnd) var respinStatus int if data.Results[0].ArrSpins[0].Special != nil { @@ -520,7 +521,7 @@ func FortuneOxAndSaveLog(sceneEx *FortuneOxSceneData, playerEx *FortuneOxPlayerD sceneEx.SaveGameDetailedLog(&base.SaveGameDetailedParam{ LogId: logid, Detail: info, - GameTime: 1, + GameTime: 2, }) var totalin, totalout int64 if data.Results[0].FreeStatus == 1 || data.Results[0].FreeNumMax == 0 { @@ -543,7 +544,7 @@ func FortuneOxAndSaveLog(sceneEx *FortuneOxSceneData, playerEx *FortuneOxPlayerD WinAmountNoAnyTax: totalout - totalin - playerEx.taxCoin, IsFirstGame: sceneEx.IsPlayerFirst(playerEx.Player), IsFree: totalin == 0, - GameTime: 1, + GameTime: 2, }) } } diff --git a/gamesrv/fortunerabbit/scenepolicy_fortunerabbit.go b/gamesrv/fortunerabbit/scenepolicy_fortunerabbit.go index 738ba3b..a292add 100644 --- a/gamesrv/fortunerabbit/scenepolicy_fortunerabbit.go +++ b/gamesrv/fortunerabbit/scenepolicy_fortunerabbit.go @@ -405,6 +405,7 @@ func (this *SceneStateStartFortuneRabbit) OnPlayerOp(s *base.Scene, p *base.Play var gameEndStr string var data assemble.GameEnd if err == nil { + s.SetGameNowTime(time.Now()) data = assemble.DataToCli(Response).(assemble.GameEnd) if data.Results[0].FreeStatus == 1 || data.Results[0].FreeNumMax == 0 { //第一次触发或者正常模式 @@ -514,7 +515,7 @@ func FortuneRabbitAndSaveLog(sceneEx *FortuneRabbitSceneData, playerEx *FortuneR sceneEx.SaveGameDetailedLog(&base.SaveGameDetailedParam{ LogId: logid, Detail: info, - GameTime: 1, + GameTime: 2, }) var totalin, totalout int64 if data.Results[0].FreeStatus == 1 || data.Results[0].FreeNumMax == 0 { @@ -537,7 +538,7 @@ func FortuneRabbitAndSaveLog(sceneEx *FortuneRabbitSceneData, playerEx *FortuneR WinAmountNoAnyTax: totalout - totalin - playerEx.taxCoin, IsFirstGame: sceneEx.IsPlayerFirst(playerEx.Player), IsFree: playerEx.isFree, - GameTime: 1, + GameTime: 2, }) } } diff --git a/gamesrv/fortunetiger/scenepolicy_fortunetiger.go b/gamesrv/fortunetiger/scenepolicy_fortunetiger.go index 2c5c11d..155a835 100644 --- a/gamesrv/fortunetiger/scenepolicy_fortunetiger.go +++ b/gamesrv/fortunetiger/scenepolicy_fortunetiger.go @@ -405,6 +405,7 @@ func (this *SceneStateStartFortuneTiger) OnPlayerOp(s *base.Scene, p *base.Playe var gameEndStr string var data assemble.GameEnd if err == nil { + s.SetGameNowTime(time.Now()) data = assemble.DataToCli(Response).(assemble.GameEnd) var respinStatus int if data.Results[0].ArrSpins[0].Special != nil { @@ -517,7 +518,7 @@ func FortuneTigerAndSaveLog(sceneEx *FortuneTigerSceneData, playerEx *FortuneTig sceneEx.SaveGameDetailedLog(&base.SaveGameDetailedParam{ LogId: logid, Detail: info, - GameTime: 1, + GameTime: 2, }) var totalin, totalout int64 if data.Results[0].FreeStatus == 1 || data.Results[0].FreeNumMax == 0 { @@ -540,7 +541,7 @@ func FortuneTigerAndSaveLog(sceneEx *FortuneTigerSceneData, playerEx *FortuneTig WinAmountNoAnyTax: totalout - totalin - playerEx.taxCoin, IsFirstGame: sceneEx.IsPlayerFirst(playerEx.Player), IsFree: totalin == 0, - GameTime: 1, + GameTime: 2, }) } } diff --git a/gamesrv/fruits/scenedata_fruits.go b/gamesrv/fruits/scenedata_fruits.go index 8280e92..3a24307 100644 --- a/gamesrv/fruits/scenedata_fruits.go +++ b/gamesrv/fruits/scenedata_fruits.go @@ -329,7 +329,7 @@ func (s *FruitsSceneData) SaveLog(p *FruitsPlayerData, isOffline int) { s.SaveGameDetailedLog(&base.SaveGameDetailedParam{ LogId: logId, Detail: info, - GameTime: 1, + GameTime: 2, }) //水池上下文环境s s.CpCtx = p.cpCtx @@ -354,7 +354,7 @@ func (s *FruitsSceneData) SaveLog(p *FruitsPlayerData, isOffline int) { WinAmountNoAnyTax: p.Coin - p.startCoin, IsFirstGame: s.IsPlayerFirst(p.Player), IsFree: totalIn == 0, - GameTime: 1, + GameTime: 2, }) } s.GameNowTime = time.Now() diff --git a/gamesrv/iceage/scenepolicy_iceage.go b/gamesrv/iceage/scenepolicy_iceage.go index 787d74f..762891e 100644 --- a/gamesrv/iceage/scenepolicy_iceage.go +++ b/gamesrv/iceage/scenepolicy_iceage.go @@ -945,7 +945,7 @@ func IceAgeCheckAndSaveLog(sceneEx *IceAgeSceneData, playerEx *IceAgePlayerData) sceneEx.SaveGameDetailedLog(&base.SaveGameDetailedParam{ LogId: logid, Detail: info, - GameTime: 1, + GameTime: 2, }) totalin := int64(playerEx.RollGameType.BaseResult.TotalBet) totalout := playerEx.RollGameType.BaseResult.ChangeCoin + playerEx.taxCoin + totalin @@ -965,7 +965,7 @@ func IceAgeCheckAndSaveLog(sceneEx *IceAgeSceneData, playerEx *IceAgePlayerData) IsFree: playerEx.RollGameType.BaseResult.IsFree, WinSmallGame: playerEx.RollGameType.BaseResult.WinSmallGame, WinTotal: playerEx.RollGameType.BaseResult.WinTotal, - GameTime: 1, + GameTime: 2, }) } } diff --git a/gamesrv/richblessed/scenedata_richblessed.go b/gamesrv/richblessed/scenedata_richblessed.go index 957fc1c..8b35d71 100644 --- a/gamesrv/richblessed/scenedata_richblessed.go +++ b/gamesrv/richblessed/scenedata_richblessed.go @@ -351,7 +351,7 @@ func (s *RichBlessedSceneData) SaveLog(p *RichBlessedPlayerData, isOffline int) s.SaveGameDetailedLog(&base.SaveGameDetailedParam{ LogId: logId, Detail: info, - GameTime: 1, + GameTime: 2, }) //水池上下文环境s s.CpCtx = p.cpCtx @@ -376,7 +376,7 @@ func (s *RichBlessedSceneData) SaveLog(p *RichBlessedPlayerData, isOffline int) WinAmountNoAnyTax: p.Coin - p.startCoin, IsFirstGame: s.IsPlayerFirst(p.Player), IsFree: totalIn == 0, - GameTime: 1, + GameTime: 2, }) } s.GameNowTime = time.Now() diff --git a/gamesrv/tamquoc/scenepolicy_tamquoc.go b/gamesrv/tamquoc/scenepolicy_tamquoc.go index 2a57d3b..e1f908d 100644 --- a/gamesrv/tamquoc/scenepolicy_tamquoc.go +++ b/gamesrv/tamquoc/scenepolicy_tamquoc.go @@ -781,7 +781,7 @@ func TamQuocCheckAndSaveLog(sceneEx *TamQuocSceneData, playerEx *TamQuocPlayerDa sceneEx.SaveGameDetailedLog(&base.SaveGameDetailedParam{ LogId: logid, Detail: info, - GameTime: 1, + GameTime: 2, }) totalin := int64(playerEx.RollGameType.BaseResult.TotalBet) totalout := playerEx.RollGameType.BaseResult.ChangeCoin + playerEx.taxCoin + totalin @@ -801,7 +801,7 @@ func TamQuocCheckAndSaveLog(sceneEx *TamQuocSceneData, playerEx *TamQuocPlayerDa IsFree: playerEx.RollGameType.BaseResult.IsFree, WinSmallGame: playerEx.RollGameType.BaseResult.WinSmallGame, WinTotal: playerEx.RollGameType.BaseResult.WinTotal, - GameTime: 1, + GameTime: 2, }) } } From 57def951c1d8f752bf6fd9446df38fe185718af9 Mon Sep 17 00:00:00 2001 From: sk <123456@qq.com> Date: Mon, 2 Dec 2024 13:54:49 +0800 Subject: [PATCH 11/41] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- data/DB_GameFree.dat | Bin 24144 -> 23953 bytes data/DB_GameFree.json | 201 ++-- data/DB_GameRule.dat | Bin 1417 -> 1472 bytes data/DB_GameRule.json | 20 +- data/DB_PropExchange.dat | Bin 384 -> 384 bytes data/DB_Task.dat | Bin 5519 -> 5519 bytes protocol/server/pbdata.pb.go | 1925 +++++++++++++++++----------------- protocol/server/pbdata.proto | 124 ++- xlsx/DB_GameFree.xlsx | Bin 65616 -> 66169 bytes xlsx/DB_GameRule.xlsx | Bin 12964 -> 13519 bytes 10 files changed, 1101 insertions(+), 1169 deletions(-) diff --git a/data/DB_GameFree.dat b/data/DB_GameFree.dat index 9ed570013bf427b6cf7d22d1081b9237d012c275..744409862002d65fe50c15ebc1238808e58d62b9 100644 GIT binary patch literal 23953 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 G1{MJ0q!Nb! diff --git a/data/DB_GameRule.json b/data/DB_GameRule.json index 3975258..4860e87 100644 --- a/data/DB_GameRule.json +++ b/data/DB_GameRule.json @@ -71,7 +71,7 @@ "Name": "十三张(四人场)", "GameId": 211, "Params": [ - 0, + 4, 0, 30, 50, @@ -84,7 +84,7 @@ "Name": "十三张(八人场)", "GameId": 212, "Params": [ - 1, + 8, 0, 30, 50, @@ -97,7 +97,7 @@ "Name": "十三张(自由场经典场)", "GameId": 213, "Params": [ - 1, + 8, 0, 30, 50, @@ -110,7 +110,7 @@ "Name": "十三张(自由场癞子场)", "GameId": 214, "Params": [ - 1, + 8, 0, 30, 50, @@ -250,6 +250,18 @@ "GameId": 312, "GameDif": "312" }, + { + "Id": 31300, + "Name": "CashMania", + "GameId": 313, + "GameDif": "313" + }, + { + "Id": 31400, + "Name": "GatesOfOlympus", + "GameId": 314, + "GameDif": "314" + }, { "Id": 60800, "Name": "娃娃机", diff --git a/data/DB_PropExchange.dat b/data/DB_PropExchange.dat index 804f10646fe2eaa8171cfa2bf4475d6bf342eea8..5cadcdc0d315ae31235cc99ae2873cda02dadc63 100644 GIT binary patch literal 384 zcmd-w<6snElw#w!+Qtl~uR-bSQ2H{Iz5=3^I5-yevI!h$vE|a^U;?YZ0hPZArEfv$ z+i2>;IUwf4%!Ap3q8{iDusulbfw=?49wkn&I~vwLV&RJAU;#S>rV!>3m__IwgBgTw W@g1ncAs%JtSOoOw7iKO7+Cl(ik~}p4 literal 384 zcmd-w<6snElw#w!*2WB`uS4m}Q2Gj#z6zq1I5-yevI!h$vE|a^U;?YZ1(m-IrEfs# zn`r98IUwev+k>JW=nk+wKpJK*y7^#tDRF|`(XjRr3s)=$3)mqrjW7#f2E!bN?je{* a!43sl2(#!8*x~FPi+~>e!py}$TL=JT;yg6~ diff --git a/data/DB_Task.dat b/data/DB_Task.dat index adeaa2c214e90e75e727ba605c283a59b8524c3e..4a3c1f5192c358115837757ca0468db7f362b84e 100644 GIT binary patch delta 235 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 z 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 delta 51602 zcma(2Wn5JK*ES9V(nzOtNJ@xO(v2WPmmnn~IkYrvq#Kb?X@(Z*mJ}2Oq@)?TyF34T z@T}|iJTLASd^Qsfcxji!AZouKYH2w#nmMDP_#fyJUrnWpwGUVCCy zuNpNWi62=N=Mjrc%#TMYSuMiF%q7;i_a*}5A}%jENpXp*-g;>Yn!Lag*u4+^WcjG_ zO|dD3K^fW)=pxMo5V0}Aw(V^tP&+rDV2`9J&0U7l!R$uu)>3*eY}GIRrL2H`?mDuD zNxtM;SF#TENT2~PvK$a!O$gIWu$wte#dFNFWk+{(*|B{>39pWt$c~vi=s5LwbJAZz znfSFn0VzID9hU$eM`fyQP17Q4?XGTNhE-Z6sn zd{Jh>njb_<@oJRs3*Yr(KQgO$Cjax9;L)NFxs7Fh+vZIexv6riyAeT`W$Sx)X;GAY z@sl;(pUuc>&+ed-AR!@PB88~TOG>3NiN`&-^8onilN7^kBQgZ5!_qIR^S~sqL?M%YtfE?8ZI^Pa=Vmw)DlJ$+ z()ALM|4AfRQKk>u!@=Nb7#_GL9baFzwfH<`;GQ%efPK@vHMaa;fXXwVHGZ@5Gyvnw!hx6Jy}w zbS_3S3;c;&Bkk?mH4?z-+J_RGz#U%$R-ipk;%Y6APJ-6^e6K_TxLk6^-G_HHd!KSH z++6iZT%Fg;U(5h69!%2#7rSns3Zpx4_c9pC?42zrX26$E;dwLQ2OJ1W_@1A^g)1Es zcba@K4ld6+7}QGjz@M}QTpx|zaK8l-I~lG}aCx-@#8qOG0L|Ce zXM=qhbmGA2d5DCvh{F}UM&fcVMxv7=vFK*KCI&da-uSWX)*aHb)mVa-ltK%fpPtN2 zH8-DMΠ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 C5({qt delta 3803 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 eB!>00;DCy-V#6n From 1477611d4a3c232f90ca3f2c85adb9dcd41207d7 Mon Sep 17 00:00:00 2001 From: sk <123456@qq.com> Date: Mon, 2 Dec 2024 14:06:15 +0800 Subject: [PATCH 12/41] =?UTF-8?q?fix=E6=B8=B8=E6=88=8F=E6=97=B6=E9=95=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gamesrv/base/scene.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gamesrv/base/scene.go b/gamesrv/base/scene.go index cb10fac..7dfe670 100644 --- a/gamesrv/base/scene.go +++ b/gamesrv/base/scene.go @@ -1471,7 +1471,7 @@ func (this *Scene) SaveGameDetailedLog(param *SaveGameDetailedParam) { return } - if param.GameTime < 0 { + if param.GameTime <= 0 { param.GameTime = int64(time.Now().Sub(this.GameNowTime).Seconds()) } From 0fe7ee6d4cfd644c23e03466a5b83f360ec50734 Mon Sep 17 00:00:00 2001 From: sk <123456@qq.com> Date: Mon, 2 Dec 2024 14:11:39 +0800 Subject: [PATCH 13/41] =?UTF-8?q?fix=20=E5=8D=81=E4=B8=89=E5=BC=A0?= =?UTF-8?q?=E7=89=8C=E5=B1=80=E8=AE=B0=E5=BD=95=E7=A8=8E=E6=94=B6=E6=AF=94?= =?UTF-8?q?=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gamesrv/thirteen/scenepolicy.go | 2 +- model/gamelogtype.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gamesrv/thirteen/scenepolicy.go b/gamesrv/thirteen/scenepolicy.go index b7a3fd9..5665f79 100644 --- a/gamesrv/thirteen/scenepolicy.go +++ b/gamesrv/thirteen/scenepolicy.go @@ -1334,7 +1334,7 @@ func (this *StateBilled) OnEnter(s *base.Scene) { RoomType: sceneEx.GetSceneType(), BaseScore: int32(sceneEx.GetBaseScore()), NowRound: int32(sceneEx.NumOfGames), - ClubRate: sceneEx.Scene.PumpCoin, + TaxRate: s.GetDBGameFree().GetTaxRate(), } var person []model.ThirteenWaterPerson for _, o_player := range sceneEx.players { diff --git a/model/gamelogtype.go b/model/gamelogtype.go index 4ca1a01..d9f4185 100644 --- a/model/gamelogtype.go +++ b/model/gamelogtype.go @@ -168,8 +168,8 @@ type ThirteenWaterType struct { NowRound int32 //当前局数 PlayerCount int //玩家数量 BaseScore int32 //底分 + TaxRate int32 //税率(万分比) PlayerData []ThirteenWaterPerson //玩家信息 - ClubRate int32 //俱乐部抽水比例 } type ThirteenWaterPoker struct { From f532cee29b0a188c09c62606637f3979964231dd Mon Sep 17 00:00:00 2001 From: sk <123456@qq.com> Date: Mon, 2 Dec 2024 14:32:32 +0800 Subject: [PATCH 14/41] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- data/DB_GameFree.dat | Bin 23953 -> 23953 bytes data/DB_GiftCard.dat | Bin 57 -> 57 bytes data/DB_PropExchange.dat | Bin 384 -> 384 bytes data/DB_Task.dat | Bin 5519 -> 5519 bytes protocol/server/pbdata.pb.go | 1941 +++++++++++++++++----------------- protocol/server/pbdata.proto | 130 +-- xlsx/DB_GameFree.xlsx | Bin 66169 -> 66837 bytes 7 files changed, 1041 insertions(+), 1030 deletions(-) diff --git a/data/DB_GameFree.dat b/data/DB_GameFree.dat index 744409862002d65fe50c15ebc1238808e58d62b9..28559c2cd217a73fd8bd958ff461ac0ce54bb150 100644 GIT binary patch literal 23953 zcmdU1ZEzGvdZv3;tI?V>m9?ulQ)f=8-hR#gu z+M&bi($%T^{`v90pH-CEl+4t;m~QSaew&n#*o9UypZ^}cWE8zX_}s3Ka!;G z(G*Dz(OyzeT7v)j2suN@v`Zx1QplK`|***eT$z@#_mxkS$DJvT`V7f3vBRHc?gE^+8BG zf3heLi;#`Q{}T0DE*8T(8%MKH1Pk7Ng#Api?l5?S%NP&Y7dl7)1(p681LqW@I|#Z% zWp8E#7?-Y^JG5;5_XBZJY+T+TYULL$no1`+2M^UbHPz2F)zjwCl;{zrsm9A=(A32A z$0?$&%*8>f%EG~-Du@EI!cRk2I*p*ZQrSCuuH3kdb;iYyW@^3f{?#}-~( zmI|EeYH< zB>^|mk+CFT_9W6W;rArAhxmt$9sVjW_)cZ>cN4YR3wd_+zI1Yp4S9h? z&axrGQVQfGNR&+IJiBs2Z}~3fMGJJEifF&y|0!vr5v}2)3yPL_=TPBTMSqN_FL;4Z zw|5L}f7u2;EWz{ihwv;Y$rCFBzN#ndPWoM7WYp5B|2f^;B3!P|jadS{y)bTLT| zmNnpnTM&qx$Vo(cks#vkMX+#lL>Q71EbI%wi8rHOqMpo2M7ok7;_gb!&CS7K*pgh! zeto`llBmDRNkSTwAmMIMZ24xAFbv8;;%jm!td~yZq#>tlbPEMW$6bn0#Gc zh0JLE+6^)@axW%a#X9eZuSMmoCrq$GAv3D?!YzGC;P&<6#LYQz{0{jhL@TD6G z`0j4Rt5E@p1`}^a$c!4i;7bn@@ZCKKwr|v+CO0$M=!IMwk3jBjJbGrtTfT6TGowvj z;HBLN@Sb*q4AW@&NzRPm|EEuGB+>7#(Cgy5+YHsjFCU3}Rhe#(Sl4l1@8Ri@K7>6A z4SapR&Yo$eiw|0bS*)|-L>>|NhdOyu7#59JHe<(4--^8J&dPJoXjM97`FCW&m&`+ zY1EQ3zpNiTTI*g>8bQ7CDEF>^A^#?O1rv8Zt4bIoZT<|TZ3zYx3?gEwjk$XY)R#bH zn?Dh0S%QcHA~OV$@$BwRd_IM(y>@>h(yj!N5Qy9jYKL_blfH<;=~9A57&OWxjVV%x!amEz`b{KS?BZ0O)u@{!*4UHNvSdZd>rBD~r(ACn z^@D(1qV-sw=jm=WEn$*SPX`*HV@{tZF`1m@UEMHB2F4mbqrQM#3 zx!16+k=Vz3zh(YPC9p(GtoQ1W)XeAUX{A?nSskdpok>*S6|KGaM=9uh^-McVTuNMzKFhBE5u`mgtAw$uzIi>-w4XKAc(qiCX#5s35w* zT7&$a#0C=M4)T<`{!kT(e#eE0*utPdzLLI@OeG)Ntu0>B7*Agtp;0oe%kd!u2_BTlElKwXl z^pi{)3JA)=NHb3EZTv*Zah68FON8Zt+hLTqn`#nb+HJ2tQN1ak%rytm*pI zj!dc{^V0g_^-8S$5S<_T5s8!c_7U9dU>l!!>Lo<(^50$eD0Z2#D93RyG!{-KU1Ru~%(l$7>S#pPy)K0bc0)IB<&;G?q2!Yj(c&y_F8 z%Ft?3a$kALy(RZo%quUw54#(9oI9_yr1U-$-SlXD)1Cz zPxqJ4i{Y8=i{M2C-ilZ32*bT)_$xf{ce7Uy;_Z0F3M}`Q-(QB0Fy6;rR>VV*#?W&u zp-3{6EJ}r1!jTJ9t#@hJ?B;dp-7gJwG^X2D$(E%?%jz?cvuS7RvK#1#YWu&9w4&$j zzZ|&m1MN~t%V%@Zn3lFJVjsXyu89+DeS2EI7o>F&V?e>DeM6czL)8r~%{!QC&g?%p zd~8d4_fFZoxRS($%gzOkR_^ziAZwoOsXfRKm$Su!w)Iom^U6*|YtJg?;Za*NWm>wKYpL&D9WS$FAmSMu&I|p&SZAQAb zaxhhsKGKrjx^=L-dlo4zK8sBV#|5^!))|eYBS4bp*tp|6UWfG@3Soo^NcI1QmrG72l?w2;C z{Y^NKL06r(-EY)bcP(Hz%;g97cq=7BrV2P9B)=m040 zApHHAcYf1N|H+qvmK!QTk?z12fjiO)iPRiDb^J<@c`-=t zFcAWA34ys@{^W&+ha4HGzr3qRY98jbN~5BW5KUU!^j#RBJ)F@Y2AP|GFMDPjUA z-GM$Jfld_@_?0`-3W;j_?ET7=BVD7ZQ`o%9sW{|@9_8hp=$#v=OgKUvv!EN&i&gO#N{EBgP*8)8szLBN!Yd8$}P|U@*JQTC#<@ByPt76_^ifJ^rOXN(FAH{r- z1GiL+1^3iY%!j$43&mKVPZ7mDuU@=-m0|;;sy(CCv*pjahFL{u>`W?^iLWdELnxMd zPnjRqzgY^8Y}diuQZsWO)U(`Ik#kGt_R&I@O$AZViqv4w=;#QIvY11aJBN1fLip;} z)771s=Gx-_3&onxEAxpS9*;@3{b6Dl;CbaGe4CXIk`{`0=+&UPUf*7&?{P$)RZqWv zkVK2JU2WOpb+{>R9WJ|Qtl=XvUjY>C7c>rs_?iaQpRiG?8V>amd_h*RY@JYiPT9gW z_;xImO0oOVN2yCw7_t9bJ>!gx-WWWxnVF=BO=WDJ`}bqT$CoI;gXk5G==c0>;OJ*Z zMHgRDAfhWWI#v(~tTl~whaSDG!lDdtpIsI(`g7_zXLPyUE~1A-bhdCwki-f0m0J83 zph4aq{?2;>hS%VluccVB-CjF*cy(5*M!{le>nqmY-%Vqm%ihN#-_iT{6aU^X^X>hW zIG^keL5e^?;3Ci=*hQd&@DV{y5FdJg5Lyr*xE6E}b}bk!;jIOK5LGw@><&UoLV)0s z;2@lm;3!xL#6BD?n(&A5oO<;$NMbr9k?A^|U9&R1cdJzoduZ&!$HEP=pF8z{Kk?T? zxvw6cS4UjJOD%}-Tnl=5yB2f+K3d2H;F=o%p#uSc>p%x!*MZRj-a7CHfI)fP1%VWS zK)^-75jaI)wt=TF_(OP3tvq#zY2bxqX79ei)TW{C9aaq_X{_fHp@Dv_z~Kq_6BiBK zC1->Oa%fdh!1!8un z@a+azbG-`$*$)B&?*|y&?+Ok=9}QxT<{%th zq4K8aBC`X+fFfEyVBL{Pc4b~}&b(MN+?+zb7Jte33e3GU7QZaIW4IDuM9Q}FSdPT@ zMzzoIm63dJ)FnyMbF^}nGWz66mDsFtfgpDj1q9w590D>VeN?conef1%r%J&vKoZ+r zFvy)kfr0l1$ACmd9~an1^8}%1Ou;}v674P^pi5)>Pk`VC$w9Eiv5`3OtkI(_^jR_( z3`n9gd6>_XO+&A)OSd;6d$vkqAB}x1C2_jOA&Kmt0!RX1I_ocqy)F=>Bm@L52@b&~ z2@ec*N%&)cB=)&rkdhD>xFk3RyCgh7*d^f)0+Q%*0U;$JKyXQL5Kc*Wz_3fgAI1{( zjXyC(JhJTR70)bP^!VbRE_#~nUUkt}{}o{lcx2|F8v|ZAjDb0lslb?T_b*jX|Mm!p ze#;2=4^J=n>9VCP-hLYEx+>z~QO3gypLlY$R6U zSEjjp7FH7-`YX1m9|*;?_eE_3kH#GNK58u1Ig-esFt@~iDEwSq87w3(oJ~;3RnCww YUKf_U;N=~Xj)i4au#kL{WFkWTKMKqfHvj+t literal 23953 zcmdU1dvFxTou+$MtI?X6I@wjkR7`Yrm*7g-K0PeFcbu=d@|7=tB=%LxRd@g0;lL%N z3?v3u64&`W0?Di}3PK1FAloY;tTh;rK)|xR)<7tq6Wihu8{1SOWbJB&AH1>47035= z&rJ8sXl8aKWUWkrG$S$l`@Zh4zy9@WB1edNdE5V%PJ49zyoHa?TbNtEb+EZR+qQD> zz^Y7L@}7Tx^q;4dWY=|N>z~WCrpn$TEztr6`6+h+0D-l)~`H8$)r9S&QWrS&W$N^lOYm0M${|$7z`x0 z52iXD45(yK`v4f!K9C^2&nhN`YC8q|8h@{lqFiy;1uKVQ_M3Ixw27+P_WqFe-tm$^ zEJ8LG|3}oT`B)5XYZ=Z$5iEH55%x8~s>9$Bu4Fu9UFaYI6jXYr^qoL92Nl|9S| zFfKjyw`sYi?*`(c*ton()SAy-G?hto5A1JrYO0rMD&6kTl&BG=sg{c)(A3z}#|fe? z&BsBi%EG~-Du@EI!dF9AI*p*ZQrVN~OV@8W$V{uVqKZk z+KUJ4t+sWNNvvbDLt=%st=|*1DKHhOGz%4r(nM=1n17uj>YBiGq~0uaEP7)d!9*}J zm~z`XjSSbD?qr^NJH_-C>zGh_dxNO$!MRAmS-4Cn!JQ`R=HPs!;w*e7pyKwR>pa{< zO8?4mIQKN{5<1KS!_?JCkVK)w36zN`NY>mEv2gm61?*$;=V3NuK8Wtp3%Asgz-?0! za3dWVNdjh1A}t+$ISsY!TZbP0TYMmGI-16O-t`#=qMG`s7 zh6qb3kdq)$GNJSA$_YLGZS;#4=sXqCUf=TxX`&IW`NMOHmUw%A@km8~n5fTsfzNbw z4sLnD20kpo^Yn-CEGWSfD+9i&C+kl9u^IL}J;I;lm>GfISFYZw#ox`|IZ^^?qP}{g znTXM!?lzv?+BFjGJ?v{c804A54qZdThk#>jJjm0J=A|GVNKo*0p!m`0CI?+il7nRo zIOY}vBFFL)kzOQ-xO)*S+-wnsqy!850C4Qh=qOQ-=OrRtNf2>&CFbU4<1lPVj%B|( zUph|I-{vJD4N8!3Hz+oIGf5Z*-GgBJ#vIi6W=3nhkW1qc$lZ-c&y0A<7msshw9X5> zv>O55({7Mq8YMr@nGyW|%x!6C)?Log!JwFD7&*V5A^oyd5)7N%t14n{?Kn4se6VLWBxWX9RUu(a3q9x|q> z##~bNH%$YF8r)};u3*0M5cjTsBmW_51s!)GXO+-M+Wi?w+Y$^Y7(~QS8-4c#m|p^s z&HhBBWeFk*h)fYgMzgv%_W2Z+_B#BDNV^h5LLhRxBvR-(C-m)G{5eRc5*&)aVY=in z0cM|Iyf69FkS--?gh8WH(wHFgP*`U<-?WaDmbo~U=WNss5^YK6wJbR!<+Ueaj8m?+ zh}s{Ji!?96#oxT-)Kn4g7sZ@T_^X_m0;3NCGLkMP7+*~s`7@AqCK&kJSz%_hKxDT+5$R%rh_{OsZf*;?SdTvu zX`L9n&^v?kkvhg&oGuR(G5<=3(1R;MLE6i*dXk8r%Eoo|kmba-DZeFaH zsMkh9OInNse=RBfmJ1WHgkg>LE{Pt0`6i;ZEw6J%(6~$&CDQ%+cH*6oB z|49UWC(~z?;3Pt%6+8FVeyrr#OC#VV!g53Mc))vys;m31kQm`1%H~|-H*p{$0k_ruDZ7pA7MPlZmYFWq%rh# zODK{Eb(M65;^D|Ssy4ZlY;OIk%#P;=J6kgC%Vfz?qh$4-$XT@0b=mcGmTG&xiL@g9 z*5CG>`<`~8JpSoS6sDzYOV|hSooiwT+iN@H-w9H>h;dfIr+rO|H%rwuF2y^LY|ZZ3 zH*|PIX2&*Jyf~7?h0FE@4p;7XnIP+*N;mA|o6Ff?LEH2RO~1HJ(K>R9xp~x9%=jRU zm24Beg@4z2-#>PZ1}SF*JFBp2`kEB<$5d^0DQJ{(R@<80*PTtSkOdtw3!1g*;U#?+ zmnYjFy1esNev*hCVEN6P-_j0r{WUvPq^-UFJyuDUvc5&%h{?;hiB8rFT8lStX}B{; zakGdhZ+zz0q`cd)q3O#*wDi^oe>!jR;s@s}cx=(!`EwRp&#lylqP6Q4+hMz0ah!K% zIEAJkiwZGI6BEI7(nA*rzL@1oR#4YIt-2B(>~^|N?9NRo_?XBR>|SyQxnakUwvlzT z0;Jq8kenJP$*BqaGeN>qB}nC=z4QWMU#&3H|AbBiT`x=zj;D9ML141aiM)($O0GEN zXingiTLI9MVH>=DZqaQ>8rn;5lw2VEn-waaYX~!_+)si-|5xIJ6`?=;AP*ec-f;zr;h@!^2HsKA{(&m{l;NhdYipn{b$jKreVU|y9aQ*ZAzx0 zW*}LgIT+7u+BA?#O(PX$r?Cj(IKbA}Hl>lof7b#Z!exTQW*7si5X+T?3z11?TV@Bm z@jrXF`~XK-8@JZ$56h!D75Vz0v{L?>LLvz)J-FknlsL`C!bdH(Eg#%3^<(LFzqBFs zKSdN2>PuK$aEDqYp_&Z`P?3VhjU&S7QjGEpvo77MMDrXA4hpmriwEvN?~_2yrURfj zhYX zFcn@;~cfX;u;bgm&e*1di%Qw1M@# zrF?WUisFR{yt=E#W&(BF3==qm13z1gIU3_-4}~;=qwY8>%LL8|V*Hg9% zUl>(d!14*+3+7J?tS^2sGJ_=cx97o~=~|UZ?PG%!3vQcFpkHIJei?C^V9s#_Fx@^X z-}Yia$HAJ@`JlJHXdKa#cX&Xv%S%(n75f?TFm7V*^?AT zG5vXPOT}1lPYlI;kPo_0j0O4xQOq;y`HPn+79eUnvRV@x{;X=AR)WILCX?CNsx&smGepp)0hM#T=~JHn?Lu z!q>f$sq4NtSGPGz=VAp3~|uVKKPrMQiQvpwZ7{?PHMdsD1pzzxFGA zYkw*BC%Z$CA`lR`2y_T`5$GU%M35K62Oc1V76b^c1s#N43r0zJYr!8xEp`FBgOHLC zAh;wr2&W`C3N{5|Z;lpC_``Twz5FR8F&UD`_8iEqSen_j$*PB)GDa@N8Fh*Y1Jjy1~>|s|LDgH2tyAK(AKh@C5wC zMFV%p9^t+`8d&NQUTQ#u=NjPQ*+LuU_svd02jJAe?b4S00iX(&xgiiD5D2&kbOhKU zWa$_4rgO6*_g9e?xxX>PedIgW6nCjPn>m79GmgbIx@XT z^bXa&)c|X5a)BW0K|tX3phMtILDYi|!d4GDh+jnlf`BWoaRVW$LV(~^!9nP)LG;la zgrh1{UKBlKdO#RZL|Z?rj%-&?_J!8$bM-^5N#tv>=Z#lj?xNAyMNu6?HFyyzTh3!S z5?dS9KE*2|`P!&UlBDNoRV-!n$&+fZSmOdgt|$r!ygE1pWJr3eV6U0*z@Vo}!7xA) zn_V!-l|q4m*9OOcL`82GSV!{&p=V6NKtK{5E+C*wWBE^j;0DP-u)(pBIPt8}qb&4Z zG8haBCE)?XE(w1a z3)ENt!W8k)q9>L-xp3a2^M5k$3ATFGL!-TyggM}nnS*W&xN#T*b0kxNQQzucsGj`& zK~nk+Biz3{G3O_X7P5GIXtd|Dh=)rV4>vyX{ytB<^BWJzct4u+*kkjTuy}iEwB?G3 zhf5g`H{S6o%6;SgOud{#yb^=oBfny?_R;8{Wh`9ESh(?trid5a(U??)d0^@5*2xtIk^(P-kj2#8A=5H~&n{d1RJs5L9EvWbnv zGW^Z9rlw&u(W&3DL498+s=Y7fHgIY5k?&)U#o9*_*%W4$`!|JOs7r%|;IUweP%|WscrXSrttmXmrf!(LX33f-r+D9y0u^cR5hoCqVs1V%%n8#oqg;@-C ZC{X;IUwf4%!Ap3q8{iDusulbfw=?49wkn&I~vwLV&RJAU;#S>rV!>3m__IwgBgTw W@g1ncAs%JtSOoOw7iKO7+Cl(ik~}p4 diff --git a/data/DB_Task.dat b/data/DB_Task.dat index 4a3c1f5192c358115837757ca0468db7f362b84e..c77b7fde801255a536b4fbd974f205c61e660e90 100644 GIT binary patch delta 176 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%0DT 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 Date: Mon, 2 Dec 2024 14:58:23 +0800 Subject: [PATCH 15/41] =?UTF-8?q?fix=E5=90=8C=E6=84=8F=E5=A5=BD=E5=8F=8B?= =?UTF-8?q?=E7=94=B3=E8=AF=B7=E7=94=B3=E8=AF=B7=E8=AE=B0=E5=BD=95=E6=B2=A1?= =?UTF-8?q?=E6=9C=89=E5=88=A0=E9=99=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- worldsrv/friendmgr.go | 92 +++++++++++++++++++++++-------------------- 1 file changed, 50 insertions(+), 42 deletions(-) diff --git a/worldsrv/friendmgr.go b/worldsrv/friendmgr.go index 4a8e394..7b4f82e 100644 --- a/worldsrv/friendmgr.go +++ b/worldsrv/friendmgr.go @@ -608,51 +608,59 @@ func (this *FriendMgr) FriendAgree(p *Player, destP *model.BindFriend) { } } - ret, err := model.QueryFriendApplyBySnid(p.Platform, p.SnId) - if err != nil { - return friend.OpResultCode_OPRC_Error - } - // 维护申请放和被申请方的申请列表 - //查看是否在申请列表 - if ret != nil { - if ret.ApplySnids != nil { - for i, as := range ret.ApplySnids { - if as.SnId == destP.SnId { - // 删除被申请者的申请列表 - ret.ApplySnids = append(ret.ApplySnids[:i], ret.ApplySnids[i+1:]...) - model.UpsertFriendApply(p.Platform, p.SnId, ret) - - // 删除发起方的申请列表 - data, err := model.QueryFriendApplyListBySnid(p.Platform, destP.SnId) - if err != nil { - logger.Logger.Errorf("QueryFriendApplyListBySnid err:%v", err) - } else { - if data == nil { - data = model.NewApplyList(destP.SnId) - } - for k, v := range data.List { - if v == p.SnId { - data.List = append(data.List[:k], data.List[k+1:]...) - model.UpsertApplyList(p.Platform, data) - applyList = data.List - break - } - } - } - - // 保存好友关系 - if friendDB != nil { - friendDB.BindFriend = append(friendDB.BindFriend, &model.BindFriend{ - SnId: p.SnId, - CreateTime: time.Now().Unix(), - }) - model.UpsertFriend(friendDB) - } - return nil - } + // 删除申请者的申请列表 + delApplyListFunc := func(plt string, snid int32, applySnid int32) friend.OpResultCode { + // 删除被申请者的申请列表 + list1, err := model.QueryFriendApplyBySnid(plt, snid) + if err != nil { + return friend.OpResultCode_OPRC_Error + } + for k, v := range list1.ApplySnids { + if v.SnId == applySnid { + list1.ApplySnids = append(list1.ApplySnids[:k], list1.ApplySnids[k+1:]...) + model.UpsertFriendApply(plt, snid, list1) + break } } + // 删除发起方的申请列表 + list2, err := model.QueryFriendApplyListBySnid(plt, applySnid) + if err != nil { + return friend.OpResultCode_OPRC_Error + } + for k, v := range list2.List { + if v == snid { + list2.List = append(list2.List[:k], list2.List[k+1:]...) + model.UpsertApplyList(plt, list2) + break + } + } + + if applySnid == destP.SnId { + applyList = list2.List + } + + return friend.OpResultCode_OPRC_Sucess } + + //查看是否在申请列表 + code := delApplyListFunc(p.Platform, p.SnId, destP.SnId) + if code != friend.OpResultCode_OPRC_Sucess { + return code + } + code = delApplyListFunc(p.Platform, destP.SnId, p.SnId) + if code != friend.OpResultCode_OPRC_Sucess { + return code + } + // 保存好友关系 + if friendDB != nil { + friendDB.BindFriend = append(friendDB.BindFriend, &model.BindFriend{ + SnId: p.SnId, + CreateTime: time.Now().Unix(), + }) + model.UpsertFriend(friendDB) + return friend.OpResultCode_OPRC_Sucess + } + return friend.OpResultCode_OPRC_Error }), task.CompleteNotifyWrapper(func(data interface{}, tt task.Task) { if data != nil { From 2d43a4153a4ef9ff2d89a8928ea41962c8a6d12d Mon Sep 17 00:00:00 2001 From: sk <123456@qq.com> Date: Mon, 2 Dec 2024 15:53:42 +0800 Subject: [PATCH 16/41] =?UTF-8?q?fix=E5=90=8C=E6=84=8F=E5=A5=BD=E5=8F=8B?= =?UTF-8?q?=E7=94=B3=E8=AF=B7=E7=94=B3=E8=AF=B7=E8=AE=B0=E5=BD=95=E6=B2=A1?= =?UTF-8?q?=E6=9C=89=E5=88=A0=E9=99=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- worldsrv/friendmgr.go | 41 +++++++++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 14 deletions(-) diff --git a/worldsrv/friendmgr.go b/worldsrv/friendmgr.go index 7b4f82e..9a18df5 100644 --- a/worldsrv/friendmgr.go +++ b/worldsrv/friendmgr.go @@ -511,7 +511,7 @@ func (this *FriendMgr) FriendApply(p *Player, destP *model.BindFriend) { // p 同意者 // destP 申请者 func (this *FriendMgr) FriendAgree(p *Player, destP *model.BindFriend) { - var applyList []int32 + var applyList, meApplyList []int32 SendToClick := func(retCode friend.OpResultCode, self ...bool) { pack := &friend.SCFriendOp{ OpCode: proto.Int32(OpTypeAgree), @@ -534,6 +534,10 @@ func (this *FriendMgr) FriendAgree(p *Player, destP *model.BindFriend) { RoleId: int32(roleId), } p.SendToClient(int(friend.FriendPacketID_PACKET_SCFriendOp), pack) + if meApplyList != nil { + p.ApplyList = meApplyList + this.SendApplyList(p) + } } else { destPs := PlayerMgrSington.GetPlayerBySnId(destP.SnId) if destPs != nil && destPs.IsOnLine() { @@ -613,32 +617,42 @@ func (this *FriendMgr) FriendAgree(p *Player, destP *model.BindFriend) { // 删除被申请者的申请列表 list1, err := model.QueryFriendApplyBySnid(plt, snid) if err != nil { + logger.Logger.Errorf("QueryFriendApplyBySnid %v error: %v", snid, err) return friend.OpResultCode_OPRC_Error } - for k, v := range list1.ApplySnids { - if v.SnId == applySnid { - list1.ApplySnids = append(list1.ApplySnids[:k], list1.ApplySnids[k+1:]...) - model.UpsertFriendApply(plt, snid, list1) - break + if list1 != nil { + for k, v := range list1.ApplySnids { + if v.SnId == applySnid { + list1.ApplySnids = append(list1.ApplySnids[:k], list1.ApplySnids[k+1:]...) + model.UpsertFriendApply(plt, snid, list1) + break + } } } // 删除发起方的申请列表 list2, err := model.QueryFriendApplyListBySnid(plt, applySnid) if err != nil { + logger.Logger.Errorf("QueryFriendApplyListBySnid %v error: %v", applySnid, err) return friend.OpResultCode_OPRC_Error } - for k, v := range list2.List { - if v == snid { - list2.List = append(list2.List[:k], list2.List[k+1:]...) - model.UpsertApplyList(plt, list2) - break + if list2 != nil { + for k, v := range list2.List { + if v == snid { + list2.List = append(list2.List[:k], list2.List[k+1:]...) + model.UpsertApplyList(plt, list2) + break + } } } - if applySnid == destP.SnId { + if applySnid == destP.SnId && list2 != nil { applyList = list2.List } + if applySnid == p.SnId && list2 != nil { + meApplyList = list2.List + } + return friend.OpResultCode_OPRC_Sucess } @@ -658,10 +672,9 @@ func (this *FriendMgr) FriendAgree(p *Player, destP *model.BindFriend) { CreateTime: time.Now().Unix(), }) model.UpsertFriend(friendDB) - return friend.OpResultCode_OPRC_Sucess } - return friend.OpResultCode_OPRC_Error + return nil }), task.CompleteNotifyWrapper(func(data interface{}, tt task.Task) { if data != nil { logger.Logger.Error("FriendAgree data:", data) From 744d52226ce879e14d35f50587e42fbcce52222d Mon Sep 17 00:00:00 2001 From: sk <123456@qq.com> Date: Mon, 2 Dec 2024 15:58:56 +0800 Subject: [PATCH 17/41] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=8D=81=E4=B8=89?= =?UTF-8?q?=E5=BC=A0=E6=89=93=E6=9E=AA=E6=97=B6=E9=95=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gamesrv/thirteen/scenepolicy.go | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/gamesrv/thirteen/scenepolicy.go b/gamesrv/thirteen/scenepolicy.go index 5665f79..331c12f 100644 --- a/gamesrv/thirteen/scenepolicy.go +++ b/gamesrv/thirteen/scenepolicy.go @@ -1234,11 +1234,8 @@ func (this *StateHit) OnEnter(s *base.Scene) { } } } - if sceneEx.isCanAllHitPos != -1 { - hitNum++ - } - // 每个打枪加1秒,全垒打再加1秒 - sceneEx.hitTime += time.Second * (time.Duration(hitNum)) + // 每个打枪加2秒,全垒打再加2秒 + sceneEx.hitTime += time.Second * 2 * (time.Duration(hitNum)) sceneEx.ShowCards() } } From c7ca731c338a2b514e8237116d433165180aa7ea Mon Sep 17 00:00:00 2001 From: sk <123456@qq.com> Date: Mon, 2 Dec 2024 16:29:40 +0800 Subject: [PATCH 18/41] =?UTF-8?q?=E7=89=8C=E5=B1=80=E8=AE=B0=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../fortunemouse/scenepolicy_fortunemouse.go | 28 ++++++++++--------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/gamesrv/fortunemouse/scenepolicy_fortunemouse.go b/gamesrv/fortunemouse/scenepolicy_fortunemouse.go index 9c1998b..65356b3 100644 --- a/gamesrv/fortunemouse/scenepolicy_fortunemouse.go +++ b/gamesrv/fortunemouse/scenepolicy_fortunemouse.go @@ -405,6 +405,7 @@ func (this *SceneStateStartFortuneMouse) OnPlayerOp(s *base.Scene, p *base.Playe var gameEndStr string var data assemble.GameEnd if err == nil { + s.SetGameNowTime(time.Now()) data = assemble.DataToCli(Response).(assemble.GameEnd) var respinStatus int if data.Results[0].ArrSpins[0].Special != nil { @@ -524,7 +525,11 @@ func FortuneMouseAndSaveLog(sceneEx *FortuneMouseSceneData, playerEx *FortuneMou if err == nil { logid, _ := model.AutoIncGameLogId() playerEx.currentLogId = logid - sceneEx.SaveGameDetailedLog(logid, info, &base.GameDetailedParam{}) + sceneEx.SaveGameDetailedLog(&base.SaveGameDetailedParam{ + LogId: logid, + Detail: info, + GameTime: 2, + }) var totalin, totalout int64 if respinStatus == 0 || respinStatus == 1 { totalin = playerEx.totalBet @@ -532,25 +537,22 @@ func FortuneMouseAndSaveLog(sceneEx *FortuneMouseSceneData, playerEx *FortuneMou if respinStatus == 0 || respinStatus == 3 { totalout = int64(data.RoundReward) + playerEx.taxCoin } - validFlow := totalin + totalout - validBet := common.AbsI64(totalin - totalout) - logParam := &base.SaveGamePlayerListLogParam{ - Platform: playerEx.Platform, - Channel: playerEx.Channel, - Promoter: playerEx.BeUnderAgentCode, - PackageTag: playerEx.PackageID, - InviterId: playerEx.InviterId, + sceneEx.SaveGamePlayerListLog(&base.SaveGamePlayerListLogParam{ LogId: logid, + Platform: playerEx.Platform, + Snid: playerEx.SnId, + PlayerName: playerEx.Name, + Channel: playerEx.Channel, + ChannelId: playerEx.ChannelId, TotalIn: totalin, TotalOut: totalout, TaxCoin: playerEx.taxCoin, BetAmount: playerEx.totalBet, WinAmountNoAnyTax: totalout - totalin - playerEx.taxCoin, - ValidBet: validBet, - ValidFlow: validFlow, IsFirstGame: sceneEx.IsPlayerFirst(playerEx.Player), - } - sceneEx.SaveGamePlayerListLog(playerEx.SnId, logParam) + IsFree: totalin == 0, + GameTime: 2, + }) } } From b1d365e03001166d9d632bfc19abf92593701963 Mon Sep 17 00:00:00 2001 From: sk <123456@qq.com> Date: Mon, 2 Dec 2024 17:10:19 +0800 Subject: [PATCH 19/41] =?UTF-8?q?=E5=A5=BD=E5=8F=8B=E7=94=B3=E8=AF=B7?= =?UTF-8?q?=E6=95=B0=E6=8D=AE=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- worldsrv/friendmgr.go | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/worldsrv/friendmgr.go b/worldsrv/friendmgr.go index 9a18df5..c10caea 100644 --- a/worldsrv/friendmgr.go +++ b/worldsrv/friendmgr.go @@ -621,11 +621,13 @@ func (this *FriendMgr) FriendAgree(p *Player, destP *model.BindFriend) { return friend.OpResultCode_OPRC_Error } if list1 != nil { - for k, v := range list1.ApplySnids { - if v.SnId == applySnid { + k := 0 + for k < len(list1.ApplySnids) { + if list1.ApplySnids[k].SnId == applySnid { list1.ApplySnids = append(list1.ApplySnids[:k], list1.ApplySnids[k+1:]...) model.UpsertFriendApply(plt, snid, list1) - break + } else { + k++ } } } @@ -636,11 +638,13 @@ func (this *FriendMgr) FriendAgree(p *Player, destP *model.BindFriend) { return friend.OpResultCode_OPRC_Error } if list2 != nil { - for k, v := range list2.List { - if v == snid { + k := 0 + for k < len(list2.List) { + if list2.List[k] == snid { list2.List = append(list2.List[:k], list2.List[k+1:]...) model.UpsertApplyList(plt, list2) - break + } else { + k++ } } } From bdac067402b06c8dc7b54f87608e0166fdbe6265 Mon Sep 17 00:00:00 2001 From: sk <123456@qq.com> Date: Mon, 2 Dec 2024 17:53:07 +0800 Subject: [PATCH 20/41] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=8D=81=E4=B8=89?= =?UTF-8?q?=E5=BC=A0=E9=A2=84=E9=80=89=E7=89=8C=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gamerule/thirteen/constants.go | 1 + gamesrv/thirteen/player.go | 2 ++ gamesrv/thirteen/scenepolicy.go | 34 +++++++++++++++++++++++++++++++++ 3 files changed, 37 insertions(+) diff --git a/gamerule/thirteen/constants.go b/gamerule/thirteen/constants.go index 64d4508..d3eb482 100644 --- a/gamerule/thirteen/constants.go +++ b/gamerule/thirteen/constants.go @@ -34,6 +34,7 @@ const ( ThirteenWaterPlayerOpTest = 3 // test ThirteenWaterPlayerOpReset = 4 // 重新选牌 ThirteenWaterPlayerJoin = 5 // 加入游戏 + ThirteenWaterPlayerOpSelect = 6 // 预选牌 ) const ( ThirteenWaterSceneWaitTimeout = time.Second * 2 //等待倒计时 diff --git a/gamesrv/thirteen/player.go b/gamesrv/thirteen/player.go index f3d5a70..d59c380 100644 --- a/gamesrv/thirteen/player.go +++ b/gamesrv/thirteen/player.go @@ -12,6 +12,7 @@ type PlayerEx struct { cards [13]int //手牌信息 allGroup map[int]*thirteen.Group //玩家所有牌型 cardsO *thirteen.Group //确定的牌型信息 + preCardsO *thirteen.Group //预确定的牌型 isDP bool // 是否倒排 gainCoin int64 //本局赢的金币 taxCoin int64 //本局税收 @@ -36,6 +37,7 @@ func (this *PlayerEx) Clear() { } this.allGroup = make(map[int]*thirteen.Group) this.cardsO = &thirteen.Group{Head: [3]int{-1, -1, -1}, Mid: [5]int{-1, -1, -1, -1, -1}, End: [5]int{-1, -1, -1, -1, -1}, PokerType: -1} + this.preCardsO = &thirteen.Group{Head: [3]int{-1, -1, -1}, Mid: [5]int{-1, -1, -1, -1, -1}, End: [5]int{-1, -1, -1, -1, -1}, PokerType: -1} this.isDP = false this.gainCoin = 0 this.taxCoin = 0 diff --git a/gamesrv/thirteen/scenepolicy.go b/gamesrv/thirteen/scenepolicy.go index 331c12f..05d9b36 100644 --- a/gamesrv/thirteen/scenepolicy.go +++ b/gamesrv/thirteen/scenepolicy.go @@ -870,6 +870,7 @@ func (this *StateOp) OnPlayerOp(s *base.Scene, p *base.Player, opcode int, param } else { sceneEx.SendSelectCards(playerEx, int(params[0]), int64(opcode)) } + playerEx.preCardsO = &rule.Group{Head: [3]int{-1, -1, -1}, Mid: [5]int{-1, -1, -1, -1, -1}, End: [5]int{-1, -1, -1, -1, -1}, PokerType: -1} playerEx.Trusteeship = 0 playerEx.UnmarkFlag(base.PlayerState_Auto) playerEx.deterMine = true @@ -886,6 +887,34 @@ func (this *StateOp) OnPlayerOp(s *base.Scene, p *base.Player, opcode int, param //提前进入亮牌阶段 s.ChangeSceneState(rule.ThirteenWaterSceneStateShowCards) } + + case rule.ThirteenWaterPlayerOpSelect: + playerEx.deterMine = false + playerEx.cardsO = &rule.Group{Head: [3]int{-1, -1, -1}, Mid: [5]int{-1, -1, -1, -1, -1}, End: [5]int{-1, -1, -1, -1, -1}, PokerType: -1} + playerEx.Trusteeship = 0 + playerEx.UnmarkFlag(base.PlayerState_Auto) + pack := &thirteen.SCThirteenPlayerOp{ + OpRetCode: thirteen.OpResultCode_OPRC_Sucess, + OpCode: int32(opcode), + OpParam: params, + Pos: int32(playerEx.GetPos()), + } + if len(params) == 13 { + //校验牌 + a := rule.DelCards(playerEx.cards[:], common.Int64Toint(params)) + if len(a) != 0 { + logger.Logger.Error("the cards is error.") + returnFunc(thirteen.OpResultCode_OPRC_Error) + return true + } + //牌赋值 + copy(playerEx.preCardsO.Head[:], common.Int64Toint(params[:3])) + copy(playerEx.preCardsO.Mid[:], common.Int64Toint(params[3:8])) + copy(playerEx.preCardsO.End[:], common.Int64Toint(params[8:])) + playerEx.preCardsO.PokerType = 0 + } + playerEx.SendToClient(int(thirteen.TWMmoPacketID_PACKET_SCThirteenPlayerOp), pack) + case rule.ThirteenWaterPlayerOpReset: // 取消确认 playerEx.deterMine = false @@ -913,6 +942,11 @@ func (this *StateOp) OnLeave(s *base.Scene) { for _, player := range sceneEx.players { if player != nil && player.IsGameing() { + // 使用预选牌 + if player.preCardsO != nil && player.preCardsO.PokerType != -1 && (player.cardsO == nil || player.cardsO.PokerType == -1) { + player.cardsO = player.preCardsO + } + // 判断是否倒水 if player.cardsO != nil && player.cardsO.PokerType != -1 { if player.cardsO.PokerType < 1000000 { player.isDP = sceneEx.logic.IsDP(player.cardsO.Head, player.cardsO.Mid, player.cardsO.End) From 2b8815517775fc35de9f54b2c17563434154582c Mon Sep 17 00:00:00 2001 From: sk <123456@qq.com> Date: Mon, 2 Dec 2024 17:57:46 +0800 Subject: [PATCH 21/41] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=8D=81=E4=B8=89?= =?UTF-8?q?=E5=BC=A0=E9=A2=84=E9=80=89=E7=89=8C=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- protocol/thirteen/thirteen.pb.go | 2 +- protocol/thirteen/thirteen.proto | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/protocol/thirteen/thirteen.pb.go b/protocol/thirteen/thirteen.pb.go index e3c891e..77cbe10 100644 --- a/protocol/thirteen/thirteen.pb.go +++ b/protocol/thirteen/thirteen.pb.go @@ -386,7 +386,7 @@ type CSThirteenPlayerOp struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - OpCode int32 `protobuf:"varint,1,opt,name=OpCode,proto3" json:"OpCode,omitempty"` // 1:确定牌 2站起状态 3test 4重新选牌 5加入游戏 + OpCode int32 `protobuf:"varint,1,opt,name=OpCode,proto3" json:"OpCode,omitempty"` // 1:确定牌 2站起状态 3test 4重新选牌 5加入游戏 6预选 // 确定牌时,两种参数规则,都可以 // 第一种:玩家从推荐牌型中选择一个,把Poker.IndexType发过来(减少数据传输) // 第二种:按头墩中墩尾墩顺序把牌发过来 diff --git a/protocol/thirteen/thirteen.proto b/protocol/thirteen/thirteen.proto index 0ac7d2d..fe2bed2 100644 --- a/protocol/thirteen/thirteen.proto +++ b/protocol/thirteen/thirteen.proto @@ -73,7 +73,7 @@ message SCThirteenPlayerCards { //玩家操作 //PACKET_CSThirteenPlayerOp message CSThirteenPlayerOp { - int32 OpCode = 1; // 1:确定牌 2站起状态 3test 4重新选牌 5加入游戏 + int32 OpCode = 1; // 1:确定牌 2站起状态 3test 4重新选牌 5加入游戏 6预选 // 确定牌时,两种参数规则,都可以 // 第一种:玩家从推荐牌型中选择一个,把Poker.IndexType发过来(减少数据传输) From 8e5f5e4e47b5e15ccc2a459287b6a1559fddaff8 Mon Sep 17 00:00:00 2001 From: sk <123456@qq.com> Date: Mon, 2 Dec 2024 13:06:07 +0800 Subject: [PATCH 22/41] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E7=89=8C=E5=B1=80?= =?UTF-8?q?=E8=AE=B0=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gamesrv/avengers/scenepolicy_avengers.go | 27 +- gamesrv/base/player.go | 56 ++- gamesrv/base/scene.go | 353 ++++++++++-------- gamesrv/caishen/scenepolicy_caishen.go | 26 +- gamesrv/chess/scene.go | 1 + gamesrv/chess/scenepolicy.go | 26 +- gamesrv/clawdoll/scenepolicy_clawdoll.go | 40 +- .../easterisland/scenepolicy_easterisland.go | 26 +- gamesrv/fishing/playerdata_fishing.go | 25 +- .../scenepolicy_fortunedragon.go | 27 +- gamesrv/fortuneox/scenepolicy_fortuneox.go | 29 +- .../scenepolicy_fortunerabbit.go | 29 +- .../fortunetiger/scenepolicy_fortunetiger.go | 29 +- gamesrv/fruits/scenedata_fruits.go | 38 +- gamesrv/iceage/scenepolicy_iceage.go | 26 +- gamesrv/richblessed/scenedata_richblessed.go | 38 +- gamesrv/smallrocket/scene.go | 2 + gamesrv/smallrocket/scenepolicy.go | 59 ++- gamesrv/tamquoc/scenepolicy_tamquoc.go | 26 +- gamesrv/thirteen/scenepolicy.go | 49 ++- gamesrv/tienlen/scenepolicy_tienlen.go | 32 +- model/dataevent.go | 43 --- model/gamelogtype.go | 2 + model/gameplayerlistlog.go | 4 +- 24 files changed, 556 insertions(+), 457 deletions(-) diff --git a/gamesrv/avengers/scenepolicy_avengers.go b/gamesrv/avengers/scenepolicy_avengers.go index b73f65c..c9334c3 100644 --- a/gamesrv/avengers/scenepolicy_avengers.go +++ b/gamesrv/avengers/scenepolicy_avengers.go @@ -934,31 +934,30 @@ func AvengersCheckAndSaveLog(sceneEx *AvengersSceneData, playerEx *AvengersPlaye if err == nil { logid, _ := model.AutoIncGameLogId() playerEx.currentLogId = logid - sceneEx.SaveGameDetailedLog(logid, info, &base.GameDetailedParam{}) + sceneEx.SaveGameDetailedLog(&base.SaveGameDetailedParam{ + LogId: logid, + Detail: info, + GameTime: 1, + }) totalin := int64(playerEx.RollGameType.BaseResult.TotalBet) totalout := playerEx.RollGameType.BaseResult.ChangeCoin + playerEx.taxCoin + totalin - validFlow := totalin + totalout - validBet := common.AbsI64(totalin - totalout) - logParam := &base.SaveGamePlayerListLogParam{ - Platform: playerEx.Platform, - Channel: playerEx.Channel, - Promoter: playerEx.BeUnderAgentCode, - PackageTag: playerEx.PackageID, - InviterId: playerEx.InviterId, + sceneEx.SaveGamePlayerListLog(&base.SaveGamePlayerListLogParam{ LogId: logid, + Platform: playerEx.Platform, + Snid: playerEx.SnId, + Channel: playerEx.Channel, + ChannelId: playerEx.ChannelId, TotalIn: totalin, TotalOut: totalout, TaxCoin: playerEx.taxCoin, BetAmount: int64(playerEx.RollGameType.BaseResult.TotalBet), WinAmountNoAnyTax: playerEx.RollGameType.BaseResult.ChangeCoin, - ValidBet: validBet, - ValidFlow: validFlow, - IsFirstGame: sceneEx.IsPlayerFirst(playerEx.Player), + IsFirstGame: false, IsFree: playerEx.RollGameType.BaseResult.IsFree, WinSmallGame: playerEx.RollGameType.BaseResult.WinSmallGame, WinTotal: playerEx.RollGameType.BaseResult.WinTotal, - } - sceneEx.SaveGamePlayerListLog(playerEx.SnId, logParam) + GameTime: 1, + }) } } } diff --git a/gamesrv/base/player.go b/gamesrv/base/player.go index 53d263d..5f47a55 100644 --- a/gamesrv/base/player.go +++ b/gamesrv/base/player.go @@ -2,6 +2,7 @@ package base import ( "fmt" + "github.com/jinzhu/now" "math" "math/rand" "time" @@ -621,7 +622,14 @@ func (this *Player) AddRankScore(rankType int32, num int64) { } } -func (this *Player) ReportGameEvent(tax, taxex, changeCoin, validbet, validFlow, in, out int64) { +type ReportGameEventParam struct { + Tax int64 // 税收 + Change int64 // 净输赢,正负值,不带税收 + In, Out int64 // 投入,产出(税前) + GameTime int64 // 游戏时长,秒 +} + +func (this *Player) ReportGameEvent(param *ReportGameEventParam) { // 记录玩家 首次参与该场次的游戏时间 游戏次数 var gameFirstTime, gameFreeFirstTime time.Time var gameTimes, gameFreeTimes int64 @@ -638,12 +646,46 @@ func (this *Player) ReportGameEvent(tax, taxex, changeCoin, validbet, validFlow, gameFreeTimes = dataGame.Statics.GameTimes } - gamingTime := int32(time.Now().Sub(this.scene.GameNowTime).Seconds()) - mq.Write(model.CreatePlayerGameRecEvent(this.SnId, tax, taxex, changeCoin, validbet, validFlow, in, out, - this.scene.GameId, this.scene.GetGameFreeId(), int32(this.scene.GameMode), - this.scene.GetRecordId(), this.Channel, this.ChannelId, this.BeUnderAgentCode, this.Platform, this.City, this.DeviceOS, - this.CreateTime, gamingTime, gameFirstTime, gameFreeFirstTime, gameTimes, gameFreeTimes, this.LastLoginTime, - this.TelephonePromoter, this.DeviceId), mq.BackGameRecord) + isNew := int32(0) + tCreateDay := now.New(this.CreateTime.Local()).BeginningOfDay() + if now.BeginningOfDay().Equal(tCreateDay) { + isNew = 1 + } + + if param.GameTime < 0 { + param.GameTime = int64(time.Now().Sub(this.scene.GameNowTime).Seconds()) + } + if param.GameTime < 0 { + param.GameTime = 0 + } + + log := &model.PlayerGameRecEvent{ + Platform: this.Platform, + RecordId: this.scene.GetRecordId(), + SnId: this.GetSnId(), + Channel: this.Channel, + ChannelId: this.ChannelId, + City: this.City, + OS: this.DeviceOS, + GameId: this.scene.GameId, + ModeId: this.scene.GameMode, + Tax: param.Tax, + Amount: param.Change, + CreateTime: this.CreateTime.Unix(), + CreateDayTime: tCreateDay.Unix(), + Out: param.Out, + In: param.In, + IsNew: isNew, + GameFreeID: this.scene.GetGameFreeId(), + GamingTime: int32(param.GameTime), + FirstTime: gameFirstTime.Unix(), + PlayTimes: gameTimes, + FirstGameTime: gameFreeFirstTime.Unix(), + PlayGameTimes: gameFreeTimes, + LastLoginTime: this.LastLoginTime.Unix(), + DeviceId: this.DeviceId, + } + mq.Write(log, mq.BackGameRecord) } // 汇总玩家该次游戏总产生的税收 diff --git a/gamesrv/base/scene.go b/gamesrv/base/scene.go index a0ca96f..cb10fac 100644 --- a/gamesrv/base/scene.go +++ b/gamesrv/base/scene.go @@ -2,6 +2,7 @@ package base import ( "fmt" + "github.com/globalsign/mgo/bson" "math" "math/rand" "strconv" @@ -87,7 +88,8 @@ type Scene struct { SystemCoinOut int64 //本局游戏机器人营收 机器人赢:正值 机器人输:负值 ChessRank []int32 RealCtrl bool - CycleID string + CycleID string // 房卡场多轮对局id + LogId string // 游戏每局id } func NewScene(args *CreateSceneParam) *Scene { @@ -160,75 +162,104 @@ func (this *Scene) GetGameFreeId() int32 { 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 { - return int(this.WGCreateScene.GetPlayerNum()) + 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 } @@ -236,42 +267,55 @@ func (this *Scene) GetParams() []int64 { 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 } @@ -1403,112 +1447,6 @@ func (this *Scene) ClearAutoPlayer() { } } -type GameDetailedParam struct { - Trend20Lately string //最近20局开奖结果 - CtrlType int - PlayerPool map[int]int - CycleId string -} - -// 保存详细游戏日志 -func (this *Scene) SaveGameDetailedLog(logid string, gamedetailednote string, gameDetailedParam *GameDetailedParam) { - if this != nil { - if !this.Testing { //测试场屏蔽掉 - trend20Lately := gameDetailedParam.Trend20Lately - baseScore := this.GetDBGameFree().GetBaseScore() - if common.IsLocalGame(int(this.GameId)) { - baseScore = this.BaseScore - } - if this.IsCoinScene() { - mapPlatform := make(map[string]bool) - for _, p := range this.Players { - if _, ok := mapPlatform[p.Platform]; !ok { - mapPlatform[p.Platform] = true - log := model.NewGameDetailedLogEx(logid, int32(this.GameId), int32(this.SceneId), - this.GetDBGameFree().GetGameMode(), this.GetDBGameFree().Id, int32(len(this.Players)), - int32(time.Now().Unix()-this.GameNowTime.Unix()), baseScore, - gamedetailednote, p.Platform, this.ClubId, this.RoomId, this.CpCtx, GameDetailedVer[int(this.GameId)], trend20Lately, - gameDetailedParam.CtrlType, gameDetailedParam.PlayerPool, gameDetailedParam.CycleId) - if log != nil { - if this.IsMatchScene() { - log.MatchId = this.GetMatch().GetMatchSortId() - } - if this.IsCustom() { - log.CycleId = this.CycleID - } - mq.Write(log) - } - } - } - } else { - log := model.NewGameDetailedLogEx(logid, int32(this.GameId), int32(this.SceneId), - this.GetDBGameFree().GetGameMode(), this.GetDBGameFree().Id, int32(len(this.Players)), - int32(time.Now().Unix()-this.GameNowTime.Unix()), baseScore, - gamedetailednote, this.Platform, this.ClubId, this.RoomId, this.CpCtx, GameDetailedVer[int(this.GameId)], trend20Lately, - gameDetailedParam.CtrlType, gameDetailedParam.PlayerPool, gameDetailedParam.CycleId) - if log != nil { - if this.IsMatchScene() { - log.MatchId = this.GetMatch().GetMatchSortId() - } - if this.IsCustom() { - log.CycleId = this.CycleID - } - newLog := new(model.GameDetailedLog) - *newLog = *log - mq.Write(log) - } - } - } - } -} - -type SaveGamePlayerListLogParam struct { - Platform string //平台 - Channel string //渠道 - Promoter string //推广员 - PackageTag string //包标识 - InviterId int32 //邀请人 - LogId string //日志id - TotalIn int64 //总投入 - TotalOut int64 //总产出 - TaxCoin int64 //总税收 - ClubPumpCoin int64 //俱乐部抽水 - BetAmount int64 //下注量 - WinAmountNoAnyTax int64 //税后赢取额(净利润,正负值) - ValidBet int64 //有效下注 - ValidFlow int64 //有效流水 - IsFirstGame bool //是否第一次游戏 - IsLeave bool //是否中途离开,用于金花,德州可以中途离开游戏使用 - IsFree bool //拉霸专用 是否免费 - WinSmallGame int64 //拉霸专用 小游戏奖励 - WinTotal int64 //拉霸专用 本局输赢 - PlayerName string //玩家名字 - CycleId string // 房卡场对局id -} - -func GetSaveGamePlayerListLogParam(platform, channel, promoter, packageTag, logid string, - inviterId int32, totalin, totalout, taxCoin, clubPumpCoin, betAmount, winAmountNoAnyTax, validBet, validFlow int64, - isFirstGame, isLeave bool) *SaveGamePlayerListLogParam { - return &SaveGamePlayerListLogParam{ - Platform: platform, - Channel: channel, - Promoter: promoter, - PackageTag: packageTag, - InviterId: inviterId, - LogId: logid, - TotalIn: totalin, - TotalOut: totalout, - TaxCoin: taxCoin, - ClubPumpCoin: clubPumpCoin, - BetAmount: betAmount, - WinAmountNoAnyTax: winAmountNoAnyTax, - ValidBet: validBet, - ValidFlow: validFlow, - IsFirstGame: isFirstGame, - IsLeave: isLeave, - } -} - func (this *Scene) SaveFriendRecord(snid int32, isWin int32, billCoin int64, baseScore int32) { if this.SceneMode == common.SceneModePrivate { return @@ -1519,55 +1457,160 @@ func (this *Scene) SaveFriendRecord(snid int32, isWin int32, billCoin int64, bas } } -// 保存玩家和GameDetailedLog的映射表 -func (this *Scene) SaveGamePlayerListLog(snid int32, param *SaveGamePlayerListLogParam) { - if this != nil { - if !this.Testing { //测试场屏蔽掉 龙虎两边都压,totalin和totalout都=0,这个条件去掉 - //统计流水值 - playerEx := this.GetPlayer(snid) - //有些结算的时候,玩家已经退场,不要用是否在游戏,0709,修改为扣税后数值 - if playerEx != nil && !param.IsLeave && !playerEx.IsRob && (param.IsFree || param.TotalIn != 0 || param.TotalOut != 0) { - totalFlow := param.ValidFlow * int64(this.GetDBGameFree().GetBetWaterRate()) / 100 - playerEx.TotalConvertibleFlow += totalFlow - playerEx.TotalFlow += totalFlow - playerEx.ValidCacheBetTotal += param.ValidBet - //报表统计 - //playerEx.SaveReportForm(int(this.GetDBGameFree().GetGameClass()), this.SceneMode, this.KeyGameId, - // param.WinAmountNoAnyTax, totalFlow, param.ValidBet) - //分配利润 - ProfitDistribution(playerEx, param.TaxCoin, param.ClubPumpCoin, totalFlow) - //上报游戏事件 - playerEx.ReportGameEvent(param.TaxCoin, param.ClubPumpCoin, param.WinAmountNoAnyTax, param.ValidBet, totalFlow, param.TotalIn, param.TotalOut) - } +type SaveGameDetailedParam struct { + LogId string // 日志id + Detail string // 游戏详细信息 + GameTime int64 // 游戏时长 + Trend20Lately string // 最近20局开奖结果 + CtrlType int // 调控类型 1控赢 2控输 + PlayerPool map[int]int // 个人水池分 +} - roomType := int32(this.SceneMode) - if this.GameId == common.GameId_Avengers || - this.GameId == common.GameId_CaiShen || - this.GameId == common.GameId_EasterIsland || - this.GameId == common.GameId_IceAge || - this.GameId == common.GameId_TamQuoc { //复仇者联盟强制为0,所有场次操作记录放一起 - roomType = 0 - } - baseScore := this.GetDBGameFree().GetBaseScore() - if common.IsLocalGame(int(this.GameId)) { - baseScore = this.BaseScore - } - - Name := param.PlayerName - if playerEx != nil { - Name = param.PlayerName - } - - log := model.NewGamePlayerListLogEx(snid, param.LogId, param.Platform, param.Channel, param.Promoter, param.PackageTag, - this.GameId, baseScore, this.SceneId, int32(this.GetGameMode()), - this.GetGameFreeId(), param.TotalIn, param.TotalOut, this.ClubId, this.RoomId, param.TaxCoin, param.ClubPumpCoin, roomType, - param.BetAmount, param.WinAmountNoAnyTax, this.KeyGameId, Name, this.GetDBGameFree().GetGameClass(), - param.IsFirstGame, this.GetMatch().GetMatchSortId(), int64(this.GetMatch().GetMatchType()), param.IsFree, param.WinSmallGame, param.WinTotal, param.CycleId) - if log != nil { - mq.Write(log) - } - } +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 { diff --git a/gamesrv/caishen/scenepolicy_caishen.go b/gamesrv/caishen/scenepolicy_caishen.go index cf4ba08..aa21249 100644 --- a/gamesrv/caishen/scenepolicy_caishen.go +++ b/gamesrv/caishen/scenepolicy_caishen.go @@ -1023,31 +1023,31 @@ func CaiShenCheckAndSaveLog(sceneEx *CaiShenSceneData, playerEx *CaiShenPlayerDa if err == nil { logid, _ := model.AutoIncGameLogId() playerEx.currentLogId = logid - sceneEx.SaveGameDetailedLog(logid, info, &base.GameDetailedParam{}) + sceneEx.SaveGameDetailedLog(&base.SaveGameDetailedParam{ + LogId: logid, + Detail: info, + GameTime: 1, + }) totalin := int64(playerEx.RollGameType.BaseResult.TotalBet) totalout := playerEx.RollGameType.BaseResult.ChangeCoin + playerEx.taxCoin + totalin - validFlow := totalin + totalout - validBet := common.AbsI64(totalin - totalout) - logParam := &base.SaveGamePlayerListLogParam{ - Platform: playerEx.Platform, - Channel: playerEx.Channel, - Promoter: playerEx.BeUnderAgentCode, - PackageTag: playerEx.PackageID, - InviterId: playerEx.InviterId, + sceneEx.SaveGamePlayerListLog(&base.SaveGamePlayerListLogParam{ LogId: logid, + Platform: playerEx.Platform, + Snid: playerEx.SnId, + PlayerName: playerEx.Name, + Channel: playerEx.Channel, + ChannelId: playerEx.ChannelId, TotalIn: totalin, TotalOut: totalout, TaxCoin: playerEx.taxCoin, BetAmount: int64(playerEx.RollGameType.BaseResult.TotalBet), WinAmountNoAnyTax: playerEx.RollGameType.BaseResult.ChangeCoin, - ValidBet: validBet, - ValidFlow: validFlow, IsFirstGame: sceneEx.IsPlayerFirst(playerEx.Player), IsFree: playerEx.RollGameType.BaseResult.IsFree, WinSmallGame: playerEx.RollGameType.BaseResult.WinSmallGame, WinTotal: playerEx.RollGameType.BaseResult.WinTotal, - } - sceneEx.SaveGamePlayerListLog(playerEx.SnId, logParam) + GameTime: 1, + }) } } } diff --git a/gamesrv/chess/scene.go b/gamesrv/chess/scene.go index ad40fdf..00ba0dc 100644 --- a/gamesrv/chess/scene.go +++ b/gamesrv/chess/scene.go @@ -767,6 +767,7 @@ func (e *SceneEx) ToBilled(p1, p2 *PlayerEx, isWin int) (*chesstitians.Chesstiti UserIcon: p1.Head, Platform: p1.Platform, Channel: p1.Channel, + ChannelId: p1.ChannelId, Promoter: p1.BeUnderAgentCode, PackageTag: p1.PackageID, InviterId: p1.InviterId, diff --git a/gamesrv/chess/scenepolicy.go b/gamesrv/chess/scenepolicy.go index 95084c5..116ecdd 100644 --- a/gamesrv/chess/scenepolicy.go +++ b/gamesrv/chess/scenepolicy.go @@ -1298,9 +1298,6 @@ func (this *SceneStateBilled) OnEnter(s *base.Scene) { } else { totalout += (o_player.GainCoin + o_player.GainTaxCoin) } - - validFlow := totalin + totalout - validBet := common.AbsI64(totalin - totalout) sceneEx.SaveFriendRecord(o_player.UserId, o_player.IsWin, o_player.GainCoin, sceneEx.GetBaseScore()) // 游戏数据统计 @@ -1313,16 +1310,29 @@ func (this *SceneStateBilled) OnEnter(s *base.Scene) { }) // 玩家游戏记录 - sceneEx.SaveGamePlayerListLog(o_player.UserId, - base.GetSaveGamePlayerListLogParam(o_player.Platform, o_player.Channel, o_player.Promoter, - o_player.PackageTag, logid, o_player.InviterId, totalin, totalout, o_player.GainTaxCoin, - 0, 0, o_player.GainCoin, validBet, validFlow, o_player.IsFirst, o_player.IsLeave)) + sceneEx.SaveGamePlayerListLog(&base.SaveGamePlayerListLogParam{ + LogId: logid, + Platform: o_player.Platform, + Snid: o_player.UserId, + PlayerName: "", + Channel: o_player.Channel, + ChannelId: o_player.ChannelId, + TotalIn: totalin, + TotalOut: totalout, + TaxCoin: o_player.GainTaxCoin, + BetAmount: 0, + WinAmountNoAnyTax: o_player.GainCoin, + IsFirstGame: o_player.IsFirst, + }) isSave = true } } if isSave { // 牌局记录 - sceneEx.SaveGameDetailedLog(logid, info, &base.GameDetailedParam{}) + sceneEx.SaveGameDetailedLog(&base.SaveGameDetailedParam{ + LogId: logid, + Detail: info, + }) } } sceneEx.NotifySceneRoundPause() diff --git a/gamesrv/clawdoll/scenepolicy_clawdoll.go b/gamesrv/clawdoll/scenepolicy_clawdoll.go index 6b2d895..ce712e3 100644 --- a/gamesrv/clawdoll/scenepolicy_clawdoll.go +++ b/gamesrv/clawdoll/scenepolicy_clawdoll.go @@ -781,34 +781,28 @@ func (this *StateBilled) OnEnter(s *base.Scene) { sceneEx.logid, _ = model.AutoIncGameLogId() info, err := model.MarshalGameNoteByHUNDRED(LogBaseResult) if err == nil { - sceneEx.SaveGameDetailedLog(sceneEx.logid, info, &base.GameDetailedParam{}) + sceneEx.SaveGameDetailedLog(&base.SaveGameDetailedParam{ + LogId: sceneEx.logid, + Detail: info, + }) } TotalBetValue := 0 totalin := int64(TotalBetValue) totalout := playerEx.gainCoin - validFlow := totalin + totalout - validBet := common.AbsI64(totalin - totalout) - logParam := &base.SaveGamePlayerListLogParam{ - Platform: playerEx.Platform, - Channel: playerEx.Channel, - Promoter: playerEx.BeUnderAgentCode, - PackageTag: playerEx.PackageID, - InviterId: playerEx.InviterId, - LogId: sceneEx.logid, - TotalIn: totalin, - TotalOut: totalout, - TaxCoin: playerEx.taxCoin, - BetAmount: int64(TotalBetValue), - WinAmountNoAnyTax: playerEx.gainCoin, - ValidBet: validBet, - ValidFlow: validFlow, - IsFirstGame: sceneEx.IsPlayerFirst(playerEx.Player), - IsFree: false, - WinSmallGame: 0, - WinTotal: 0, - } - sceneEx.SaveGamePlayerListLog(playerEx.SnId, logParam) + sceneEx.SaveGamePlayerListLog(&base.SaveGamePlayerListLogParam{ + LogId: sceneEx.logid, + Platform: playerEx.Platform, + Snid: playerEx.SnId, + PlayerName: playerEx.Name, + Channel: playerEx.Channel, + ChannelId: playerEx.ChannelId, + TotalIn: totalin, + TotalOut: totalout, + TaxCoin: playerEx.taxCoin, + BetAmount: int64(TotalBetValue), + IsFirstGame: sceneEx.IsPlayerFirst(playerEx.Player), + }) } playerEx.lastIsWin = playerEx.IsWin diff --git a/gamesrv/easterisland/scenepolicy_easterisland.go b/gamesrv/easterisland/scenepolicy_easterisland.go index 2474ad4..677d88b 100644 --- a/gamesrv/easterisland/scenepolicy_easterisland.go +++ b/gamesrv/easterisland/scenepolicy_easterisland.go @@ -892,31 +892,31 @@ func EasterIslandCheckAndSaveLog(sceneEx *EasterIslandSceneData, playerEx *Easte if err == nil { logid, _ := model.AutoIncGameLogId() playerEx.currentLogId = logid - sceneEx.SaveGameDetailedLog(logid, info, &base.GameDetailedParam{}) + sceneEx.SaveGameDetailedLog(&base.SaveGameDetailedParam{ + LogId: logid, + Detail: info, + GameTime: 1, + }) totalin := int64(playerEx.RollGameType.BaseResult.TotalBet) totalout := playerEx.RollGameType.BaseResult.ChangeCoin + playerEx.taxCoin + totalin - validFlow := totalin + totalout - validBet := common.AbsI64(totalin - totalout) - logParam := &base.SaveGamePlayerListLogParam{ - Platform: playerEx.Platform, - Channel: playerEx.Channel, - Promoter: playerEx.BeUnderAgentCode, - PackageTag: playerEx.PackageID, - InviterId: playerEx.InviterId, + sceneEx.SaveGamePlayerListLog(&base.SaveGamePlayerListLogParam{ LogId: logid, + Platform: playerEx.Platform, + Snid: playerEx.SnId, + PlayerName: playerEx.Name, + Channel: playerEx.Channel, + ChannelId: playerEx.ChannelId, TotalIn: totalin, TotalOut: totalout, TaxCoin: playerEx.taxCoin, BetAmount: int64(playerEx.RollGameType.BaseResult.TotalBet), WinAmountNoAnyTax: playerEx.RollGameType.BaseResult.ChangeCoin, - ValidBet: validBet, - ValidFlow: validFlow, IsFirstGame: sceneEx.IsPlayerFirst(playerEx.Player), IsFree: playerEx.RollGameType.BaseResult.IsFree, WinSmallGame: playerEx.RollGameType.BaseResult.WinSmallGame, WinTotal: playerEx.RollGameType.BaseResult.WinTotal, - } - sceneEx.SaveGamePlayerListLog(playerEx.SnId, logParam) + GameTime: 1, + }) } } } diff --git a/gamesrv/fishing/playerdata_fishing.go b/gamesrv/fishing/playerdata_fishing.go index cad0291..8e244fa 100644 --- a/gamesrv/fishing/playerdata_fishing.go +++ b/gamesrv/fishing/playerdata_fishing.go @@ -262,13 +262,24 @@ func (this *FishingPlayerData) SaveDetailedLog(s *base.Scene) { info, err := model.MarshalGameNoteByFISH(&fd) if err == nil { logid, _ := model.AutoIncGameLogId() - validFlow := totalin + totalout - validBet := common.AbsI64(totalin - totalout) - param := base.GetSaveGamePlayerListLogParam(this.Platform, this.Channel, this.BeUnderAgentCode, this.PackageID, logid, - this.InviterId, totalin, totalout, int64(this.sTaxCoin), 0, totalin, - totalout, validFlow, validBet, sceneEx.IsPlayerFirst(this.Player), false) - sceneEx.SaveGamePlayerListLog(this.SnId, param) - sceneEx.SaveGameDetailedLog(logid, info, &base.GameDetailedParam{}) + sceneEx.SaveGamePlayerListLog(&base.SaveGamePlayerListLogParam{ + LogId: logid, + Platform: this.Platform, + Snid: this.SnId, + PlayerName: this.Name, + Channel: this.Channel, + ChannelId: this.ChannelId, + TotalIn: totalin, + TotalOut: totalout, + TaxCoin: int64(this.sTaxCoin), + BetAmount: totalin, + WinAmountNoAnyTax: totalout, + IsFirstGame: sceneEx.IsPlayerFirst(this.Player), + }) + sceneEx.SaveGameDetailedLog(&base.SaveGameDetailedParam{ + LogId: logid, + Detail: info, + }) } pack := &server_proto.GWFishRecord{ diff --git a/gamesrv/fortunedragon/scenepolicy_fortunedragon.go b/gamesrv/fortunedragon/scenepolicy_fortunedragon.go index c5fc2d8..cea24a8 100644 --- a/gamesrv/fortunedragon/scenepolicy_fortunedragon.go +++ b/gamesrv/fortunedragon/scenepolicy_fortunedragon.go @@ -512,7 +512,11 @@ func FortuneDragonAndSaveLog(sceneEx *FortuneDragonSceneData, playerEx *FortuneD if err == nil { logid, _ := model.AutoIncGameLogId() playerEx.currentLogId = logid - sceneEx.SaveGameDetailedLog(logid, info, &base.GameDetailedParam{}) + sceneEx.SaveGameDetailedLog(&base.SaveGameDetailedParam{ + LogId: logid, + Detail: info, + GameTime: 1, + }) var totalin, totalout int64 if data.Results[0].FreeStatus == 1 || data.Results[0].FreeNumMax == 0 { totalin = playerEx.totalBet @@ -520,25 +524,22 @@ func FortuneDragonAndSaveLog(sceneEx *FortuneDragonSceneData, playerEx *FortuneD if data.Results[0].FreeStatus == 3 || data.Results[0].FreeNumMax == 0 { totalout = int64(data.RoundReward) + playerEx.taxCoin } - validFlow := totalin + totalout - validBet := common.AbsI64(totalin - totalout) - logParam := &base.SaveGamePlayerListLogParam{ - Platform: playerEx.Platform, - Channel: playerEx.Channel, - Promoter: playerEx.BeUnderAgentCode, - PackageTag: playerEx.PackageID, - InviterId: playerEx.InviterId, + sceneEx.SaveGamePlayerListLog(&base.SaveGamePlayerListLogParam{ LogId: logid, + Platform: playerEx.Platform, + Snid: playerEx.SnId, + PlayerName: playerEx.Name, + Channel: playerEx.Channel, + ChannelId: playerEx.ChannelId, TotalIn: totalin, TotalOut: totalout, TaxCoin: playerEx.taxCoin, BetAmount: totalin, WinAmountNoAnyTax: totalout - totalin - playerEx.taxCoin, - ValidBet: validBet, - ValidFlow: validFlow, IsFirstGame: sceneEx.IsPlayerFirst(playerEx.Player), - } - sceneEx.SaveGamePlayerListLog(playerEx.SnId, logParam) + IsFree: playerEx.isFree, + GameTime: 1, + }) } } diff --git a/gamesrv/fortuneox/scenepolicy_fortuneox.go b/gamesrv/fortuneox/scenepolicy_fortuneox.go index 1e05719..f204c1c 100644 --- a/gamesrv/fortuneox/scenepolicy_fortuneox.go +++ b/gamesrv/fortuneox/scenepolicy_fortuneox.go @@ -517,7 +517,11 @@ func FortuneOxAndSaveLog(sceneEx *FortuneOxSceneData, playerEx *FortuneOxPlayerD if err == nil { logid, _ := model.AutoIncGameLogId() playerEx.currentLogId = logid - sceneEx.SaveGameDetailedLog(logid, info, &base.GameDetailedParam{}) + sceneEx.SaveGameDetailedLog(&base.SaveGameDetailedParam{ + LogId: logid, + Detail: info, + GameTime: 1, + }) var totalin, totalout int64 if data.Results[0].FreeStatus == 1 || data.Results[0].FreeNumMax == 0 { totalin = playerEx.totalBet @@ -525,25 +529,22 @@ func FortuneOxAndSaveLog(sceneEx *FortuneOxSceneData, playerEx *FortuneOxPlayerD if data.Results[0].FreeStatus == 3 || data.Results[0].FreeNumMax == 0 { totalout = int64(data.RoundReward) + playerEx.taxCoin } - validFlow := totalin + totalout - validBet := common.AbsI64(totalin - totalout) - logParam := &base.SaveGamePlayerListLogParam{ - Platform: playerEx.Platform, - Channel: playerEx.Channel, - Promoter: playerEx.BeUnderAgentCode, - PackageTag: playerEx.PackageID, - InviterId: playerEx.InviterId, + sceneEx.SaveGamePlayerListLog(&base.SaveGamePlayerListLogParam{ LogId: logid, + Platform: playerEx.Platform, + Snid: playerEx.SnId, + PlayerName: playerEx.Name, + Channel: playerEx.Channel, + ChannelId: playerEx.ChannelId, TotalIn: totalin, TotalOut: totalout, TaxCoin: playerEx.taxCoin, - BetAmount: playerEx.totalBet, + BetAmount: totalin, WinAmountNoAnyTax: totalout - totalin - playerEx.taxCoin, - ValidBet: validBet, - ValidFlow: validFlow, IsFirstGame: sceneEx.IsPlayerFirst(playerEx.Player), - } - sceneEx.SaveGamePlayerListLog(playerEx.SnId, logParam) + IsFree: totalin == 0, + GameTime: 1, + }) } } diff --git a/gamesrv/fortunerabbit/scenepolicy_fortunerabbit.go b/gamesrv/fortunerabbit/scenepolicy_fortunerabbit.go index 13e788c..738ba3b 100644 --- a/gamesrv/fortunerabbit/scenepolicy_fortunerabbit.go +++ b/gamesrv/fortunerabbit/scenepolicy_fortunerabbit.go @@ -511,7 +511,11 @@ func FortuneRabbitAndSaveLog(sceneEx *FortuneRabbitSceneData, playerEx *FortuneR if err == nil { logid, _ := model.AutoIncGameLogId() playerEx.currentLogId = logid - sceneEx.SaveGameDetailedLog(logid, info, &base.GameDetailedParam{}) + sceneEx.SaveGameDetailedLog(&base.SaveGameDetailedParam{ + LogId: logid, + Detail: info, + GameTime: 1, + }) var totalin, totalout int64 if data.Results[0].FreeStatus == 1 || data.Results[0].FreeNumMax == 0 { totalin = playerEx.totalBet @@ -519,25 +523,22 @@ func FortuneRabbitAndSaveLog(sceneEx *FortuneRabbitSceneData, playerEx *FortuneR if data.Results[0].FreeStatus == 3 || data.Results[0].FreeNumMax == 0 { totalout = int64(data.RoundReward) + playerEx.taxCoin } - validFlow := totalin + totalout - validBet := common.AbsI64(totalin - totalout) - logParam := &base.SaveGamePlayerListLogParam{ - Platform: playerEx.Platform, - Channel: playerEx.Channel, - Promoter: playerEx.BeUnderAgentCode, - PackageTag: playerEx.PackageID, - InviterId: playerEx.InviterId, + sceneEx.SaveGamePlayerListLog(&base.SaveGamePlayerListLogParam{ LogId: logid, + Platform: playerEx.Platform, + Snid: playerEx.SnId, + PlayerName: playerEx.Name, + Channel: playerEx.Channel, + ChannelId: playerEx.ChannelId, TotalIn: totalin, TotalOut: totalout, TaxCoin: playerEx.taxCoin, - BetAmount: playerEx.totalBet, + BetAmount: totalin, WinAmountNoAnyTax: totalout - totalin - playerEx.taxCoin, - ValidBet: validBet, - ValidFlow: validFlow, IsFirstGame: sceneEx.IsPlayerFirst(playerEx.Player), - } - sceneEx.SaveGamePlayerListLog(playerEx.SnId, logParam) + IsFree: playerEx.isFree, + GameTime: 1, + }) } } diff --git a/gamesrv/fortunetiger/scenepolicy_fortunetiger.go b/gamesrv/fortunetiger/scenepolicy_fortunetiger.go index 9edc6be..2c5c11d 100644 --- a/gamesrv/fortunetiger/scenepolicy_fortunetiger.go +++ b/gamesrv/fortunetiger/scenepolicy_fortunetiger.go @@ -514,7 +514,11 @@ func FortuneTigerAndSaveLog(sceneEx *FortuneTigerSceneData, playerEx *FortuneTig if err == nil { logid, _ := model.AutoIncGameLogId() playerEx.currentLogId = logid - sceneEx.SaveGameDetailedLog(logid, info, &base.GameDetailedParam{}) + sceneEx.SaveGameDetailedLog(&base.SaveGameDetailedParam{ + LogId: logid, + Detail: info, + GameTime: 1, + }) var totalin, totalout int64 if data.Results[0].FreeStatus == 1 || data.Results[0].FreeNumMax == 0 { totalin = playerEx.totalBet @@ -522,25 +526,22 @@ func FortuneTigerAndSaveLog(sceneEx *FortuneTigerSceneData, playerEx *FortuneTig if data.Results[0].FreeStatus == 3 || data.Results[0].FreeNumMax == 0 { totalout = int64(data.RoundReward) + playerEx.taxCoin } - validFlow := totalin + totalout - validBet := common.AbsI64(totalin - totalout) - logParam := &base.SaveGamePlayerListLogParam{ - Platform: playerEx.Platform, - Channel: playerEx.Channel, - Promoter: playerEx.BeUnderAgentCode, - PackageTag: playerEx.PackageID, - InviterId: playerEx.InviterId, + sceneEx.SaveGamePlayerListLog(&base.SaveGamePlayerListLogParam{ LogId: logid, + Platform: playerEx.Platform, + Snid: playerEx.SnId, + PlayerName: playerEx.Name, + Channel: playerEx.Channel, + ChannelId: playerEx.ChannelId, TotalIn: totalin, TotalOut: totalout, TaxCoin: playerEx.taxCoin, - BetAmount: playerEx.totalBet, + BetAmount: totalin, WinAmountNoAnyTax: totalout - totalin - playerEx.taxCoin, - ValidBet: validBet, - ValidFlow: validFlow, IsFirstGame: sceneEx.IsPlayerFirst(playerEx.Player), - } - sceneEx.SaveGamePlayerListLog(playerEx.SnId, logParam) + IsFree: totalin == 0, + GameTime: 1, + }) } } diff --git a/gamesrv/fruits/scenedata_fruits.go b/gamesrv/fruits/scenedata_fruits.go index 94f20de..8280e92 100644 --- a/gamesrv/fruits/scenedata_fruits.go +++ b/gamesrv/fruits/scenedata_fruits.go @@ -326,7 +326,11 @@ func (s *FruitsSceneData) SaveLog(p *FruitsPlayerData, isOffline int) { info, err := model.MarshalGameNoteByROLL(&FruitsType) if err == nil { logId, _ := model.AutoIncGameLogId() - s.SaveGameDetailedLog(logId, info, &base.GameDetailedParam{}) + s.SaveGameDetailedLog(&base.SaveGameDetailedParam{ + LogId: logId, + Detail: info, + GameTime: 1, + }) //水池上下文环境s s.CpCtx = p.cpCtx var totalIn, totalOut int64 @@ -336,22 +340,22 @@ func (s *FruitsSceneData) SaveLog(p *FruitsPlayerData, isOffline int) { if nowGetCoin > 0 && isF { totalOut = p.Coin - p.startCoin + betCoin /*+ p.taxCoin*/ } - s.SaveGamePlayerListLog(p.SnId, - &base.SaveGamePlayerListLogParam{ - Platform: p.Platform, - Channel: p.Channel, - Promoter: p.BeUnderAgentCode, - PackageTag: p.PackageID, - InviterId: p.InviterId, - LogId: logId, - TotalIn: totalIn, - TotalOut: totalOut, - TaxCoin: p.taxCoin, - ClubPumpCoin: 0, - BetAmount: totalIn, - WinAmountNoAnyTax: p.Coin - p.startCoin, - IsFirstGame: s.IsPlayerFirst(p.Player), - }) + s.SaveGamePlayerListLog(&base.SaveGamePlayerListLogParam{ + LogId: logId, + Platform: p.Platform, + Snid: p.SnId, + PlayerName: p.Name, + Channel: p.Channel, + ChannelId: p.ChannelId, + TotalIn: totalIn, + TotalOut: totalOut, + TaxCoin: p.taxCoin, + BetAmount: totalIn, + WinAmountNoAnyTax: p.Coin - p.startCoin, + IsFirstGame: s.IsPlayerFirst(p.Player), + IsFree: totalIn == 0, + GameTime: 1, + }) } s.GameNowTime = time.Now() if s.CheckNeedDestroy() && p.freeTimes == 0 && p.maryFreeTimes == 0 { diff --git a/gamesrv/iceage/scenepolicy_iceage.go b/gamesrv/iceage/scenepolicy_iceage.go index be0ebff..787d74f 100644 --- a/gamesrv/iceage/scenepolicy_iceage.go +++ b/gamesrv/iceage/scenepolicy_iceage.go @@ -942,31 +942,31 @@ func IceAgeCheckAndSaveLog(sceneEx *IceAgeSceneData, playerEx *IceAgePlayerData) if err == nil { logid, _ := model.AutoIncGameLogId() playerEx.currentLogId = logid - sceneEx.SaveGameDetailedLog(logid, info, &base.GameDetailedParam{}) + sceneEx.SaveGameDetailedLog(&base.SaveGameDetailedParam{ + LogId: logid, + Detail: info, + GameTime: 1, + }) totalin := int64(playerEx.RollGameType.BaseResult.TotalBet) totalout := playerEx.RollGameType.BaseResult.ChangeCoin + playerEx.taxCoin + totalin - validFlow := totalin + totalout - validBet := common.AbsI64(totalin - totalout) - logParam := &base.SaveGamePlayerListLogParam{ - Platform: playerEx.Platform, - Channel: playerEx.Channel, - Promoter: playerEx.BeUnderAgentCode, - PackageTag: playerEx.PackageID, - InviterId: playerEx.InviterId, + sceneEx.SaveGamePlayerListLog(&base.SaveGamePlayerListLogParam{ LogId: logid, + Platform: playerEx.Platform, + Snid: playerEx.SnId, + PlayerName: playerEx.Name, + Channel: playerEx.Channel, + ChannelId: playerEx.ChannelId, TotalIn: totalin, TotalOut: totalout, TaxCoin: playerEx.taxCoin, BetAmount: int64(playerEx.RollGameType.BaseResult.TotalBet), WinAmountNoAnyTax: playerEx.RollGameType.BaseResult.ChangeCoin, - ValidBet: validBet, - ValidFlow: validFlow, IsFirstGame: sceneEx.IsPlayerFirst(playerEx.Player), IsFree: playerEx.RollGameType.BaseResult.IsFree, WinSmallGame: playerEx.RollGameType.BaseResult.WinSmallGame, WinTotal: playerEx.RollGameType.BaseResult.WinTotal, - } - sceneEx.SaveGamePlayerListLog(playerEx.SnId, logParam) + GameTime: 1, + }) } } } diff --git a/gamesrv/richblessed/scenedata_richblessed.go b/gamesrv/richblessed/scenedata_richblessed.go index 9d31d45..957fc1c 100644 --- a/gamesrv/richblessed/scenedata_richblessed.go +++ b/gamesrv/richblessed/scenedata_richblessed.go @@ -348,7 +348,11 @@ func (s *RichBlessedSceneData) SaveLog(p *RichBlessedPlayerData, isOffline int) info, err := model.MarshalGameNoteByROLL(&RichBlessed) if err == nil { logId, _ := model.AutoIncGameLogId() - s.SaveGameDetailedLog(logId, info, &base.GameDetailedParam{}) + s.SaveGameDetailedLog(&base.SaveGameDetailedParam{ + LogId: logId, + Detail: info, + GameTime: 1, + }) //水池上下文环境s s.CpCtx = p.cpCtx var totalIn, totalOut int64 @@ -358,22 +362,22 @@ func (s *RichBlessedSceneData) SaveLog(p *RichBlessedPlayerData, isOffline int) if nowGetCoin > 0 { totalOut = p.Coin - p.startCoin + betCoin /*+ p.taxCoin*/ } - s.SaveGamePlayerListLog(p.SnId, - &base.SaveGamePlayerListLogParam{ - Platform: p.Platform, - Channel: p.Channel, - Promoter: p.BeUnderAgentCode, - PackageTag: p.PackageID, - InviterId: p.InviterId, - LogId: logId, - TotalIn: totalIn, - TotalOut: totalOut, - TaxCoin: p.taxCoin, - ClubPumpCoin: 0, - BetAmount: totalIn, - WinAmountNoAnyTax: p.Coin - p.startCoin, - IsFirstGame: s.IsPlayerFirst(p.Player), - }) + s.SaveGamePlayerListLog(&base.SaveGamePlayerListLogParam{ + LogId: logId, + Platform: p.Platform, + Snid: p.SnId, + PlayerName: p.Name, + Channel: p.Channel, + ChannelId: p.ChannelId, + TotalIn: totalIn, + TotalOut: totalOut, + TaxCoin: p.taxCoin, + BetAmount: totalIn, + WinAmountNoAnyTax: p.Coin - p.startCoin, + IsFirstGame: s.IsPlayerFirst(p.Player), + IsFree: totalIn == 0, + GameTime: 1, + }) } s.GameNowTime = time.Now() if s.CheckNeedDestroy() && p.freeTimes == 0 { diff --git a/gamesrv/smallrocket/scene.go b/gamesrv/smallrocket/scene.go index d7fec18..d329343 100644 --- a/gamesrv/smallrocket/scene.go +++ b/gamesrv/smallrocket/scene.go @@ -33,6 +33,7 @@ type PlayerData struct { Platform string //平台 Channel string //渠道信息 + ChannelId string PackageID string //推广包标识 对应客户端的packagetag flag int } @@ -333,6 +334,7 @@ func (this *SceneEx) BackupPlayer(p *PlayerEx, isBilled bool) { flag: p.GetFlag(), Platform: p.Platform, Channel: p.Channel, + ChannelId: p.ChannelId, PackageID: p.PackageID, CurIsWin: p.CurIsWin, Name: p.Name, diff --git a/gamesrv/smallrocket/scenepolicy.go b/gamesrv/smallrocket/scenepolicy.go index d690fda..cfe3367 100644 --- a/gamesrv/smallrocket/scenepolicy.go +++ b/gamesrv/smallrocket/scenepolicy.go @@ -1166,33 +1166,28 @@ func (this *StateBilled) OnEnter(s *base.Scene) { if !playerEx.IsRob { info, err := model.MarshalGameNoteByHUNDRED(LogBaseResult) if err == nil { - sceneEx.SaveGameDetailedLog(sceneEx.logid, info, &base.GameDetailedParam{}) + sceneEx.SaveGameDetailedLog(&base.SaveGameDetailedParam{ + LogId: sceneEx.logid, + Detail: info, + }) } totalin := int64(TotalBetValue) totalout := playerEx.gainCoin - validFlow := totalin + totalout - validBet := common.AbsI64(totalin - totalout) - logParam := &base.SaveGamePlayerListLogParam{ - Platform: playerEx.Platform, - Channel: playerEx.Channel, - Promoter: playerEx.BeUnderAgentCode, - PackageTag: playerEx.PackageID, - InviterId: playerEx.InviterId, + sceneEx.SaveGamePlayerListLog(&base.SaveGamePlayerListLogParam{ LogId: sceneEx.logid, + Platform: playerEx.Platform, + Snid: playerEx.SnId, + PlayerName: playerEx.Name, + Channel: playerEx.Channel, + ChannelId: playerEx.ChannelId, TotalIn: totalin, TotalOut: totalout, TaxCoin: playerEx.taxCoin, BetAmount: int64(TotalBetValue), WinAmountNoAnyTax: playerEx.gainCoin, - ValidBet: validBet, - ValidFlow: validFlow, - IsFirstGame: sceneEx.IsPlayerFirst(playerEx.Player), - IsFree: false, - WinSmallGame: 0, - WinTotal: 0, - } - sceneEx.SaveGamePlayerListLog(playerEx.SnId, logParam) + IsFirstGame: s.IsPlayerFirst(playerEx.Player), + }) } } @@ -1248,34 +1243,30 @@ func (this *StateBilled) OnEnter(s *base.Scene) { if !playerEx.IsRob { info, err := model.MarshalGameNoteByHUNDRED(LogBaseResult) if err == nil { - sceneEx.SaveGameDetailedLog(sceneEx.logid, info, &base.GameDetailedParam{}) + sceneEx.SaveGameDetailedLog(&base.SaveGameDetailedParam{ + LogId: sceneEx.logid, + Detail: info, + }) } totalin := int64(TotalBetValue) totalout := playerEx.gainCoin - validFlow := totalin + totalout - validBet := common.AbsI64(totalin - totalout) - logParam := &base.SaveGamePlayerListLogParam{ - Platform: playerEx.Platform, - Channel: playerEx.Channel, - Promoter: playerEx.BeUnderAgentCode, - PackageTag: playerEx.PackageID, - InviterId: playerEx.InviterId, + //validFlow := totalin + totalout + //validBet := common.AbsI64(totalin - totalout) + sceneEx.SaveGamePlayerListLog(&base.SaveGamePlayerListLogParam{ LogId: sceneEx.logid, + Platform: playerEx.Platform, + Snid: playerEx.SnId, + PlayerName: playerEx.Name, + Channel: playerEx.Channel, + ChannelId: playerEx.ChannelId, TotalIn: totalin, TotalOut: totalout, TaxCoin: playerEx.taxCoin, BetAmount: int64(TotalBetValue), WinAmountNoAnyTax: playerEx.gainCoin, - ValidBet: validBet, - ValidFlow: validFlow, IsFirstGame: playerEx.IsPlayerFirst, - IsFree: false, - WinSmallGame: 0, - WinTotal: 0, - PlayerName: playerEx.Name, - } - sceneEx.SaveGamePlayerListLog(playerEx.SnId, logParam) + }) } } } diff --git a/gamesrv/tamquoc/scenepolicy_tamquoc.go b/gamesrv/tamquoc/scenepolicy_tamquoc.go index a3495d7..2a57d3b 100644 --- a/gamesrv/tamquoc/scenepolicy_tamquoc.go +++ b/gamesrv/tamquoc/scenepolicy_tamquoc.go @@ -778,31 +778,31 @@ func TamQuocCheckAndSaveLog(sceneEx *TamQuocSceneData, playerEx *TamQuocPlayerDa if err == nil { logid, _ := model.AutoIncGameLogId() playerEx.currentLogId = logid - sceneEx.SaveGameDetailedLog(logid, info, &base.GameDetailedParam{}) + sceneEx.SaveGameDetailedLog(&base.SaveGameDetailedParam{ + LogId: logid, + Detail: info, + GameTime: 1, + }) totalin := int64(playerEx.RollGameType.BaseResult.TotalBet) totalout := playerEx.RollGameType.BaseResult.ChangeCoin + playerEx.taxCoin + totalin - validFlow := totalin + totalout - validBet := common.AbsI64(totalin - totalout) - logParam := &base.SaveGamePlayerListLogParam{ - Platform: playerEx.Platform, - Channel: playerEx.Channel, - Promoter: playerEx.BeUnderAgentCode, - PackageTag: playerEx.PackageID, - InviterId: playerEx.InviterId, + sceneEx.SaveGamePlayerListLog(&base.SaveGamePlayerListLogParam{ LogId: logid, + Platform: playerEx.Platform, + Snid: playerEx.SnId, + PlayerName: playerEx.Name, + Channel: playerEx.Channel, + ChannelId: playerEx.ChannelId, TotalIn: totalin, TotalOut: totalout, TaxCoin: playerEx.taxCoin, BetAmount: int64(playerEx.RollGameType.BaseResult.TotalBet), WinAmountNoAnyTax: playerEx.RollGameType.BaseResult.ChangeCoin, - ValidBet: validBet, - ValidFlow: validFlow, IsFirstGame: sceneEx.IsPlayerFirst(playerEx.Player), IsFree: playerEx.RollGameType.BaseResult.IsFree, WinSmallGame: playerEx.RollGameType.BaseResult.WinSmallGame, WinTotal: playerEx.RollGameType.BaseResult.WinTotal, - } - sceneEx.SaveGamePlayerListLog(playerEx.SnId, logParam) + GameTime: 1, + }) } } } diff --git a/gamesrv/thirteen/scenepolicy.go b/gamesrv/thirteen/scenepolicy.go index 356cd2e..274c3f5 100644 --- a/gamesrv/thirteen/scenepolicy.go +++ b/gamesrv/thirteen/scenepolicy.go @@ -181,11 +181,22 @@ func (this *PolicyThirteen) OnPlayerLeave(s *base.Scene, p *base.Player, reason } else { totalin -= playerEx.gainCoin } - validFlow := totalin + totalout - validBet := common.AbsI64(totalin - totalout) - sceneEx.SaveGamePlayerListLog(playerEx.SnId, base.GetSaveGamePlayerListLogParam(playerEx.Platform, playerEx.Channel, playerEx.BeUnderAgentCode, - playerEx.PackageID, sceneEx.logid, playerEx.InviterId, totalin, totalout, playerEx.taxCoin, - 0, 0, playerEx.gainCoin, validBet, validFlow, sceneEx.IsPlayerFirst(sceneEx.GetPlayer(playerEx.SnId)), false)) + //validFlow := totalin + totalout + //validBet := common.AbsI64(totalin - totalout) + sceneEx.SaveGamePlayerListLog(&base.SaveGamePlayerListLogParam{ + LogId: sceneEx.logid, + Platform: playerEx.Platform, + Snid: playerEx.SnId, + PlayerName: playerEx.Name, + Channel: playerEx.Channel, + ChannelId: playerEx.ChannelId, + TotalIn: totalin, + TotalOut: totalout, + TaxCoin: playerEx.taxCoin, + BetAmount: 0, + WinAmountNoAnyTax: playerEx.gainCoin, + IsFirstGame: sceneEx.IsPlayerFirst(sceneEx.GetPlayer(playerEx.SnId)), + }) sceneEx.Statistics(&base.StaticParam{ SnId: playerEx.SnId, @@ -1354,11 +1365,20 @@ func (this *StateBilled) OnEnter(s *base.Scene) { } else { totalin -= o_player.gainCoin } - validFlow := totalin + totalout - validBet := common.AbsI64(totalin - totalout) - sceneEx.SaveGamePlayerListLog(o_player.SnId, base.GetSaveGamePlayerListLogParam(o_player.Platform, o_player.Channel, o_player.BeUnderAgentCode, - o_player.PackageID, sceneEx.logid, o_player.InviterId, totalin, totalout, o_player.taxCoin, - 0, 0, o_player.gainCoin, validBet, validFlow, p.IsFirst, false)) + sceneEx.SaveGamePlayerListLog(&base.SaveGamePlayerListLogParam{ + LogId: sceneEx.logid, + Platform: o_player.Platform, + Snid: o_player.SnId, + PlayerName: o_player.Name, + Channel: o_player.Channel, + ChannelId: o_player.ChannelId, + TotalIn: totalin, + TotalOut: totalout, + TaxCoin: o_player.taxCoin, + BetAmount: 0, + WinAmountNoAnyTax: o_player.gainCoin, + IsFirstGame: p.IsFirst, + }) } } } @@ -1417,10 +1437,11 @@ func (this *StateBilled) OnEnter(s *base.Scene) { thirteenWaterType.PlayerCount = len(person) info, err := model.MarshalGameNoteByFIGHT(&thirteenWaterType) if err == nil { - sceneEx.SaveGameDetailedLog(sceneEx.logid, info, &base.GameDetailedParam{ - Trend20Lately: "", - CtrlType: sceneEx.ctrlType, - PlayerPool: playerPool, + sceneEx.SaveGameDetailedLog(&base.SaveGameDetailedParam{ + LogId: sceneEx.logid, + Detail: info, + CtrlType: sceneEx.ctrlType, + PlayerPool: playerPool, }) } } diff --git a/gamesrv/tienlen/scenepolicy_tienlen.go b/gamesrv/tienlen/scenepolicy_tienlen.go index 5a249ae..2f29da4 100644 --- a/gamesrv/tienlen/scenepolicy_tienlen.go +++ b/gamesrv/tienlen/scenepolicy_tienlen.go @@ -1737,6 +1737,7 @@ func (this *SceneBilledStateTienLen) OnEnter(s *base.Scene) { UserIcon: playerEx.Head, Platform: playerEx.Platform, Channel: playerEx.Channel, + ChannelId: playerEx.ChannelId, Promoter: playerEx.BeUnderAgentCode, PackageTag: playerEx.PackageID, InviterId: playerEx.InviterId, @@ -1888,6 +1889,7 @@ func (this *SceneBilledStateTienLen) OnEnter(s *base.Scene) { UserIcon: losePlayer.Head, Platform: losePlayer.Platform, Channel: losePlayer.Channel, + ChannelId: losePlayer.ChannelId, Promoter: losePlayer.BeUnderAgentCode, PackageTag: losePlayer.PackageID, InviterId: losePlayer.InviterId, @@ -2030,6 +2032,7 @@ func (this *SceneBilledStateTienLen) OnEnter(s *base.Scene) { UserIcon: lastWinPlayer.Head, Platform: lastWinPlayer.Platform, Channel: lastWinPlayer.Channel, + ChannelId: lastWinPlayer.ChannelId, Promoter: lastWinPlayer.BeUnderAgentCode, PackageTag: lastWinPlayer.PackageID, InviterId: lastWinPlayer.InviterId, @@ -2141,6 +2144,7 @@ func (this *SceneBilledStateTienLen) OnEnter(s *base.Scene) { UserIcon: playerEx.Head, Platform: playerEx.Platform, Channel: playerEx.Channel, + ChannelId: playerEx.ChannelId, Promoter: playerEx.BeUnderAgentCode, PackageTag: playerEx.PackageID, InviterId: playerEx.InviterId, @@ -2246,6 +2250,7 @@ func (this *SceneBilledStateTienLen) OnEnter(s *base.Scene) { UserIcon: playerEx.Head, Platform: playerEx.Platform, Channel: playerEx.Channel, + ChannelId: playerEx.ChannelId, Promoter: playerEx.BeUnderAgentCode, PackageTag: playerEx.PackageID, InviterId: playerEx.InviterId, @@ -2397,6 +2402,7 @@ func (this *SceneBilledStateTienLen) OnEnter(s *base.Scene) { UserIcon: playerEx.Head, Platform: playerEx.Platform, Channel: playerEx.Channel, + ChannelId: playerEx.ChannelId, Promoter: playerEx.BeUnderAgentCode, PackageTag: playerEx.PackageID, InviterId: playerEx.InviterId, @@ -2527,6 +2533,7 @@ func (this *SceneBilledStateTienLen) OnEnter(s *base.Scene) { UserIcon: playerEx.Head, Platform: playerEx.Platform, Channel: playerEx.Channel, + ChannelId: playerEx.ChannelId, Promoter: playerEx.BeUnderAgentCode, PackageTag: playerEx.PackageID, InviterId: playerEx.InviterId, @@ -2729,8 +2736,6 @@ func (this *SceneBilledStateTienLen) OnEnter(s *base.Scene) { playerEx.UpdatePigBankCoin(o_player.GainCoin) } - validFlow := totalin + totalout - validBet := common.AbsI64(totalin - totalout) sceneEx.SaveFriendRecord(o_player.UserId, o_player.IsWin, o_player.BillCoin, sceneEx.GetBaseScore()) // 玩家数据统计 @@ -2752,20 +2757,29 @@ func (this *SceneBilledStateTienLen) OnEnter(s *base.Scene) { }) // 保存玩家游戏记录 - param := base.GetSaveGamePlayerListLogParam(o_player.Platform, o_player.Channel, o_player.Promoter, - o_player.PackageTag, sceneEx.recordId, o_player.InviterId, totalin, totalout, o_player.BillTaxCoin, - 0, 0, o_player.GainCoin+o_player.BombCoin, validBet, validFlow, o_player.IsFirst, o_player.IsLeave) - param.CycleId = sceneEx.CycleID - sceneEx.SaveGamePlayerListLog(o_player.UserId, param) + sceneEx.SaveGamePlayerListLog(&base.SaveGamePlayerListLogParam{ + LogId: sceneEx.recordId, + Platform: o_player.Platform, + Snid: o_player.UserId, + Channel: o_player.Channel, + ChannelId: o_player.ChannelId, + TotalIn: totalin, + TotalOut: totalout, + TaxCoin: o_player.BillTaxCoin, + BetAmount: 0, + WinAmountNoAnyTax: o_player.GainCoin + o_player.BombCoin, + IsFirstGame: o_player.IsFirst, + }) } } if isSave { // 牌局记录 - sceneEx.SaveGameDetailedLog(sceneEx.recordId, info, &base.GameDetailedParam{ + sceneEx.SaveGameDetailedLog(&base.SaveGameDetailedParam{ + LogId: sceneEx.recordId, + Detail: info, Trend20Lately: "", CtrlType: sceneEx.ctrlType, PlayerPool: tienlenType.PlayerPool, - CycleId: sceneEx.CycleID, }) } } diff --git a/model/dataevent.go b/model/dataevent.go index 3cb9070..b3d138f 100644 --- a/model/dataevent.go +++ b/model/dataevent.go @@ -275,49 +275,6 @@ type PlayerGameRecEvent struct { ChannelId string //推广渠道id } -func CreatePlayerGameRecEvent(snid int32, tax, taxex, amount, validbet, validflow, in, out int64, gameid, gameFreeId, modeid int32, recordId, channel, channelId, promoter, - platform, city, os string, createDayTime time.Time, gamingTime int32, firstGameFreeTime, firstGameTime time.Time, - playGameFreeTimes, playerGameTimes int64, lastLoginTime time.Time, teleponePromoter int32, deviceId string) *PlayerGameRecEvent { - isNewbie := int32(0) - tCreateDay := now.New(createDayTime).BeginningOfDay() - if now.BeginningOfDay().Equal(tCreateDay) { - isNewbie = 1 - } - if gamingTime < 0 { - gamingTime = 0 - } - return &PlayerGameRecEvent{RecordId: recordId, - SnId: snid, - Channel: channel, - Promoter: promoter, - TelephonePromoter: teleponePromoter, - Platform: platform, - City: city, - OS: os, - GameId: gameid, - ModeId: modeid, - Tax: tax, - //Taxex: taxex, - Amount: amount, - ValidBet: validbet, - ValidFlow: validflow, - In: in, - Out: out, - CreateTime: time.Now().Local().Unix(), - CreateDayTime: tCreateDay.Local().Unix(), - IsNew: isNewbie, - GameFreeID: gameFreeId, - GamingTime: gamingTime, - FirstTime: firstGameFreeTime.Unix(), - FirstGameTime: firstGameTime.Unix(), - PlayTimes: playGameFreeTimes, - PlayGameTimes: playerGameTimes, - LastLoginTime: lastLoginTime.Unix(), - DeviceId: deviceId, - ChannelId: channelId, - } -} - // 玩家游戏记录 //type PlayerGameRecPayEvent struct { // SnId int32 //用户ID diff --git a/model/gamelogtype.go b/model/gamelogtype.go index 0d9b998..4ca1a01 100644 --- a/model/gamelogtype.go +++ b/model/gamelogtype.go @@ -1536,6 +1536,7 @@ type TienLenPerson struct { UserIcon int32 //玩家头像 Platform string `json:"-"` Channel string `json:"-"` + ChannelId string `json:"-"` Promoter string `json:"-"` PackageTag string `json:"-"` InviterId int32 `json:"-"` @@ -1581,6 +1582,7 @@ type ChesstitiansPerson struct { UserIcon int32 //玩家头像 Platform string `json:"-"` Channel string `json:"-"` + ChannelId string `json:"-"` Promoter string `json:"-"` PackageTag string `json:"-"` InviterId int32 `json:"-"` diff --git a/model/gameplayerlistlog.go b/model/gameplayerlistlog.go index 4441b2d..9d06b23 100644 --- a/model/gameplayerlistlog.go +++ b/model/gameplayerlistlog.go @@ -51,7 +51,7 @@ type GamePlayerListLog struct { GameClass int32 //游戏类型 1棋牌 2电子 3百人 4捕鱼 5视讯 6彩票 7体育 MatchId int64 MatchType int64 //0.普通场 1.锦标赛 2.冠军赛 3.vip专属 - Ts int32 + Ts int64 IsFree bool //拉霸专用 是否免费 WinSmallGame int64 //拉霸专用 小游戏奖励 WinTotal int64 //拉霸专用 输赢 @@ -95,7 +95,7 @@ func NewGamePlayerListLogEx(snid int32, gamedetailedlogid string, platform, chan cl.WinSmallGame = winSmallGame cl.WinTotal = winTotal tNow := time.Now() - cl.Ts = int32(tNow.Unix()) + cl.Ts = tNow.Unix() cl.Time = tNow cl.MatchId = matchid cl.MatchType = matchType From 80c191ec98be289161c37b0a8fc35ad2f9c63e42 Mon Sep 17 00:00:00 2001 From: sk <123456@qq.com> Date: Mon, 2 Dec 2024 13:44:26 +0800 Subject: [PATCH 23/41] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E7=89=8C=E5=B1=80?= =?UTF-8?q?=E8=AE=B0=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gamesrv/avengers/scenepolicy_avengers.go | 4 ++-- gamesrv/caishen/scenepolicy_caishen.go | 4 ++-- gamesrv/easterisland/scenepolicy_easterisland.go | 4 ++-- gamesrv/fortunedragon/scenepolicy_fortunedragon.go | 5 +++-- gamesrv/fortuneox/scenepolicy_fortuneox.go | 5 +++-- gamesrv/fortunerabbit/scenepolicy_fortunerabbit.go | 5 +++-- gamesrv/fortunetiger/scenepolicy_fortunetiger.go | 5 +++-- gamesrv/fruits/scenedata_fruits.go | 4 ++-- gamesrv/iceage/scenepolicy_iceage.go | 4 ++-- gamesrv/richblessed/scenedata_richblessed.go | 4 ++-- gamesrv/tamquoc/scenepolicy_tamquoc.go | 4 ++-- 11 files changed, 26 insertions(+), 22 deletions(-) diff --git a/gamesrv/avengers/scenepolicy_avengers.go b/gamesrv/avengers/scenepolicy_avengers.go index c9334c3..abb1ed2 100644 --- a/gamesrv/avengers/scenepolicy_avengers.go +++ b/gamesrv/avengers/scenepolicy_avengers.go @@ -937,7 +937,7 @@ func AvengersCheckAndSaveLog(sceneEx *AvengersSceneData, playerEx *AvengersPlaye sceneEx.SaveGameDetailedLog(&base.SaveGameDetailedParam{ LogId: logid, Detail: info, - GameTime: 1, + GameTime: 2, }) totalin := int64(playerEx.RollGameType.BaseResult.TotalBet) totalout := playerEx.RollGameType.BaseResult.ChangeCoin + playerEx.taxCoin + totalin @@ -956,7 +956,7 @@ func AvengersCheckAndSaveLog(sceneEx *AvengersSceneData, playerEx *AvengersPlaye IsFree: playerEx.RollGameType.BaseResult.IsFree, WinSmallGame: playerEx.RollGameType.BaseResult.WinSmallGame, WinTotal: playerEx.RollGameType.BaseResult.WinTotal, - GameTime: 1, + GameTime: 2, }) } } diff --git a/gamesrv/caishen/scenepolicy_caishen.go b/gamesrv/caishen/scenepolicy_caishen.go index aa21249..b227c93 100644 --- a/gamesrv/caishen/scenepolicy_caishen.go +++ b/gamesrv/caishen/scenepolicy_caishen.go @@ -1026,7 +1026,7 @@ func CaiShenCheckAndSaveLog(sceneEx *CaiShenSceneData, playerEx *CaiShenPlayerDa sceneEx.SaveGameDetailedLog(&base.SaveGameDetailedParam{ LogId: logid, Detail: info, - GameTime: 1, + GameTime: 2, }) totalin := int64(playerEx.RollGameType.BaseResult.TotalBet) totalout := playerEx.RollGameType.BaseResult.ChangeCoin + playerEx.taxCoin + totalin @@ -1046,7 +1046,7 @@ func CaiShenCheckAndSaveLog(sceneEx *CaiShenSceneData, playerEx *CaiShenPlayerDa IsFree: playerEx.RollGameType.BaseResult.IsFree, WinSmallGame: playerEx.RollGameType.BaseResult.WinSmallGame, WinTotal: playerEx.RollGameType.BaseResult.WinTotal, - GameTime: 1, + GameTime: 2, }) } } diff --git a/gamesrv/easterisland/scenepolicy_easterisland.go b/gamesrv/easterisland/scenepolicy_easterisland.go index 677d88b..0b19dde 100644 --- a/gamesrv/easterisland/scenepolicy_easterisland.go +++ b/gamesrv/easterisland/scenepolicy_easterisland.go @@ -895,7 +895,7 @@ func EasterIslandCheckAndSaveLog(sceneEx *EasterIslandSceneData, playerEx *Easte sceneEx.SaveGameDetailedLog(&base.SaveGameDetailedParam{ LogId: logid, Detail: info, - GameTime: 1, + GameTime: 2, }) totalin := int64(playerEx.RollGameType.BaseResult.TotalBet) totalout := playerEx.RollGameType.BaseResult.ChangeCoin + playerEx.taxCoin + totalin @@ -915,7 +915,7 @@ func EasterIslandCheckAndSaveLog(sceneEx *EasterIslandSceneData, playerEx *Easte IsFree: playerEx.RollGameType.BaseResult.IsFree, WinSmallGame: playerEx.RollGameType.BaseResult.WinSmallGame, WinTotal: playerEx.RollGameType.BaseResult.WinTotal, - GameTime: 1, + GameTime: 2, }) } } diff --git a/gamesrv/fortunedragon/scenepolicy_fortunedragon.go b/gamesrv/fortunedragon/scenepolicy_fortunedragon.go index cea24a8..59b2784 100644 --- a/gamesrv/fortunedragon/scenepolicy_fortunedragon.go +++ b/gamesrv/fortunedragon/scenepolicy_fortunedragon.go @@ -407,6 +407,7 @@ func (this *SceneStateStartFortuneDragon) OnPlayerOp(s *base.Scene, p *base.Play var gameEndStr string var data assemble.GameEnd if err == nil { + s.SetGameNowTime(time.Now()) data = assemble.DataToCli(Response).(assemble.GameEnd) if data.Results[0].FreeStatus == 1 || data.Results[0].FreeNumMax == 0 { //logger.Logger.Trace("=====================AddCoin=====TotalBet===", -data.TotalBet) @@ -515,7 +516,7 @@ func FortuneDragonAndSaveLog(sceneEx *FortuneDragonSceneData, playerEx *FortuneD sceneEx.SaveGameDetailedLog(&base.SaveGameDetailedParam{ LogId: logid, Detail: info, - GameTime: 1, + GameTime: 2, }) var totalin, totalout int64 if data.Results[0].FreeStatus == 1 || data.Results[0].FreeNumMax == 0 { @@ -538,7 +539,7 @@ func FortuneDragonAndSaveLog(sceneEx *FortuneDragonSceneData, playerEx *FortuneD WinAmountNoAnyTax: totalout - totalin - playerEx.taxCoin, IsFirstGame: sceneEx.IsPlayerFirst(playerEx.Player), IsFree: playerEx.isFree, - GameTime: 1, + GameTime: 2, }) } } diff --git a/gamesrv/fortuneox/scenepolicy_fortuneox.go b/gamesrv/fortuneox/scenepolicy_fortuneox.go index f204c1c..0cc788d 100644 --- a/gamesrv/fortuneox/scenepolicy_fortuneox.go +++ b/gamesrv/fortuneox/scenepolicy_fortuneox.go @@ -405,6 +405,7 @@ func (this *SceneStateStartFortuneOx) OnPlayerOp(s *base.Scene, p *base.Player, var gameEndStr string var data assemble.GameEnd if err == nil { + s.SetGameNowTime(time.Now()) data = assemble.DataToCli(Response).(assemble.GameEnd) var respinStatus int if data.Results[0].ArrSpins[0].Special != nil { @@ -520,7 +521,7 @@ func FortuneOxAndSaveLog(sceneEx *FortuneOxSceneData, playerEx *FortuneOxPlayerD sceneEx.SaveGameDetailedLog(&base.SaveGameDetailedParam{ LogId: logid, Detail: info, - GameTime: 1, + GameTime: 2, }) var totalin, totalout int64 if data.Results[0].FreeStatus == 1 || data.Results[0].FreeNumMax == 0 { @@ -543,7 +544,7 @@ func FortuneOxAndSaveLog(sceneEx *FortuneOxSceneData, playerEx *FortuneOxPlayerD WinAmountNoAnyTax: totalout - totalin - playerEx.taxCoin, IsFirstGame: sceneEx.IsPlayerFirst(playerEx.Player), IsFree: totalin == 0, - GameTime: 1, + GameTime: 2, }) } } diff --git a/gamesrv/fortunerabbit/scenepolicy_fortunerabbit.go b/gamesrv/fortunerabbit/scenepolicy_fortunerabbit.go index 738ba3b..a292add 100644 --- a/gamesrv/fortunerabbit/scenepolicy_fortunerabbit.go +++ b/gamesrv/fortunerabbit/scenepolicy_fortunerabbit.go @@ -405,6 +405,7 @@ func (this *SceneStateStartFortuneRabbit) OnPlayerOp(s *base.Scene, p *base.Play var gameEndStr string var data assemble.GameEnd if err == nil { + s.SetGameNowTime(time.Now()) data = assemble.DataToCli(Response).(assemble.GameEnd) if data.Results[0].FreeStatus == 1 || data.Results[0].FreeNumMax == 0 { //第一次触发或者正常模式 @@ -514,7 +515,7 @@ func FortuneRabbitAndSaveLog(sceneEx *FortuneRabbitSceneData, playerEx *FortuneR sceneEx.SaveGameDetailedLog(&base.SaveGameDetailedParam{ LogId: logid, Detail: info, - GameTime: 1, + GameTime: 2, }) var totalin, totalout int64 if data.Results[0].FreeStatus == 1 || data.Results[0].FreeNumMax == 0 { @@ -537,7 +538,7 @@ func FortuneRabbitAndSaveLog(sceneEx *FortuneRabbitSceneData, playerEx *FortuneR WinAmountNoAnyTax: totalout - totalin - playerEx.taxCoin, IsFirstGame: sceneEx.IsPlayerFirst(playerEx.Player), IsFree: playerEx.isFree, - GameTime: 1, + GameTime: 2, }) } } diff --git a/gamesrv/fortunetiger/scenepolicy_fortunetiger.go b/gamesrv/fortunetiger/scenepolicy_fortunetiger.go index 2c5c11d..155a835 100644 --- a/gamesrv/fortunetiger/scenepolicy_fortunetiger.go +++ b/gamesrv/fortunetiger/scenepolicy_fortunetiger.go @@ -405,6 +405,7 @@ func (this *SceneStateStartFortuneTiger) OnPlayerOp(s *base.Scene, p *base.Playe var gameEndStr string var data assemble.GameEnd if err == nil { + s.SetGameNowTime(time.Now()) data = assemble.DataToCli(Response).(assemble.GameEnd) var respinStatus int if data.Results[0].ArrSpins[0].Special != nil { @@ -517,7 +518,7 @@ func FortuneTigerAndSaveLog(sceneEx *FortuneTigerSceneData, playerEx *FortuneTig sceneEx.SaveGameDetailedLog(&base.SaveGameDetailedParam{ LogId: logid, Detail: info, - GameTime: 1, + GameTime: 2, }) var totalin, totalout int64 if data.Results[0].FreeStatus == 1 || data.Results[0].FreeNumMax == 0 { @@ -540,7 +541,7 @@ func FortuneTigerAndSaveLog(sceneEx *FortuneTigerSceneData, playerEx *FortuneTig WinAmountNoAnyTax: totalout - totalin - playerEx.taxCoin, IsFirstGame: sceneEx.IsPlayerFirst(playerEx.Player), IsFree: totalin == 0, - GameTime: 1, + GameTime: 2, }) } } diff --git a/gamesrv/fruits/scenedata_fruits.go b/gamesrv/fruits/scenedata_fruits.go index 8280e92..3a24307 100644 --- a/gamesrv/fruits/scenedata_fruits.go +++ b/gamesrv/fruits/scenedata_fruits.go @@ -329,7 +329,7 @@ func (s *FruitsSceneData) SaveLog(p *FruitsPlayerData, isOffline int) { s.SaveGameDetailedLog(&base.SaveGameDetailedParam{ LogId: logId, Detail: info, - GameTime: 1, + GameTime: 2, }) //水池上下文环境s s.CpCtx = p.cpCtx @@ -354,7 +354,7 @@ func (s *FruitsSceneData) SaveLog(p *FruitsPlayerData, isOffline int) { WinAmountNoAnyTax: p.Coin - p.startCoin, IsFirstGame: s.IsPlayerFirst(p.Player), IsFree: totalIn == 0, - GameTime: 1, + GameTime: 2, }) } s.GameNowTime = time.Now() diff --git a/gamesrv/iceage/scenepolicy_iceage.go b/gamesrv/iceage/scenepolicy_iceage.go index 787d74f..762891e 100644 --- a/gamesrv/iceage/scenepolicy_iceage.go +++ b/gamesrv/iceage/scenepolicy_iceage.go @@ -945,7 +945,7 @@ func IceAgeCheckAndSaveLog(sceneEx *IceAgeSceneData, playerEx *IceAgePlayerData) sceneEx.SaveGameDetailedLog(&base.SaveGameDetailedParam{ LogId: logid, Detail: info, - GameTime: 1, + GameTime: 2, }) totalin := int64(playerEx.RollGameType.BaseResult.TotalBet) totalout := playerEx.RollGameType.BaseResult.ChangeCoin + playerEx.taxCoin + totalin @@ -965,7 +965,7 @@ func IceAgeCheckAndSaveLog(sceneEx *IceAgeSceneData, playerEx *IceAgePlayerData) IsFree: playerEx.RollGameType.BaseResult.IsFree, WinSmallGame: playerEx.RollGameType.BaseResult.WinSmallGame, WinTotal: playerEx.RollGameType.BaseResult.WinTotal, - GameTime: 1, + GameTime: 2, }) } } diff --git a/gamesrv/richblessed/scenedata_richblessed.go b/gamesrv/richblessed/scenedata_richblessed.go index 957fc1c..8b35d71 100644 --- a/gamesrv/richblessed/scenedata_richblessed.go +++ b/gamesrv/richblessed/scenedata_richblessed.go @@ -351,7 +351,7 @@ func (s *RichBlessedSceneData) SaveLog(p *RichBlessedPlayerData, isOffline int) s.SaveGameDetailedLog(&base.SaveGameDetailedParam{ LogId: logId, Detail: info, - GameTime: 1, + GameTime: 2, }) //水池上下文环境s s.CpCtx = p.cpCtx @@ -376,7 +376,7 @@ func (s *RichBlessedSceneData) SaveLog(p *RichBlessedPlayerData, isOffline int) WinAmountNoAnyTax: p.Coin - p.startCoin, IsFirstGame: s.IsPlayerFirst(p.Player), IsFree: totalIn == 0, - GameTime: 1, + GameTime: 2, }) } s.GameNowTime = time.Now() diff --git a/gamesrv/tamquoc/scenepolicy_tamquoc.go b/gamesrv/tamquoc/scenepolicy_tamquoc.go index 2a57d3b..e1f908d 100644 --- a/gamesrv/tamquoc/scenepolicy_tamquoc.go +++ b/gamesrv/tamquoc/scenepolicy_tamquoc.go @@ -781,7 +781,7 @@ func TamQuocCheckAndSaveLog(sceneEx *TamQuocSceneData, playerEx *TamQuocPlayerDa sceneEx.SaveGameDetailedLog(&base.SaveGameDetailedParam{ LogId: logid, Detail: info, - GameTime: 1, + GameTime: 2, }) totalin := int64(playerEx.RollGameType.BaseResult.TotalBet) totalout := playerEx.RollGameType.BaseResult.ChangeCoin + playerEx.taxCoin + totalin @@ -801,7 +801,7 @@ func TamQuocCheckAndSaveLog(sceneEx *TamQuocSceneData, playerEx *TamQuocPlayerDa IsFree: playerEx.RollGameType.BaseResult.IsFree, WinSmallGame: playerEx.RollGameType.BaseResult.WinSmallGame, WinTotal: playerEx.RollGameType.BaseResult.WinTotal, - GameTime: 1, + GameTime: 2, }) } } From 383716741cf06208b98f7a2e504346ff9ed73abb Mon Sep 17 00:00:00 2001 From: sk <123456@qq.com> Date: Mon, 2 Dec 2024 14:06:15 +0800 Subject: [PATCH 24/41] =?UTF-8?q?fix=E6=B8=B8=E6=88=8F=E6=97=B6=E9=95=BF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gamesrv/base/scene.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gamesrv/base/scene.go b/gamesrv/base/scene.go index cb10fac..7dfe670 100644 --- a/gamesrv/base/scene.go +++ b/gamesrv/base/scene.go @@ -1471,7 +1471,7 @@ func (this *Scene) SaveGameDetailedLog(param *SaveGameDetailedParam) { return } - if param.GameTime < 0 { + if param.GameTime <= 0 { param.GameTime = int64(time.Now().Sub(this.GameNowTime).Seconds()) } From ae426732245dd92c4a019475d3ee7630729f8d14 Mon Sep 17 00:00:00 2001 From: sk <123456@qq.com> Date: Mon, 2 Dec 2024 14:11:39 +0800 Subject: [PATCH 25/41] =?UTF-8?q?fix=20=E5=8D=81=E4=B8=89=E5=BC=A0?= =?UTF-8?q?=E7=89=8C=E5=B1=80=E8=AE=B0=E5=BD=95=E7=A8=8E=E6=94=B6=E6=AF=94?= =?UTF-8?q?=E4=BE=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gamesrv/thirteen/scenepolicy.go | 2 +- model/gamelogtype.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/gamesrv/thirteen/scenepolicy.go b/gamesrv/thirteen/scenepolicy.go index 274c3f5..cd87a69 100644 --- a/gamesrv/thirteen/scenepolicy.go +++ b/gamesrv/thirteen/scenepolicy.go @@ -1298,7 +1298,7 @@ func (this *StateBilled) OnEnter(s *base.Scene) { RoomType: sceneEx.GetSceneType(), BaseScore: int32(sceneEx.GetBaseScore()), NowRound: int32(sceneEx.NumOfGames), - ClubRate: sceneEx.Scene.PumpCoin, + TaxRate: s.GetDBGameFree().GetTaxRate(), } var person []model.ThirteenWaterPerson for _, o_player := range sceneEx.players { diff --git a/model/gamelogtype.go b/model/gamelogtype.go index 4ca1a01..d9f4185 100644 --- a/model/gamelogtype.go +++ b/model/gamelogtype.go @@ -168,8 +168,8 @@ type ThirteenWaterType struct { NowRound int32 //当前局数 PlayerCount int //玩家数量 BaseScore int32 //底分 + TaxRate int32 //税率(万分比) PlayerData []ThirteenWaterPerson //玩家信息 - ClubRate int32 //俱乐部抽水比例 } type ThirteenWaterPoker struct { From db73856059b3ddbc6db40994ffd69d3b4d248507 Mon Sep 17 00:00:00 2001 From: tomas Date: Tue, 3 Dec 2024 11:13:17 +0800 Subject: [PATCH 26/41] fix tiger --- gamesrv/fortunetiger/scenepolicy_fortunetiger.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/gamesrv/fortunetiger/scenepolicy_fortunetiger.go b/gamesrv/fortunetiger/scenepolicy_fortunetiger.go index 155a835..9557faf 100644 --- a/gamesrv/fortunetiger/scenepolicy_fortunetiger.go +++ b/gamesrv/fortunetiger/scenepolicy_fortunetiger.go @@ -409,7 +409,10 @@ func (this *SceneStateStartFortuneTiger) OnPlayerOp(s *base.Scene, p *base.Playe data = assemble.DataToCli(Response).(assemble.GameEnd) var respinStatus int if data.Results[0].ArrSpins[0].Special != nil { - respinStatus = data.Results[0].ArrSpins[0].Special.(SpinLock).ReSpinStatus + sp, _ := json.Marshal(data.Results[0].ArrSpins[0].Special) + var spinLock SpinLock + json.Unmarshal(sp, &spinLock) + respinStatus = spinLock.ReSpinStatus } if respinStatus == 0 || respinStatus == 1 { //第一次触发或者正常模式 From e13e2398978c0e55e99402f283b7a1b7dd82281b Mon Sep 17 00:00:00 2001 From: tomas Date: Tue, 3 Dec 2024 11:22:12 +0800 Subject: [PATCH 27/41] add mouse --- gamesrv/main.go | 1 + 1 file changed, 1 insertion(+) diff --git a/gamesrv/main.go b/gamesrv/main.go index 5154fc0..5a06e0d 100644 --- a/gamesrv/main.go +++ b/gamesrv/main.go @@ -31,6 +31,7 @@ import ( _ "mongo.games.com/game/gamesrv/caishen" _ "mongo.games.com/game/gamesrv/easterisland" _ "mongo.games.com/game/gamesrv/fortunedragon" + _ "mongo.games.com/game/gamesrv/fortunemouse" _ "mongo.games.com/game/gamesrv/fortuneox" _ "mongo.games.com/game/gamesrv/fortunerabbit" _ "mongo.games.com/game/gamesrv/fortunetiger" From 801200f4bd011954da473b581886d53f050d4f2e Mon Sep 17 00:00:00 2001 From: sk <123456@qq.com> Date: Tue, 3 Dec 2024 13:13:24 +0800 Subject: [PATCH 28/41] add statistics --- common/time.go | 5 + go.mod | 10 +- go.sum | 15 +- statistics/.gitignore | 29 + statistics/README.md | 7 + statistics/build_linux.bat | 8 + statistics/constant/constant.go | 8 + statistics/etc/config.yaml | 27 + statistics/etc/mongo.yaml | 53 + statistics/etc/mysql.yaml | 38 + statistics/logger.xml | 22 + statistics/main.go | 212 +++ .../modelmongo/log_gameplayerlistlog.go | 47 + statistics/modelmongo/log_invitescore.go | 19 + statistics/modelmongo/log_item.go | 27 + statistics/modelmongo/log_login.go | 33 + statistics/modelmongo/user_account.go | 24 + statistics/modelmysql/bankrupt.go | 12 + statistics/modelmysql/log_invitescore.go | 26 + statistics/modelmysql/log_itemgain.go | 16 + statistics/modelmysql/log_login.go | 26 + statistics/modelmysql/log_login_mid.go | 6 + statistics/modelmysql/log_mid.go | 11 + statistics/modelmysql/tables.go | 17 + statistics/modelmysql/user_account.go | 18 + statistics/modelmysql/user_id.go | 9 + statistics/modelmysql/user_login.go | 29 + statistics/mq/handler.go | 1 + statistics/mq/readme | 1 + statistics/static/readme | 1 + statistics/static/user_login.go | 371 ++++ statistics/syn/datasync.go | 102 ++ statistics/syn/log_invitescore.go | 291 +++ statistics/syn/log_itemgain.go | 61 + statistics/syn/log_login.go | 181 ++ statistics/syn/readme | 1 + statistics/syn/user_account.go | 105 ++ statistics/task/build_linux.bat | 5 + statistics/task/etc/DB_GameFree.dat | Bin 0 -> 24144 bytes statistics/task/etc/config.yaml | 221 +++ statistics/task/etc/mongo.yaml | 53 + statistics/task/etc/mysql.yaml | 38 + statistics/task/excelmgr.go | 88 + statistics/task/gamefree/db_gamefree.go | 77 + statistics/task/logger.xml | 22 + statistics/task/main.go | 427 +++++ statistics/task/readme | 1 + statistics/task/task/bankruptcy.go | 189 ++ statistics/task/task/bankruptoffline.go | 153 ++ statistics/task/task/coin.go | 77 + statistics/task/task/ctrlrate.go | 214 +++ statistics/task/task/gamebankruptcy.go | 69 + statistics/task/task/gamecount.go | 60 + statistics/task/task/gamelogtype.go | 1625 +++++++++++++++++ statistics/task/task/gamerate.go | 110 ++ statistics/task/task/gametime.go | 104 ++ statistics/task/task/rechargeoffline.go | 62 + statistics/task/task/robotwin.go | 138 ++ 58 files changed, 5593 insertions(+), 9 deletions(-) create mode 100644 statistics/.gitignore create mode 100644 statistics/README.md create mode 100644 statistics/build_linux.bat create mode 100644 statistics/constant/constant.go create mode 100644 statistics/etc/config.yaml create mode 100644 statistics/etc/mongo.yaml create mode 100644 statistics/etc/mysql.yaml create mode 100644 statistics/logger.xml create mode 100644 statistics/main.go create mode 100644 statistics/modelmongo/log_gameplayerlistlog.go create mode 100644 statistics/modelmongo/log_invitescore.go create mode 100644 statistics/modelmongo/log_item.go create mode 100644 statistics/modelmongo/log_login.go create mode 100644 statistics/modelmongo/user_account.go create mode 100644 statistics/modelmysql/bankrupt.go create mode 100644 statistics/modelmysql/log_invitescore.go create mode 100644 statistics/modelmysql/log_itemgain.go create mode 100644 statistics/modelmysql/log_login.go create mode 100644 statistics/modelmysql/log_login_mid.go create mode 100644 statistics/modelmysql/log_mid.go create mode 100644 statistics/modelmysql/tables.go create mode 100644 statistics/modelmysql/user_account.go create mode 100644 statistics/modelmysql/user_id.go create mode 100644 statistics/modelmysql/user_login.go create mode 100644 statistics/mq/handler.go create mode 100644 statistics/mq/readme create mode 100644 statistics/static/readme create mode 100644 statistics/static/user_login.go create mode 100644 statistics/syn/datasync.go create mode 100644 statistics/syn/log_invitescore.go create mode 100644 statistics/syn/log_itemgain.go create mode 100644 statistics/syn/log_login.go create mode 100644 statistics/syn/readme create mode 100644 statistics/syn/user_account.go create mode 100644 statistics/task/build_linux.bat create mode 100644 statistics/task/etc/DB_GameFree.dat create mode 100644 statistics/task/etc/config.yaml create mode 100644 statistics/task/etc/mongo.yaml create mode 100644 statistics/task/etc/mysql.yaml create mode 100644 statistics/task/excelmgr.go create mode 100644 statistics/task/gamefree/db_gamefree.go create mode 100644 statistics/task/logger.xml create mode 100644 statistics/task/main.go create mode 100644 statistics/task/readme create mode 100644 statistics/task/task/bankruptcy.go create mode 100644 statistics/task/task/bankruptoffline.go create mode 100644 statistics/task/task/coin.go create mode 100644 statistics/task/task/ctrlrate.go create mode 100644 statistics/task/task/gamebankruptcy.go create mode 100644 statistics/task/task/gamecount.go create mode 100644 statistics/task/task/gamelogtype.go create mode 100644 statistics/task/task/gamerate.go create mode 100644 statistics/task/task/gametime.go create mode 100644 statistics/task/task/rechargeoffline.go create mode 100644 statistics/task/task/robotwin.go diff --git a/common/time.go b/common/time.go index e54bfaa..907796b 100644 --- a/common/time.go +++ b/common/time.go @@ -204,3 +204,8 @@ func StrTimeToTime(s string) time.Time { t, _ := time.ParseInLocation("2006-01-02 15:04:05", s, time.Local) return t } + +func StrRFC3339TimeToTime(s string) time.Time { + t, _ := time.Parse(time.RFC3339, s) + return t +} diff --git a/go.mod b/go.mod index 1ae0dd7..0eee4a1 100644 --- a/go.mod +++ b/go.mod @@ -26,13 +26,13 @@ require ( github.com/tomas-qstarrs/boost v1.0.3 github.com/tomas-qstarrs/excel-converter v1.0.2 github.com/wendal/errors v0.0.0-20181209125328-7f31f4b264ec + github.com/xuri/excelize/v2 v2.9.0 github.com/zegoim/zego_server_assistant/token/go/src v0.0.0-20231013093807-4e80bab42ec3 github.com/zeromicro/go-zero v1.7.3 go.etcd.io/etcd/client/v3 v3.5.16 go.mongodb.org/mongo-driver v1.17.1 golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c google.golang.org/protobuf v1.35.1 - gorm.io/driver/mysql v1.5.7 gorm.io/gorm v1.25.12 mongo.games.com/goserver v0.0.0-00010101000000-000000000000 ) @@ -70,7 +70,7 @@ require ( github.com/pelletier/go-toml/v2 v2.2.2 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/richardlehane/mscfb v1.0.4 // indirect - github.com/richardlehane/msoleps v1.0.3 // indirect + github.com/richardlehane/msoleps v1.0.4 // indirect github.com/sagikazarmark/locafero v0.4.0 // indirect github.com/sagikazarmark/slog-shim v0.1.0 // indirect github.com/shopspring/decimal v1.3.1 // indirect @@ -92,7 +92,8 @@ require ( github.com/xdg-go/scram v1.1.2 // indirect github.com/xdg-go/stringprep v1.0.4 // indirect github.com/xtaci/kcp-go v5.4.20+incompatible // indirect - github.com/xuri/efp v0.0.0-20220603152613-6918739fd470 // indirect + github.com/xuri/efp v0.0.0-20240408161823-9ad904a10d6d // indirect + github.com/xuri/nfp v0.0.0-20240318013403-ab9948c2c4a7 // indirect github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect go.etcd.io/etcd/api/v3 v3.5.16 // indirect go.etcd.io/etcd/client/pkg/v3 v3.5.16 // indirect @@ -103,7 +104,7 @@ require ( go.uber.org/multierr v1.9.0 // indirect go.uber.org/zap v1.24.0 // indirect golang.org/x/crypto v0.28.0 // indirect - golang.org/x/image v0.13.0 // indirect + golang.org/x/image v0.18.0 // indirect golang.org/x/net v0.30.0 // indirect golang.org/x/sync v0.8.0 // indirect golang.org/x/sys v0.26.0 // indirect @@ -115,4 +116,5 @@ require ( gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect + gorm.io/driver/mysql v1.5.7 // indirect ) diff --git a/go.sum b/go.sum index 79422ec..00dcca3 100644 --- a/go.sum +++ b/go.sum @@ -279,8 +279,8 @@ github.com/richardlehane/mscfb v1.0.3/go.mod h1:YzVpcZg9czvAuhk9T+a3avCpcFPMUWm7 github.com/richardlehane/mscfb v1.0.4 h1:WULscsljNPConisD5hR0+OyZjwK46Pfyr6mPu5ZawpM= github.com/richardlehane/mscfb v1.0.4/go.mod h1:YzVpcZg9czvAuhk9T+a3avCpcFPMUWm7gK3DypaEsUk= github.com/richardlehane/msoleps v1.0.1/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTKbjLycmwiWUfWg= -github.com/richardlehane/msoleps v1.0.3 h1:aznSZzrwYRl3rLKRT3gUk9am7T/mLNSnJINvN0AQoVM= -github.com/richardlehane/msoleps v1.0.3/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTKbjLycmwiWUfWg= +github.com/richardlehane/msoleps v1.0.4 h1:WuESlvhX3gH2IHcd8UqyCuFY5yiq/GR/yqaSM/9/g00= +github.com/richardlehane/msoleps v1.0.4/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTKbjLycmwiWUfWg= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= @@ -386,8 +386,12 @@ github.com/xtaci/kcp-go v5.4.20+incompatible/go.mod h1:bN6vIwHQbfHaHtFpEssmWsN45 github.com/xtaci/lossyconn v0.0.0-20200209145036-adba10fffc37 h1:EWU6Pktpas0n8lLQwDsRyZfmkPeRbdgPtW609es+/9E= github.com/xtaci/lossyconn v0.0.0-20200209145036-adba10fffc37/go.mod h1:HpMP7DB2CyokmAh4lp0EQnnWhmycP/TvwBGzvuie+H0= github.com/xuri/efp v0.0.0-20200605144744-ba689101faaf/go.mod h1:uBiSUepVYMhGTfDeBKKasV4GpgBlzJ46gXUBAqV8qLk= -github.com/xuri/efp v0.0.0-20220603152613-6918739fd470 h1:6932x8ltq1w4utjmfMPVj09jdMlkY0aiA6+Skbtl3/c= -github.com/xuri/efp v0.0.0-20220603152613-6918739fd470/go.mod h1:ybY/Jr0T0GTCnYjKqmdwxyxn2BQf2RcQIIvex5QldPI= +github.com/xuri/efp v0.0.0-20240408161823-9ad904a10d6d h1:llb0neMWDQe87IzJLS4Ci7psK/lVsjIS2otl+1WyRyY= +github.com/xuri/efp v0.0.0-20240408161823-9ad904a10d6d/go.mod h1:ybY/Jr0T0GTCnYjKqmdwxyxn2BQf2RcQIIvex5QldPI= +github.com/xuri/excelize/v2 v2.9.0 h1:1tgOaEq92IOEumR1/JfYS/eR0KHOCsRv/rYXXh6YJQE= +github.com/xuri/excelize/v2 v2.9.0/go.mod h1:uqey4QBZ9gdMeWApPLdhm9x+9o2lq4iVmjiLfBS5hdE= +github.com/xuri/nfp v0.0.0-20240318013403-ab9948c2c4a7 h1:hPVCafDV85blFTabnqKgNhDCkJX25eik94Si9cTER4A= +github.com/xuri/nfp v0.0.0-20240318013403-ab9948c2c4a7/go.mod h1:WwHg+CVyzlv/TX9xqBFXEZAuxOPxn2k1GNHwG41IIUQ= github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 h1:ilQV1hzziu+LLM3zUTJ0trRztfwgjqKnBWNtSRkbmwM= github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78/go.mod h1:aL8wCCfTfSfmXjznFBSZNN13rSJjlIOI1fUNAtF7rmI= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -441,8 +445,9 @@ golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c h1:7dEasQXItcW1xKJ2+gg5VOiBnqWrJc+rq0DPKyvvdbY= golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c/go.mod h1:NQtJDoLvd6faHhE7m4T/1IY708gDefGGjR/iUW8yQQ8= golang.org/x/image v0.0.0-20200922025426-e59bae62ef32/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= -golang.org/x/image v0.13.0 h1:3cge/F/QTkNLauhf2QoE9zp+7sr+ZcL4HnoZmdwg9sg= golang.org/x/image v0.13.0/go.mod h1:6mmbMOeV28HuMTgA6OSRkdXKYw/t5W9Uwn2Yv1r3Yxk= +golang.org/x/image v0.18.0 h1:jGzIakQa/ZXI1I0Fxvaa9W7yP25TqT6cHIHn+6CqvSQ= +golang.org/x/image v0.18.0/go.mod h1:4yyo5vMFQjVjUcVk4jEQcU9MGy/rulF5WvUILseCM2E= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= diff --git a/statistics/.gitignore b/statistics/.gitignore new file mode 100644 index 0000000..3c58f2a --- /dev/null +++ b/statistics/.gitignore @@ -0,0 +1,29 @@ +# ---> Go +# If you prefer the allow list template instead of the deny list, see community template: +# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore +# +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib +*.xlsx + +# Test binary, built with `go test -c` +*.test +local_test.go + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Dependency directories (remove the comment below to include it) +# vendor/ + +# Go workspace file +go.work + +.idea +.vscode +log + diff --git a/statistics/README.md b/statistics/README.md new file mode 100644 index 0000000..71f24d5 --- /dev/null +++ b/statistics/README.md @@ -0,0 +1,7 @@ +# statistics + +数据分析服务 + * mongodb同步到mysql + * 接收消息队列数据 + * 历史数据查询 + * 数据统计 \ No newline at end of file diff --git a/statistics/build_linux.bat b/statistics/build_linux.bat new file mode 100644 index 0000000..7962122 --- /dev/null +++ b/statistics/build_linux.bat @@ -0,0 +1,8 @@ +set GOPATH=D:\godev +go env -w GO111MODULE=on + +set CGO_ENABLED=0 +set GOOS=linux +set GOARCH=amd64 +go build +pause \ No newline at end of file diff --git a/statistics/constant/constant.go b/statistics/constant/constant.go new file mode 100644 index 0000000..78818e0 --- /dev/null +++ b/statistics/constant/constant.go @@ -0,0 +1,8 @@ +package constant + +const ( + InviteScoreTypeBind = 1 // 绑定邀请码 + InviteScoreTypePay = 2 // 充值返佣 + InviteScoreTypeRecharge = 3 // 充值完成 + InviteScoreTypePayMe = 4 // 充值(自己) +) diff --git a/statistics/etc/config.yaml b/statistics/etc/config.yaml new file mode 100644 index 0000000..ba82d5c --- /dev/null +++ b/statistics/etc/config.yaml @@ -0,0 +1,27 @@ +# 平台id +platforms: + - 1 + +# 几秒同步一次数据 +# 注册表,登录日志表 +update_second: 60 +# 注册表每次同步多少条数据 +update_account_num: 100 +# 登录日志每次同步多少条数据 +update_login_num: 100 +# 几秒读取一次玩家id列表 +update_second_snid: 30 +# 最多触发几个玩家数据更新 +update_snid_num: 100 + +# 邀请数据统计 +# 几秒读取一次邀请记录 +update_second_invite: 10 +# 一次最多读取多少条邀请记录 +update_invite_num: 30 + +# 道具获得数量统计 +# 几秒读取一次道具日志 +update_second_item: 10 +# 一次最多读取多少道具日志 +update_item_num: 100 \ No newline at end of file diff --git a/statistics/etc/mongo.yaml b/statistics/etc/mongo.yaml new file mode 100644 index 0000000..7f9e42d --- /dev/null +++ b/statistics/etc/mongo.yaml @@ -0,0 +1,53 @@ +global: + user: + HostName: 127.0.0.1 + HostPort: 27017 + Database: win88_global + Username: + Password: + Options: + log: + HostName: 127.0.0.1 + HostPort: 27017 + Database: win88_log + Username: + Password: + Options: + monitor: + HostName: 127.0.0.1 + HostPort: 27017 + Database: win88_monitor + Username: + Password: + Options: +platforms: + 0: + user: + HostName: 127.0.0.1 + HostPort: 27017 + Database: win88_user_plt_000 + Username: + Password: + Options: + log: + HostName: 127.0.0.1 + HostPort: 27017 + Database: win88_log_plt_000 + Username: + Password: + Options: + 1: + user: + HostName: 127.0.0.1 + HostPort: 27017 + Database: win88_user_plt_001 + Username: + Password: + Options: + log: + HostName: 127.0.0.1 + HostPort: 27017 + Database: win88_log_plt_001 + Username: + Password: + Options: \ No newline at end of file diff --git a/statistics/etc/mysql.yaml b/statistics/etc/mysql.yaml new file mode 100644 index 0000000..82d1fe3 --- /dev/null +++ b/statistics/etc/mysql.yaml @@ -0,0 +1,38 @@ +platforms: + global: + HostName: 127.0.0.1 + HostPort: 3306 + Database: win88_user + Username: root + Password: 123456 + Options: charset=utf8mb4&parseTime=True&loc=Local + 0: + HostName: 127.0.0.1 + HostPort: 3306 + Database: win88_plt_000 + Username: root + Password: 123456 + Options: charset=utf8mb4&parseTime=True&loc=Local + 1: + HostName: 127.0.0.1 + HostPort: 3306 + Database: win88_plt_001 + Username: root + Password: 123456 + Options: charset=utf8mb4&parseTime=True&loc=Local + count: # 破产日志库 + HostName: 127.0.0.1 + HostPort: 3306 + Database: dbmis_count + Username: root + Password: 123456 + Options: charset=utf8mb4&parseTime=True&loc=Local + +# 最大空闲连接数 +MaxIdleConns: 10 +# 最大连接数 +MaxOpenConns: 100 +# 连接可复用的最大时间 +ConnMaxLifetime: 3600 +# 连接最大空闲时间 +ConnMaxIdletime: 0 \ No newline at end of file diff --git a/statistics/logger.xml b/statistics/logger.xml new file mode 100644 index 0000000..f6eb37b --- /dev/null +++ b/statistics/logger.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/statistics/main.go b/statistics/main.go new file mode 100644 index 0000000..23e6b9f --- /dev/null +++ b/statistics/main.go @@ -0,0 +1,212 @@ +package main + +import ( + "context" + "fmt" + "os" + "os/signal" + "sync" + "time" + + "github.com/spf13/viper" + "mongo.games.com/goserver/core/logger" + "mongo.games.com/goserver/core/mongox" + "mongo.games.com/goserver/core/mysqlx" + "mongo.games.com/goserver/core/utils" + "mongo.games.com/goserver/core/viperx" + + mongomodel "mongo.games.com/game/statistics/modelmongo" + mysqlmodel "mongo.games.com/game/statistics/modelmysql" + "mongo.games.com/game/statistics/static" + "mongo.games.com/game/statistics/syn" +) + +var VP *viper.Viper + +// DoTick 定时执行 +func DoTick(ctx context.Context, wg *sync.WaitGroup, duration time.Duration, fu func(ctx context.Context)) { + wg.Add(1) + go func() { + defer wg.Done() + for { + select { + case <-ctx.Done(): + return + case <-time.After(duration): + utils.RecoverPanicFunc() // 捕获异常 + fu(ctx) + } + } + }() +} + +// DoTickPlatform 定时执行,根据platform执行 +func DoTickPlatform(ctx context.Context, wg *sync.WaitGroup, duration time.Duration, batchSize int, + fu func(ctx context.Context, platform string, batchSize int)) { + wg.Add(1) + go func() { + defer wg.Done() + for { + select { + case <-ctx.Done(): + return + case <-time.After(duration): + utils.RecoverPanicFunc() // 捕获异常 + wg := new(sync.WaitGroup) + for _, v := range VP.GetStringSlice("platforms") { + platform := v + wg.Add(1) + go func() { + defer wg.Done() + fu(ctx, platform, batchSize) + }() + } + wg.Wait() + } + } + }() +} + +func main() { + VP = viperx.GetViper("config", "yaml") + // mongo + vp := viperx.GetViper("mongo", "yaml") + // mongo初始化 + conf := &mongox.Config{} + err := vp.Unmarshal(conf) + if err != nil { + panic(fmt.Errorf("mongo config error: %v", err)) + } + mongox.Init(conf) + defer mongox.Close() + + // mysql + vp = viperx.GetViper("mysql", "yaml") + myConf := &mysqlx.Config{} + err = vp.Unmarshal(myConf) + if err != nil { + panic(fmt.Errorf("mysql config error: %v", err)) + } + mysqlx.Init(myConf) + defer mysqlx.Close() + + mysqlx.SetAutoMigrateTables(mysqlmodel.Tables) + + wg := &sync.WaitGroup{} + ctx, cancel := context.WithCancel(context.Background()) + + DoTick(ctx, wg, time.Duration(VP.GetInt64("update_second"))*time.Second, SyncSnId) + + DoTick(ctx, wg, time.Duration(VP.GetInt64("update_second_snid"))*time.Second, func(ctx context.Context) { + wg := new(sync.WaitGroup) + for _, v := range VP.GetStringSlice("platforms") { + platform := v + wg.Add(1) + go func() { + defer wg.Done() + Static(platform) + }() + } + wg.Wait() + }) + + DoTick(ctx, wg, time.Duration(VP.GetInt64("update_second_invite"))*time.Second, SyncInvite) + + DoTickPlatform(ctx, wg, time.Duration(VP.GetInt64("update_second_item"))*time.Second, VP.GetInt("update_item_num"), + func(ctx context.Context, platform string, batchSize int) { + err := syn.ItemGainDone(&syn.Data[mongomodel.ItemLog]{ + Platform: platform, + BatchSize: batchSize, + }) + if err != nil { + logger.Logger.Errorf("SyncItem error:%v", err) + } + }) + + logger.Logger.Info("start") + + c := make(chan os.Signal, 1) + signal.Notify(c, os.Interrupt, os.Kill) + sig := <-c + logger.Logger.Infof("closing down (signal: %v)", sig) + + // release + cancel() + wg.Wait() + + logger.Logger.Info("closed") +} + +// SyncSnId 同步注册和登录日志 +func SyncSnId(ctx context.Context) { + wg := new(sync.WaitGroup) + for _, v := range VP.GetStringSlice("platforms") { + platform := v + wg.Add(1) + go func() { + defer wg.Done() + _, err := syn.UserAccount(platform, VP.GetInt("update_account_num")) + if err != nil { + logger.Logger.Errorf("SyncUserAccount error: %v", err) + return + } + + _, err = syn.LogLogin(platform, VP.GetInt("update_login_num")) + if err != nil { + logger.Logger.Errorf("SyncLogLogin error: %v", err) + return + } + }() + } + wg.Wait() +} + +// Static 玩家id触发数据统计 +func Static(platform string) { + // 查询需要更新的玩家id + var ids []*mysqlmodel.UserID + db, err := mysqlx.GetDatabase(platform) + if err != nil { + logger.Logger.Errorf("GetDatabase error: %v", err) + return + } + if err := db.Limit(VP.GetInt("update_snid_num")).Find(&ids).Error; err != nil { + logger.Logger.Warnf("Get UserID error: %v", err) + return + } + + if len(ids) == 0 { + logger.Logger.Tracef("Static: no need to update") + return + } + + // 统计玩家跳出记录 + if err := static.UserLogin(platform, ids); err != nil { + logger.Logger.Errorf("StaticUserLogin error: %v", err) + return + } + + // 删除更新过的玩家id + if err := db.Delete(ids).Error; err != nil { + logger.Logger.Errorf("Delete error: %v", err) + return + } +} + +// SyncInvite 同步邀请数据 +func SyncInvite(ctx context.Context) { + wg := new(sync.WaitGroup) + for _, v := range VP.GetStringSlice("platforms") { + platform := v + wg.Add(1) + go func() { + defer wg.Done() + err := syn.SyncInviteScore(platform, VP.GetInt("update_invite_num")) + if err != nil { + logger.Logger.Errorf("SyncInviteScore error: %v", err) + return + } + }() + } + wg.Wait() +} diff --git a/statistics/modelmongo/log_gameplayerlistlog.go b/statistics/modelmongo/log_gameplayerlistlog.go new file mode 100644 index 0000000..a2a2917 --- /dev/null +++ b/statistics/modelmongo/log_gameplayerlistlog.go @@ -0,0 +1,47 @@ +package modelmongo + +import ( + "time" + + "go.mongodb.org/mongo-driver/bson/primitive" +) + +const LogGamePlayerListLog = "log_gameplayerlistlog" + +type GamePlayerListLog struct { + LogId primitive.ObjectID `bson:"_id"` + SnId int32 //用户Id + Name string //名称 + GameId int32 //游戏id + BaseScore int32 //游戏底注 + ClubId int32 //俱乐部Id + ClubRoom string //俱乐部包间 + TaxCoin int64 //税收 + ClubPumpCoin int64 //俱乐部额外抽水 + Platform string //平台id + Channel string //渠道 + Promoter string //推广员 + PackageTag string //包标识 + SceneId int32 //场景ID + GameMode int32 //游戏类型 + GameFreeid int32 //游戏类型房间号 + GameDetailedLogId string //游戏记录Id + IsFirstGame bool //是否第一次游戏 + //对于拉霸类:BetAmount=100 WinAmountNoAnyTax=0 (表示投入多少、收益多少,值>=0) + //拉霸类小游戏会是:BetAmount=0 WinAmountNoAnyTax=100 (投入0、收益多少,值>=0) + //对战场:BetAmount=0 WinAmountNoAnyTax=100 (投入会有是0、收益有正负,WinAmountNoAnyTax=100则盈利,WinAmountNoAnyTax=-100则输100) + BetAmount int64 //下注金额 + WinAmountNoAnyTax int64 //盈利金额,不包含任何税 + TotalIn int64 //本局投入 + TotalOut int64 //本局产出 + Time time.Time //记录时间 + RoomType int32 //房间类型 + GameDif string //游戏标识 + GameClass int32 //游戏类型 1棋牌 2电子 3百人 4捕鱼 5视讯 6彩票 7体育 + MatchId int32 + MatchType int32 //0.普通场 1.锦标赛 2.冠军赛 3.vip专属 + Ts int32 + IsFree bool //拉霸专用 是否免费 + WinSmallGame int64 //拉霸专用 小游戏奖励 + WinTotal int64 //拉霸专用 输赢 +} diff --git a/statistics/modelmongo/log_invitescore.go b/statistics/modelmongo/log_invitescore.go new file mode 100644 index 0000000..4a0b636 --- /dev/null +++ b/statistics/modelmongo/log_invitescore.go @@ -0,0 +1,19 @@ +package modelmongo + +import ( + "go.mongodb.org/mongo-driver/bson/primitive" +) + +const LogInviteScore = "log_invitescore" + +type InviteScore struct { + Id primitive.ObjectID `bson:"_id"` + UpSnid int // 上级代理 + DownSnid int // 下级代理 + Level int // 代理层级 例如 1:DownSnid 是 UpSnid 的 1 级代理; 2: DownSnid 是 UpSnid 的 2 级代理 + Tp int // 返佣类型 + Rate int // 返佣比例 + Score int // 积分 + Money int // 充值金额 + Ts int // 时间戳 +} diff --git a/statistics/modelmongo/log_item.go b/statistics/modelmongo/log_item.go new file mode 100644 index 0000000..4d7221f --- /dev/null +++ b/statistics/modelmongo/log_item.go @@ -0,0 +1,27 @@ +package modelmongo + +import "go.mongodb.org/mongo-driver/bson/primitive" + +const LogItem = "log_itemlog" + +type ItemInfo struct { + ItemId int32 + ItemNum int64 +} + +type ItemLog struct { + LogId primitive.ObjectID `bson:"_id"` + Platform string //平台 + SnId int32 //玩家id + LogType int32 //记录类型 0.获取 1.消耗 + ItemId int32 //道具id + ItemName string //道具名称 + Count int64 //个数 + CreateTs int64 //记录时间 + Remark string //备注 + TypeId int32 // 变化类型 + GameId int32 // 游戏id,游戏中获得时有值 + GameFreeId int32 // 场次id,游戏中获得时有值 + Cost []*ItemInfo // 消耗的道具 + Id string // 撤销的id,兑换失败 +} diff --git a/statistics/modelmongo/log_login.go b/statistics/modelmongo/log_login.go new file mode 100644 index 0000000..5145ffe --- /dev/null +++ b/statistics/modelmongo/log_login.go @@ -0,0 +1,33 @@ +package modelmongo + +import ( + "time" + + "go.mongodb.org/mongo-driver/bson/primitive" +) + +const LogLogin = "log_login" + +const ( + LogTypeLogin int32 = iota // 登录 + LogTypeLogout // 登出 + LogTypeRehold // 重连 + LogTypeDrop // 掉线 +) + +type LoginLog struct { + LogId primitive.ObjectID `bson:"_id"` + Platform string //平台id + SnId int32 + LogType int32 + Ts int64 + Time time.Time + GameId int // 玩家掉线时所在游戏id + LastGameID int // 玩家最后所在游戏id + ChannelId string // 推广渠道 + + DeviceName string + AppVersion string + BuildVersion string + AppChannel string +} diff --git a/statistics/modelmongo/user_account.go b/statistics/modelmongo/user_account.go new file mode 100644 index 0000000..89979bf --- /dev/null +++ b/statistics/modelmongo/user_account.go @@ -0,0 +1,24 @@ +package modelmongo + +import ( + "time" + + "go.mongodb.org/mongo-driver/bson/primitive" +) + +const UserAccount = "user_account" + +type Account struct { + AccountId primitive.ObjectID `bson:"_id"` + SnId int32 // 玩家账号直接在这里生成 + Platform string // 平台 + RegisterTs int64 // 注册时间戳 + RegisteTime time.Time + ChannelId string // 推广渠道 + + Tel string `gorm:"index"` + DeviceName string `gorm:"index"` + AppVersion string `gorm:"index"` + BuildVersion string `gorm:"index"` + AppChannel string `gorm:"index"` +} diff --git a/statistics/modelmysql/bankrupt.go b/statistics/modelmysql/bankrupt.go new file mode 100644 index 0000000..1ade115 --- /dev/null +++ b/statistics/modelmysql/bankrupt.go @@ -0,0 +1,12 @@ +package modelmysql + +type Bankrupt struct { + Id int `json:"id" gorm:"column:id"` + Platform int `json:"platform" gorm:"column:platform"` + Snid int `json:"snid" gorm:"column:snid"` + RegTs int `json:"register_time" gorm:"column:register_time"` + GameId int `json:"game_id" gorm:"column:game_id"` + GameFreeId int `json:"game_free_id" gorm:"column:game_free_id"` + Coin int `json:"use_coin" gorm:"column:use_coin"` + Ts int `json:"bankrupt_time" gorm:"column:bankrupt_time"` +} diff --git a/statistics/modelmysql/log_invitescore.go b/statistics/modelmysql/log_invitescore.go new file mode 100644 index 0000000..b5ffdf4 --- /dev/null +++ b/statistics/modelmysql/log_invitescore.go @@ -0,0 +1,26 @@ +package modelmysql + +type LogInviteScoreMid struct { + ID uint `gorm:"primaryKey"` + MID string +} + +type LogInviteScore struct { + ID uint `gorm:"primaryKey"` + UpSnid int `gorm:"index"` // 上级代理 + DownSnid int `gorm:"index"` // 下级代理 + Level int `gorm:"index"` // 代理层级 例如 1:DownSnid 是 UpSnid 的 1 级代理; 2: DownSnid 是 UpSnid 的 2 级代理 + Tp int `gorm:"index"` // 返佣类型 + Rate int `gorm:"index"` // 返佣比例 + Score int `gorm:"index"` // 积分 + Money int `gorm:"index"` // 充值金额 + Ts int `gorm:"index"` // 时间戳 +} + +type LogInviteUser struct { + ID uint `gorm:"primaryKey"` + Psnid int `gorm:"index"` // 当前玩家 + Snid int `gorm:"index"` // 一级代理 + Level int `gorm:"index"` // 代理层级 例如 1:DownSnid 是 UpSnid 的 1 级代理; 2: DownSnid 是 UpSnid 的 2 级代理 + Ts int `gorm:"index"` // 绑定时间 +} diff --git a/statistics/modelmysql/log_itemgain.go b/statistics/modelmysql/log_itemgain.go new file mode 100644 index 0000000..a672611 --- /dev/null +++ b/statistics/modelmysql/log_itemgain.go @@ -0,0 +1,16 @@ +package modelmysql + +// ItemGain 道具获得数量,以小时,道具id,做主键 +type ItemGain struct { + ID uint `gorm:"primaryKey"` + Hour int64 `gorm:"index:idx_item"` // 小时时间戳,每小时统计一次 + ItemId int32 `gorm:"index:idx_item"` // 道具id + ItemNum int64 // 道具数量 +} + +// ItemTotalGain 道具获得总数 +type ItemTotalGain struct { + ID uint `gorm:"primaryKey"` + ItemId int32 `gorm:"index"` // 道具id + ItemNum int64 // 道具数量 +} diff --git a/statistics/modelmysql/log_login.go b/statistics/modelmysql/log_login.go new file mode 100644 index 0000000..912d748 --- /dev/null +++ b/statistics/modelmysql/log_login.go @@ -0,0 +1,26 @@ +package modelmysql + +import "time" + +const ( + LogTypeLogin = 1 // 登录 + LogTypeRehold = 2 // 重连 + LogTypeOffline = 3 // 离线 +) + +type LogLogin struct { + ID uint `gorm:"primaryKey"` + Snid int `gorm:"index"` + OnlineType int `gorm:"index"` + //OnlineTs int `gorm:"index"` + OnlineTime time.Time `gorm:"index"` + OfflineType int `gorm:"index"` + //OfflineTs int `gorm:"index"` + OfflineTime time.Time `gorm:"index"` + ChannelId string `gorm:"index"` // 推广渠道 + + DeviceName string `gorm:"index"` + AppVersion string `gorm:"index"` + BuildVersion string `gorm:"index"` + AppChannel string `gorm:"index"` +} diff --git a/statistics/modelmysql/log_login_mid.go b/statistics/modelmysql/log_login_mid.go new file mode 100644 index 0000000..1b1385e --- /dev/null +++ b/statistics/modelmysql/log_login_mid.go @@ -0,0 +1,6 @@ +package modelmysql + +type LogLoginMid struct { + ID uint `gorm:"primaryKey"` + MID string +} diff --git a/statistics/modelmysql/log_mid.go b/statistics/modelmysql/log_mid.go new file mode 100644 index 0000000..ebca072 --- /dev/null +++ b/statistics/modelmysql/log_mid.go @@ -0,0 +1,11 @@ +package modelmysql + +const ( + MidTypeItem = 1 // 道具记录 +) + +type LogMid struct { + ID uint `gorm:"primaryKey"` + Tp int `gorm:"index"` // 类型 + MID string +} diff --git a/statistics/modelmysql/tables.go b/statistics/modelmysql/tables.go new file mode 100644 index 0000000..8f9bd15 --- /dev/null +++ b/statistics/modelmysql/tables.go @@ -0,0 +1,17 @@ +package modelmysql + +// 需要自动迁移的表添加在这里 Tables + +var Tables = []interface{}{ + &LogLogin{}, + &LogLoginMid{}, + &UserAccount{}, + &UserLogin{}, + &UserID{}, + &LogInviteScoreMid{}, + &LogInviteScore{}, + &LogInviteUser{}, + &LogMid{}, + &ItemGain{}, + &ItemTotalGain{}, +} diff --git a/statistics/modelmysql/user_account.go b/statistics/modelmysql/user_account.go new file mode 100644 index 0000000..0d56bbf --- /dev/null +++ b/statistics/modelmysql/user_account.go @@ -0,0 +1,18 @@ +package modelmysql + +import "time" + +type UserAccount struct { + ID uint `gorm:"primaryKey"` + MID string + Snid int `gorm:"index"` + //RegisterTs int `gorm:"index"` + RegisterTime time.Time `gorm:"index"` + ChannelId string `gorm:"index"` // 推广渠道 + + DeviceName string `gorm:"index"` + AppVersion string `gorm:"index"` + BuildVersion string `gorm:"index"` + AppChannel string `gorm:"index"` + Tel string `gorm:"index"` +} diff --git a/statistics/modelmysql/user_id.go b/statistics/modelmysql/user_id.go new file mode 100644 index 0000000..5a3ce33 --- /dev/null +++ b/statistics/modelmysql/user_id.go @@ -0,0 +1,9 @@ +package modelmysql + +/* + 服务定期查询注册和登录信息,然后获取玩家id,保存到这张表中;用于后续触发和玩家相关的数据统计 +*/ + +type UserID struct { + Snid int `gorm:"primaryKey"` +} diff --git a/statistics/modelmysql/user_login.go b/statistics/modelmysql/user_login.go new file mode 100644 index 0000000..4ed6e93 --- /dev/null +++ b/statistics/modelmysql/user_login.go @@ -0,0 +1,29 @@ +package modelmysql + +import "time" + +const ( + OutTypRegister = 1 // 注册 + OutTypeLogin = 2 // 登录 + OutTypeGaming = 3 // 游戏中 + OutTypeGameOver = 4 // 游戏结束 +) + +type UserLogin struct { + ID uint `gorm:"primaryKey"` + Snid int `gorm:"uniqueIndex"` + //OnlineTs int `gorm:"index"` + OnlineTime time.Time `gorm:"index"` + //OfflineTs int `gorm:"index"` + OfflineTime time.Time `gorm:"index"` + OutType int `gorm:"index"` // 跳出类型 + GameID int `gorm:"index"` // 游戏id + Age int + Sex int + DeviceName string `gorm:"index"` + AppVersion string `gorm:"index"` + BuildVersion string `gorm:"index"` + AppChannel string `gorm:"index"` + Tel string `gorm:"index"` + ChannelId string `gorm:"index"` // 推广渠道 +} diff --git a/statistics/mq/handler.go b/statistics/mq/handler.go new file mode 100644 index 0000000..71893fd --- /dev/null +++ b/statistics/mq/handler.go @@ -0,0 +1 @@ +package mq diff --git a/statistics/mq/readme b/statistics/mq/readme new file mode 100644 index 0000000..9c843ee --- /dev/null +++ b/statistics/mq/readme @@ -0,0 +1 @@ +接收消息队列 \ No newline at end of file diff --git a/statistics/static/readme b/statistics/static/readme new file mode 100644 index 0000000..b98bf32 --- /dev/null +++ b/statistics/static/readme @@ -0,0 +1 @@ +业务统计 \ No newline at end of file diff --git a/statistics/static/user_login.go b/statistics/static/user_login.go new file mode 100644 index 0000000..d217e2c --- /dev/null +++ b/statistics/static/user_login.go @@ -0,0 +1,371 @@ +package static + +import ( + "context" + "errors" + + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" + "mongo.games.com/goserver/core/logger" + + mymongo "mongo.games.com/goserver/core/mongox" + mymysql "mongo.games.com/goserver/core/mysqlx" + + mongomodel "mongo.games.com/game/statistics/modelmongo" + mysqlmodel "mongo.games.com/game/statistics/modelmysql" +) + +func getAccountTel(platform string, id int) (string, error) { + acc := &mongomodel.Account{} + cc, err := mymongo.GetUserCollection(platform, mongomodel.UserAccount) + if err != nil { + logger.Logger.Errorf("get collection %s error %v", mongomodel.UserAccount, err) + return "", err + } + dd := cc.FindOne(context.TODO(), bson.M{"snid": id}, options.FindOne().SetProjection(bson.M{"tel": 1})) + err = dd.Err() + if err != nil { + if errors.Is(err, mongo.ErrNoDocuments) { + logger.Logger.Tracef("getAccountTel %v not found in user_account", id) + return "", nil + } + logger.Logger.Errorf("getAccountTel %v get user_account err: %v", id, err) + return "", err + } + if err := dd.Decode(acc); err != nil { + logger.Logger.Errorf("getAccountTel %v decode user_account err: %v", id, err) + return "", err + } + return acc.Tel, nil +} + +// 游戏结束离开 +func checkGameOver(db *mymysql.Database, login *mysqlmodel.UserLogin, platform string, id int) (bool, error) { + // 最早的一条掉线记录并且是游戏结束离开 + a := &mongomodel.LoginLog{} + c, err := mymongo.GetLogCollection(platform, mongomodel.LogLogin) + if err != nil { + logger.Logger.Errorf("get collection %s error %v", mongomodel.LogLogin, err) + return false, err + } + d := c.FindOne(context.TODO(), bson.M{"snid": id, "logtype": mongomodel.LogTypeDrop, "gameid": 0, "lastgameid": bson.D{{"$gt", 0}}}, + options.FindOne().SetSort(bson.D{{"time", 1}})) + err = d.Err() + if err != nil { + if errors.Is(err, mongo.ErrNoDocuments) { + logger.Logger.Tracef("checkGameOver %v not found in log_login", id) + return false, nil + } + logger.Logger.Errorf("checkGameOver %v get log_login err: %v", id, err) + return false, err + } + if err := d.Decode(a); err != nil { + logger.Logger.Errorf("checkGameOver %v decode log_login err: %v", id, err) + return false, err + } + + // account tel + tel, err := getAccountTel(platform, id) + if err != nil { + logger.Logger.Warnf("get account tel %v err: %v", id, err) + } + + update := &mysqlmodel.UserLogin{ + //OfflineTs: int(a.Ts), + OfflineTime: a.Time, + OutType: mysqlmodel.OutTypeGameOver, + GameID: a.LastGameID, + Tel: tel, + DeviceName: a.DeviceName, + AppVersion: a.AppVersion, + BuildVersion: a.BuildVersion, + AppChannel: a.AppChannel, + ChannelId: a.ChannelId, + } + + if err := db.Model(login).Select( + "OfflineTime", "OutType", "GameID", "DeviceName", "AppVersion", "BuildVersion", "AppChannel", "Tel", + ).Updates(update).Error; err != nil { + logger.Logger.Errorf("checkLogin %v update user_login err: %v", id, err) + return false, err + } + + return true, nil +} + +// 游戏中离开 +func checkGaming(db *mymysql.Database, login *mysqlmodel.UserLogin, platform string, id int) (bool, error) { + // 最早的一条掉线记录并且是游戏中掉线 + a := &mongomodel.LoginLog{} + c, err := mymongo.GetLogCollection(platform, mongomodel.LogLogin) + if err != nil { + logger.Logger.Errorf("get collection %s error %v", mongomodel.LogLogin, err) + return false, err + } + d := c.FindOne(context.TODO(), bson.M{"snid": id, "logtype": mongomodel.LogTypeDrop, "gameid": bson.D{{"$gt", 0}}}, + options.FindOne().SetSort(bson.D{{"time", 1}})) + err = d.Err() + if err != nil { + if errors.Is(err, mongo.ErrNoDocuments) { + logger.Logger.Tracef("checkGaming %v not found in log_login", id) + return false, nil + } + logger.Logger.Errorf("checkGaming %v get log_login err: %v", id, err) + return false, err + } + if err := d.Decode(a); err != nil { + logger.Logger.Errorf("checkGaming %v decode log_login err: %v", id, err) + return false, err + } + + // account tel + tel, err := getAccountTel(platform, id) + if err != nil { + logger.Logger.Warnf("get account tel %v err: %v", id, err) + } + + update := &mysqlmodel.UserLogin{ + //OfflineTs: int(a.Ts), + OfflineTime: a.Time, + OutType: mysqlmodel.OutTypeGaming, + GameID: a.GameId, + Tel: tel, + DeviceName: a.DeviceName, + AppVersion: a.AppVersion, + BuildVersion: a.BuildVersion, + AppChannel: a.AppChannel, + ChannelId: a.ChannelId, + } + + if err := db.Model(login).Select( + "OfflineTime", "OutType", "GameID", "DeviceName", "AppVersion", "BuildVersion", "AppChannel", "Tel", + ).Updates(update).Error; err != nil { + logger.Logger.Errorf("checkLogin %v update user_login err: %v", id, err) + return false, err + } + + return true, nil +} + +// 登录后离开 +func checkLogin(db *mymysql.Database, login *mysqlmodel.UserLogin, platform string, id int) (bool, error) { + // 最早的一条掉线记录 + a := &mongomodel.LoginLog{} + c, err := mymongo.GetLogCollection(platform, mongomodel.LogLogin) + if err != nil { + logger.Logger.Errorf("get collection %s error %v", mongomodel.LogLogin, err) + return false, err + } + d := c.FindOne(context.TODO(), bson.M{"snid": id, "logtype": mongomodel.LogTypeDrop}, options.FindOne().SetSort(bson.D{{"time", 1}})) + err = d.Err() + if err != nil { + if errors.Is(err, mongo.ErrNoDocuments) { + logger.Logger.Tracef("checkLogin %v not found in log_login", id) + return false, nil + } + logger.Logger.Errorf("checkLogin %v get log_login err: %v", id, err) + return false, err + } + if err := d.Decode(a); err != nil { + logger.Logger.Errorf("checkLogin %v decode log_login err: %v", id, err) + return false, err + } + + // account tel + tel, err := getAccountTel(platform, id) + if err != nil { + logger.Logger.Warnf("get account tel %v err: %v", id, err) + } + + update := &mysqlmodel.UserLogin{ + //OfflineTs: int(a.Ts), + OfflineTime: a.Time, + OutType: mysqlmodel.OutTypeLogin, + Tel: tel, + DeviceName: a.DeviceName, + AppVersion: a.AppVersion, + BuildVersion: a.BuildVersion, + AppChannel: a.AppChannel, + ChannelId: a.ChannelId, + } + + if err := db.Model(login).Select( + "OfflineTime", "OutType", "DeviceName", "AppVersion", "BuildVersion", "AppChannel", "Tel", + ).Updates(update).Error; err != nil { + logger.Logger.Errorf("checkLogin %v update user_login err: %v", id, err) + return false, err + } + + return true, nil +} + +// 注册后离开 +func checkRegister(db *mymysql.Database, login *mysqlmodel.UserLogin, platform string, id int) (bool, error) { + a := &mongomodel.Account{} + c, err := mymongo.GetUserCollection(platform, mongomodel.UserAccount) + if err != nil { + logger.Logger.Errorf("get collection %s error %v", mongomodel.UserAccount, err) + return false, err + } + d := c.FindOne(context.TODO(), bson.M{"snid": id}) + err = d.Err() + if err != nil { + if errors.Is(err, mongo.ErrNoDocuments) { + logger.Logger.Warnf("checkRegister %v not found in user_account", id) + return false, nil + } + logger.Logger.Errorf("checkRegister %v get user_account err: %v", id, err) + return false, err + } + if err := d.Decode(a); err != nil { + logger.Logger.Errorf("checkRegister %v decode user_account err: %v", id, err) + return false, err + } + + // account tel + tel, err := getAccountTel(platform, id) + if err != nil { + logger.Logger.Warnf("get account tel %v err: %v", id, err) + } + + login.Snid = id + //login.OnlineTs = int(a.RegisterTs) + login.OnlineTime = a.RegisteTime + //login.OfflineTs = int(a.RegisterTs) + login.OfflineTime = a.RegisteTime + login.OutType = mysqlmodel.OutTypRegister + login.Tel = tel + login.DeviceName = a.DeviceName + login.AppVersion = a.AppVersion + login.BuildVersion = a.BuildVersion + login.AppChannel = a.AppChannel + login.ChannelId = a.ChannelId + + if err := db.Create(login).Error; err != nil { + logger.Logger.Errorf("checkRegister create err: %v", err) + return false, err + } + return true, nil +} + +// UserLogin 玩家跳出统计 +func UserLogin(platform string, ids []*mysqlmodel.UserID) error { + f := func(id int) error { + // 玩家是否已经统计结束,已经是游戏结束状态 + login := &mysqlmodel.UserLogin{} + db, err := mymysql.GetDatabase(platform) + if err != nil { + logger.Logger.Errorf("UserLogin get db err: %v", err) + return err + } + if err = db.Where("snid = ?", id).Find(login).Error; err != nil { + logger.Logger.Errorf("UserLogin find %v err: %v", id, err) + return err + } + + switch login.OutType { + case mysqlmodel.OutTypeGameOver: + return nil + + case mysqlmodel.OutTypeGaming: + _, err := checkGameOver(db, login, platform, id) + if err != nil { + logger.Logger.Errorf("UserLogin checkGameOver %v err: %v", id, err) + return err + } + return nil + + case mysqlmodel.OutTypeLogin: + ret, err := checkGameOver(db, login, platform, id) + if err != nil { + logger.Logger.Errorf("UserLogin checkGameOver %v err: %v", id, err) + return err + } + if ret { + return nil + } + ret, err = checkGaming(db, login, platform, id) + if err != nil { + logger.Logger.Errorf("UserLogin checkGaming %v err: %v", id, err) + return err + } + if ret { + return nil + } + + case mysqlmodel.OutTypRegister: + ret, err := checkGameOver(db, login, platform, id) + if err != nil { + logger.Logger.Errorf("UserLogin checkGameOver %v err: %v", id, err) + return err + } + if ret { + return nil + } + ret, err = checkGaming(db, login, platform, id) + if err != nil { + logger.Logger.Errorf("UserLogin checkGaming %v err: %v", id, err) + return err + } + if ret { + return nil + } + ret, err = checkLogin(db, login, platform, id) + if err != nil { + logger.Logger.Errorf("UserLogin checkLogin %v err: %v", id, err) + return err + } + if ret { + return nil + } + + default: + ret, err := checkRegister(db, login, platform, id) + if err != nil { + logger.Logger.Errorf("UserLogin checkRegister %v err: %v", id, err) + return err + } + if !ret { + logger.Logger.Warnf("UserLogin not found user_account checkRegister %v err: %v", id, err) + return nil + } + + ret, err = checkGameOver(db, login, platform, id) + if err != nil { + logger.Logger.Errorf("UserLogin checkGameOver %v err: %v", id, err) + return err + } + if ret { + return nil + } + ret, err = checkGaming(db, login, platform, id) + if err != nil { + logger.Logger.Errorf("UserLogin checkGaming %v err: %v", id, err) + return err + } + if ret { + return nil + } + ret, err = checkLogin(db, login, platform, id) + if err != nil { + logger.Logger.Errorf("UserLogin checkLogin %v err: %v", id, err) + return err + } + if ret { + return nil + } + return nil + } + + return nil + } + + for _, v := range ids { + if err := f(v.Snid); err != nil { + return err + } + } + + return nil +} diff --git a/statistics/syn/datasync.go b/statistics/syn/datasync.go new file mode 100644 index 0000000..8f94fc7 --- /dev/null +++ b/statistics/syn/datasync.go @@ -0,0 +1,102 @@ +package syn + +import ( + "context" + "errors" + + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/bson/primitive" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" + "gorm.io/gorm" + "mongo.games.com/goserver/core/logger" + + mysqlmodel "mongo.games.com/game/statistics/modelmysql" + mymongo "mongo.games.com/goserver/core/mongox" + mymysql "mongo.games.com/goserver/core/mysqlx" +) + +// Data 数据同步方法 +// T mongodb数据表结构 +// F mongodb中的每条数据的处理操作,自行实现 +type Data[T any] struct { + Platform string // 平台 + MidType int // 数据类型 例如 modelmysql.MidTypeItem + Database string // 库名称 + CollectionName string // 集合名称 + BatchSize int // 一次读取数量 + // F 自定义数据处理方法 + // data: mongodb中的一条日志 + F func(data *T, db *gorm.DB) (string, error) +} + +// CommonDone 数据获取方式,根据mongodb集合主键按时间顺序批量读取 +func (d *Data[T]) CommonDone() error { + db, err := mymysql.GetDatabase(d.Platform) + if err != nil { + logger.Logger.Errorf("mysql: failed to get database: %v", err) + return err + } + loginMID := &mysqlmodel.LogMid{Tp: d.MidType} + var n int64 + err = db.Model(&mysqlmodel.LogMid{}).Find(loginMID).Count(&n).Error + if err != nil { + logger.Logger.Errorf("mysql: failed to get log_mid: %v", err) + return err + } + if n == 0 { + if err = db.Create(loginMID).Error; err != nil { + logger.Logger.Errorf("mysql: failed to create log_mid: %v", err) + return err + } + } + + logger.Logger.Tracef("start log_mid tp:%v _id:%v", loginMID.Tp, loginMID.MID) + + _id, _ := primitive.ObjectIDFromHex(loginMID.MID) + filter := bson.M{"_id": bson.M{"$gt": _id}} + c, err := mymongo.GetCollection(d.Platform, mymongo.DatabaseType(d.Database), d.CollectionName) + if err != nil { + logger.Logger.Errorf("get collection %s %s error %v", d.Database, d.CollectionName, err) + return err + } + l, err := c.Find(context.TODO(), filter, + options.Find().SetSort(bson.D{primitive.E{Key: "_id", Value: 1}}), options.Find().SetLimit(int64(d.BatchSize))) + if err != nil && !errors.Is(err, mongo.ErrNoDocuments) { + logger.Logger.Errorf("mongo: failed to get %v: %v", d.CollectionName, err) + return err + } + + var logs []*T + if err = l.All(context.TODO(), &logs); err != nil { + l.Close(context.TODO()) + if errors.Is(err, mongo.ErrNoDocuments) { + return nil + } + + logger.Logger.Errorf("mongo: failed to get %v: %v", d.CollectionName, err) + return err + } + l.Close(context.TODO()) + if len(logs) == 0 { + logger.Logger.Infof("sync %v finished", d.CollectionName) + return nil + } + + err = db.Transaction(func(tx *gorm.DB) error { + for _, v := range logs { + loginMID.MID, err = d.F(v, tx) + if err != nil { + logger.Logger.Errorf("Process %v error:%v", d.CollectionName, err) + return err + } + if err = tx.Model(loginMID).Updates(loginMID).Error; err != nil { + logger.Logger.Errorf("mysql: failed to update %v log_mid: %v", d.CollectionName, err) + return err + } + } + return nil + }) + + return err +} diff --git a/statistics/syn/log_invitescore.go b/statistics/syn/log_invitescore.go new file mode 100644 index 0000000..1531469 --- /dev/null +++ b/statistics/syn/log_invitescore.go @@ -0,0 +1,291 @@ +package syn + +import ( + "context" + "errors" + + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/bson/primitive" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" + "gorm.io/gorm" + + "mongo.games.com/game/statistics/constant" + mongomodel "mongo.games.com/game/statistics/modelmongo" + mysqlmodel "mongo.games.com/game/statistics/modelmysql" + "mongo.games.com/goserver/core/logger" + mymongo "mongo.games.com/goserver/core/mongox" + mymysql "mongo.games.com/goserver/core/mysqlx" +) + +func SyncInviteScore(platform string, batchSize int) error { + db, err := mymysql.GetDatabase(platform) + if err != nil { + logger.Logger.Errorf("mysql: SyncInviteScore failed to get database: %v", err) + return err + } + inviteMID := &mysqlmodel.LogInviteScoreMid{ID: 1} + var n int64 + err = db.Model(&mysqlmodel.LogInviteScoreMid{}).Find(inviteMID).Count(&n).Error + if err != nil { + logger.Logger.Errorf("mysql: SyncInviteScore failed to get log_invitescore_mid: %v", err) + return err + } + if n == 0 { + if err = db.Create(inviteMID).Error; err != nil { + logger.Logger.Errorf("mysql: SyncInviteScore failed to create log_invitescore_mid: %v", err) + return err + } + } + + logger.Logger.Tracef("start SyncInviteScore log_invitescore _id:%v", inviteMID.MID) + + _id, _ := primitive.ObjectIDFromHex(inviteMID.MID) + filter := bson.M{"_id": bson.M{"$gt": _id}} + c, err := mymongo.GetLogCollection(platform, mongomodel.LogInviteScore) + if err != nil { + logger.Logger.Errorf("get collection %s error %v", mongomodel.LogInviteScore, err) + return err + } + l, err := c.Find(context.TODO(), filter, + options.Find().SetSort(bson.D{primitive.E{Key: "_id", Value: 1}}), options.Find().SetLimit(int64(batchSize))) + if err != nil && !errors.Is(err, mongo.ErrNoDocuments) { + logger.Logger.Errorf("mongo: SyncInviteScore failed to get log_invitescore: %v", err) + return err + } + + var logs []*mongomodel.InviteScore + if err = l.All(context.TODO(), &logs); err != nil { + l.Close(context.TODO()) + if errors.Is(err, mongo.ErrNoDocuments) { + return err + } + + logger.Logger.Errorf("mongo: SyncInviteScore failed to get log_invitescore: %v", err) + return err + } + l.Close(context.TODO()) + + getPSnId := func(tx *gorm.DB, snid int) (int, error) { + if snid <= 0 { + return 0, nil + } + ret := new(mysqlmodel.LogInviteUser) + if err = tx.First(ret, "snid = ? and level = 1", snid).Error; err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { + logger.Logger.Errorf("mysql: SyncInviteScore failed to getPSnId: %v", err) + return 0, err + } + return ret.Psnid, nil + } + + getDownSnId := func(tx *gorm.DB, snid []int) ([]int, error) { + if len(snid) == 0 { + return nil, nil + } + var ret []int + var us []*mysqlmodel.LogInviteUser + if err = tx.Select("snid").Where("psnid IN ? AND level = 1", snid).Find(&us).Error; err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { + logger.Logger.Errorf("mysql: SyncInviteScore failed to getDownSnId: %v", err) + return ret, err + } + for _, v := range us { + ret = append(ret, v.Snid) + } + return ret, nil + } + + bind := func(tx *gorm.DB, psnid, snid int, ts int) ([]*mysqlmodel.LogInviteUser, error) { + var lu []*mysqlmodel.LogInviteUser + var a1, a2, a3, a4, b1 int + var b2, b3, b4 []int + a4 = psnid + a3, err = getPSnId(tx, a4) + if err != nil { + return nil, err + } + a2, err = getPSnId(tx, a3) + if err != nil { + return nil, err + } + a1, err = getPSnId(tx, a2) + if err != nil { + return nil, err + } + b1 = snid + b2, err = getDownSnId(tx, []int{b1}) + if err != nil { + return nil, err + } + b3, err = getDownSnId(tx, b2) + if err != nil { + return nil, err + } + b4, err = getDownSnId(tx, b3) + if err != nil { + return nil, err + } + logger.Logger.Tracef("a1:%d, a2:%d, a3:%d, a4:%d, b1:%d, b2:%v, b3:%v, b4:%v", a1, a2, a3, a4, b1, b2, b3, b4) + if a1 > 0 { + if b1 > 0 { + lu = append(lu, &mysqlmodel.LogInviteUser{ + Psnid: a1, + Snid: b1, + Level: 4, + Ts: ts, + }) + logger.Logger.Tracef("a1: %v %v %v", b1, 4, ts) + } + } + if a2 > 0 { + if b1 > 0 { + lu = append(lu, &mysqlmodel.LogInviteUser{ + Psnid: a2, + Snid: b1, + Level: 3, + Ts: ts, + }) + logger.Logger.Tracef("a2: %v %v %v", b1, 3, ts) + } + for _, v := range b2 { + if v <= 0 { + continue + } + lu = append(lu, &mysqlmodel.LogInviteUser{ + Psnid: a2, + Snid: v, + Level: 4, + Ts: ts, + }) + logger.Logger.Tracef("a2: %v %v %v", v, 4, ts) + } + } + if a3 > 0 { + if b1 > 0 { + lu = append(lu, &mysqlmodel.LogInviteUser{ + Psnid: a3, + Snid: b1, + Level: 2, + Ts: ts, + }) + logger.Logger.Tracef("a3: %v %v %v", b1, 2, ts) + } + for _, v := range b2 { + if v <= 0 { + continue + } + lu = append(lu, &mysqlmodel.LogInviteUser{ + Psnid: a3, + Snid: v, + Level: 3, + Ts: ts, + }) + logger.Logger.Tracef("a3: %v %v %v", v, 3, ts) + } + for _, v := range b3 { + if v <= 0 { + continue + } + lu = append(lu, &mysqlmodel.LogInviteUser{ + Psnid: a3, + Snid: v, + Level: 4, + Ts: ts, + }) + logger.Logger.Tracef("a3: %v %v %v", v, 4, ts) + } + } + if a4 > 0 { + if b1 > 0 { + lu = append(lu, &mysqlmodel.LogInviteUser{ + Psnid: a4, + Snid: b1, + Level: 1, + Ts: ts, + }) + logger.Logger.Tracef("a4: %v %v %v", b1, 1, ts) + } + for _, v := range b2 { + if v <= 0 { + continue + } + lu = append(lu, &mysqlmodel.LogInviteUser{ + Psnid: a4, + Snid: v, + Level: 2, + Ts: ts, + }) + logger.Logger.Tracef("a4: %v %v %v", v, 2, ts) + } + for _, v := range b3 { + if v <= 0 { + continue + } + lu = append(lu, &mysqlmodel.LogInviteUser{ + Psnid: a4, + Snid: v, + Level: 3, + Ts: ts, + }) + logger.Logger.Tracef("a4: %v %v %v", v, 3, ts) + } + for _, v := range b4 { + if v <= 0 { + continue + } + lu = append(lu, &mysqlmodel.LogInviteUser{ + Psnid: a4, + Snid: v, + Level: 4, + Ts: ts, + }) + logger.Logger.Tracef("a4: %v %v %v", v, 4, ts) + } + } + return lu, nil + } + + for _, v := range logs { + err = db.Transaction(func(tx *gorm.DB) error { + inviteMID.MID = v.Id.Hex() + if err = tx.Model(inviteMID).Updates(inviteMID).Error; err != nil { + logger.Logger.Errorf("mysql: SyncInviteScore failed to update log_invitescore_mid: %v", err) + return err + } + + err = tx.Save(&mysqlmodel.LogInviteScore{ + UpSnid: v.UpSnid, + DownSnid: v.DownSnid, + Level: v.Level, + Tp: v.Tp, + Rate: v.Rate, + Score: v.Score, + Money: v.Money, + Ts: v.Ts, + }).Error + if err != nil { + logger.Logger.Errorf("mysql: SyncInviteScore failed to insert: %v", err) + return err + } + + if v.Tp == constant.InviteScoreTypeBind && v.Level == 0 { + // 绑定关系 + lu, err := bind(tx, v.UpSnid, v.DownSnid, v.Ts) + if err != nil { + logger.Logger.Errorf("mysql: SyncInviteScore failed to bind: %v", err) + return err + } + if err = tx.CreateInBatches(lu, len(lu)).Error; err != nil { + logger.Logger.Errorf("mysql: SyncInviteScore failed to create log_invite_user: %v", err) + return err + } + } + + return nil + }) + if err != nil { + logger.Logger.Errorf("mysql: SyncInviteScore failed to transaction: %v", err) + return err + } + } + return nil +} diff --git a/statistics/syn/log_itemgain.go b/statistics/syn/log_itemgain.go new file mode 100644 index 0000000..4751255 --- /dev/null +++ b/statistics/syn/log_itemgain.go @@ -0,0 +1,61 @@ +package syn + +import ( + "errors" + "time" + + "gorm.io/gorm" + "mongo.games.com/goserver/core/mongox" + + mongomodel "mongo.games.com/game/statistics/modelmongo" + mysqlmodel "mongo.games.com/game/statistics/modelmysql" +) + +func ItemGainDone(data *Data[mongomodel.ItemLog]) error { + data.MidType = mysqlmodel.MidTypeItem + data.Database = string(mongox.DatabaseLog) + data.CollectionName = mongomodel.LogItem + data.F = func(data *mongomodel.ItemLog, db *gorm.DB) (string, error) { + if data == nil || data.LogId.Hex() == "" { + return "", errors.New("null") + } + if data.LogType != 0 || data.Id != "" { + return data.LogId.Hex(), nil + } + + hourTime := time.Unix(data.CreateTs, 0).Local() + hourTs := time.Date(hourTime.Year(), hourTime.Month(), hourTime.Day(), hourTime.Hour(), 0, 0, 0, time.Local).Unix() + + item := &mysqlmodel.ItemGain{} + err := db.Model(item).Where("hour = ? and item_id = ?", hourTs, data.ItemId).First(item).Error + if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { + return "", err + } + item.Hour = hourTs + item.ItemId = data.ItemId + item.ItemNum += data.Count + if item.ID == 0 { + err = db.Create(item).Error + } else { + err = db.Model(item).Updates(item).Error + } + if err != nil { + return "", err + } + + itemTotal := &mysqlmodel.ItemTotalGain{} + err = db.Model(itemTotal).Where("item_id = ?", data.ItemId).First(itemTotal).Error + if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { + return "", err + } + itemTotal.ItemId = data.ItemId + itemTotal.ItemNum += data.Count + if itemTotal.ID == 0 { + err = db.Create(itemTotal).Error + } else { + err = db.Model(itemTotal).Updates(itemTotal).Error + } + return data.LogId.Hex(), err + } + return data.CommonDone() +} diff --git a/statistics/syn/log_login.go b/statistics/syn/log_login.go new file mode 100644 index 0000000..7f338e1 --- /dev/null +++ b/statistics/syn/log_login.go @@ -0,0 +1,181 @@ +package syn + +import ( + "context" + "errors" + + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/bson/primitive" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" + "gorm.io/gorm" + + mongomodel "mongo.games.com/game/statistics/modelmongo" + mysqlmodel "mongo.games.com/game/statistics/modelmysql" + "mongo.games.com/goserver/core/logger" + mymongo "mongo.games.com/goserver/core/mongox" + mymysql "mongo.games.com/goserver/core/mysqlx" +) + +/* + 登录日志同步使用了mongo的_id,从小到大每次同步n个 +*/ + +// LogLogin 同步登录日志 +func LogLogin(platform string, batchSize int) ([]*mysqlmodel.LogLogin, error) { + db, err := mymysql.GetDatabase(platform) + if err != nil { + logger.Logger.Errorf("mysql: SyncLogLogin failed to get database: %v", err) + return nil, err + } + loginMID := &mysqlmodel.LogLoginMid{ID: 1} + var n int64 + err = db.Model(&mysqlmodel.LogLoginMid{}).Find(loginMID).Count(&n).Error + if err != nil { + logger.Logger.Errorf("mysql: SyncLogLogin failed to get log_login_mid: %v", err) + return nil, err + } + if n == 0 { + if err = db.Create(loginMID).Error; err != nil { + logger.Logger.Errorf("mysql: SyncLogLogin failed to create log_login_mid: %v", err) + return nil, err + } + } + + logger.Logger.Tracef("start SyncLogLogin log_login _id:%v", loginMID.MID) + + _id, _ := primitive.ObjectIDFromHex(loginMID.MID) + filter := bson.M{"_id": bson.M{"$gt": _id}} + c, err := mymongo.GetLogCollection(platform, mongomodel.LogLogin) + if err != nil { + logger.Logger.Errorf("get collection %s error %v", mongomodel.LogLogin, err) + return nil, err + } + l, err := c.Find(context.TODO(), filter, + options.Find().SetSort(bson.D{primitive.E{Key: "_id", Value: 1}}), options.Find().SetLimit(int64(batchSize))) + if err != nil && !errors.Is(err, mongo.ErrNoDocuments) { + logger.Logger.Errorf("mongo: SyncLogLogin failed to get log_login: %v", err) + return nil, err + } + + var logs []*mongomodel.LoginLog + if err = l.All(context.TODO(), &logs); err != nil { + l.Close(context.TODO()) + if errors.Is(err, mongo.ErrNoDocuments) { + return nil, nil + } + + logger.Logger.Errorf("mongo: SyncLogLogin failed to get loginlog: %v", err) + return nil, err + } + l.Close(context.TODO()) + + var ls []*mysqlmodel.LogLogin + for _, v := range logs { + logger.Logger.Tracef("mongo SyncLogLogin log_login: %+v", *v) + var e *mysqlmodel.LogLogin + switch v.LogType { + case mongomodel.LogTypeLogin, mongomodel.LogTypeRehold: + onlineType := mysqlmodel.LogTypeLogin + if v.LogType == mongomodel.LogTypeRehold { + onlineType = mysqlmodel.LogTypeRehold + } + + // 创建数据 + var n int64 + if err = db.Model(&mysqlmodel.LogLogin{}).Where("snid = ? AND online_type = ? AND online_time = ?", + v.SnId, onlineType, v.Time).Count(&n).Error; err != nil { + logger.Logger.Errorf("mysql: SyncLogLogin failed to get log_login count: %v", err) + return ls, err + } + + if n == 0 { + e = &mysqlmodel.LogLogin{ + Snid: int(v.SnId), + OnlineType: onlineType, + //OnlineTs: int(v.Ts), + OnlineTime: v.Time, + OfflineType: 0, + //OfflineTs: 0, + OfflineTime: v.Time, + DeviceName: v.DeviceName, + AppVersion: v.AppVersion, + BuildVersion: v.BuildVersion, + AppChannel: v.AppChannel, + ChannelId: v.ChannelId, + } + if err = db.Create(e).Error; err != nil { + logger.Logger.Errorf("mysql: SyncLogLogin failed to create log_login: %v", err) + return ls, err + } + } else { + continue + } + + case mongomodel.LogTypeLogout, mongomodel.LogTypeDrop: + // 修改数据 + e = &mysqlmodel.LogLogin{} + err = db.Model(&mysqlmodel.LogLogin{}).Where("snid = ?", v.SnId).Order("online_time DESC").First(e).Error + if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { + logger.Logger.Errorf("mysql: SyncLogLogin failed to find log_login: %v", err) + return ls, err + } + + if errors.Is(err, gorm.ErrRecordNotFound) { + logger.Logger.Warnf("mysql: SyncLogLogin not found log_login: %v", v) + continue + } + + if e.OfflineType != 0 { + logger.Logger.Tracef("mysql: SyncLogLogin already offline: %+v", *e) + continue + } + + e.OfflineType = mysqlmodel.LogTypeOffline + //e.OfflineTs = int(v.Ts) + e.OfflineTime = v.Time + if err = db.Model(e).Select("OfflineType", "OfflineTime").Updates(e).Error; err != nil { + logger.Logger.Errorf("mysql: SyncLogLogin failed to update log_login: %v", err) + return ls, err + } + default: + continue + } + + if e != nil { + ls = append(ls, e) + } + } + + if len(logs) > 0 { + err = db.Transaction(func(tx *gorm.DB) error { + loginMID.MID = logs[len(logs)-1].LogId.Hex() + if err = tx.Model(loginMID).Updates(loginMID).Error; err != nil { + logger.Logger.Errorf("mysql: SyncLogLogin failed to update log_login_mid: %v", err) + return err + } + + for _, v := range ls { + if err = tx.First(&mysqlmodel.UserID{}, "snid = ?", v.Snid).Error; err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { + logger.Logger.Errorf("mysql: SyncLogLogin failed to find user_id: %v", err) + return err + } + + if errors.Is(err, gorm.ErrRecordNotFound) { + if err = tx.Create(&mysqlmodel.UserID{Snid: v.Snid}).Error; err != nil { + logger.Logger.Errorf("mysql: SyncLogLogin failed to create user_id: %v", err) + return err + } + } + } + + return nil + }) + if err != nil { + logger.Logger.Errorf("mysql: SyncLogLogin failed to transaction: %v", err) + return nil, err + } + } + + return ls, nil +} diff --git a/statistics/syn/readme b/statistics/syn/readme new file mode 100644 index 0000000..37acc1c --- /dev/null +++ b/statistics/syn/readme @@ -0,0 +1 @@ +游戏服mongodb同步到mysql \ No newline at end of file diff --git a/statistics/syn/user_account.go b/statistics/syn/user_account.go new file mode 100644 index 0000000..72b1c52 --- /dev/null +++ b/statistics/syn/user_account.go @@ -0,0 +1,105 @@ +package syn + +import ( + "context" + "errors" + + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/bson/primitive" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" + "gorm.io/gorm" + + mongomodel "mongo.games.com/game/statistics/modelmongo" + mysqlmodel "mongo.games.com/game/statistics/modelmysql" + "mongo.games.com/goserver/core/logger" + mymongo "mongo.games.com/goserver/core/mongox" + mymysql "mongo.games.com/goserver/core/mysqlx" +) + +/* + 注册信息同步,使用mongo的_id,从小到大每次同步n个 +*/ + +// UserAccount 同步注册表 +func UserAccount(platform string, batchSize int) ([]*mysqlmodel.UserAccount, error) { + db, err := mymysql.GetDatabase(platform) + if err != nil { + logger.Logger.Errorf("mysql: UserAccount failed to get database: %v", err) + return nil, err + } + account := &mysqlmodel.UserAccount{} + err = db.Model(&mysqlmodel.UserAccount{}).Last(account).Error + if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { + logger.Logger.Errorf("mysql: UserAccount failed to get account: %v", err) + return nil, err + } + + logger.Logger.Tracef("start UserAccount account _id:%v", account.MID) + + _id, _ := primitive.ObjectIDFromHex(account.MID) + filter := bson.M{"_id": bson.M{"$gt": _id}} + c, err := mymongo.GetUserCollection(platform, mongomodel.UserAccount) + if err != nil { + logger.Logger.Errorf("get collection %s error %v", mongomodel.UserAccount, err) + return nil, err + } + l, err := c.Find(context.TODO(), filter, + options.Find().SetSort(bson.D{primitive.E{Key: "_id", Value: 1}}), options.Find().SetLimit(int64(batchSize))) + if err != nil && !errors.Is(err, mongo.ErrNoDocuments) { + logger.Logger.Errorf("mongo: UserAccount failed to get account: %v", err) + return nil, err + } + + var accounts []*mongomodel.Account + if err = l.All(context.TODO(), &accounts); err != nil { + l.Close(context.TODO()) + if errors.Is(err, mongo.ErrNoDocuments) { + return nil, nil + } + + logger.Logger.Errorf("mongo: UserAccount failed to get account: %v", err) + return nil, err + } + l.Close(context.TODO()) + + var as []*mysqlmodel.UserAccount + err = db.Transaction(func(tx *gorm.DB) error { + for _, v := range accounts { + logger.Logger.Tracef("mongo account: %+v", *v) + a := &mysqlmodel.UserAccount{ + MID: v.AccountId.Hex(), + Snid: int(v.SnId), + //RegisterTs: int(v.RegisterTs), + RegisterTime: v.RegisteTime, + Tel: v.Tel, + ChannelId: v.ChannelId, + } + + if err = tx.Create(a).Error; err != nil { + logger.Logger.Errorf("mysql: UserAccount failed to create account: %v", err) + return err + } + + if err = tx.First(&mysqlmodel.UserID{}, "snid = ?", v.SnId).Error; err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { + logger.Logger.Errorf("mysql: UserAccount failed to find user_id: %v", err) + return err + } + + if errors.Is(err, gorm.ErrRecordNotFound) { + if err = tx.Create(&mysqlmodel.UserID{Snid: int(v.SnId)}).Error; err != nil { + logger.Logger.Errorf("mysql: UserAccount failed to create user_id: %v", err) + return err + } + } + + as = append(as, a) + } + return nil + }) + if err != nil { + logger.Logger.Errorf("mysql: UserAccount failed to transaction: %v", err) + return as, err + } + return as, nil +} diff --git a/statistics/task/build_linux.bat b/statistics/task/build_linux.bat new file mode 100644 index 0000000..0cc7a25 --- /dev/null +++ b/statistics/task/build_linux.bat @@ -0,0 +1,5 @@ +set CGO_ENABLED=0 +set GOOS=linux +set GOARCH=amd64 +go build -o ./task2 +pause \ No newline at end of file diff --git a/statistics/task/etc/DB_GameFree.dat b/statistics/task/etc/DB_GameFree.dat new file mode 100644 index 0000000000000000000000000000000000000000..9ed570013bf427b6cf7d22d1081b9237d012c275 GIT binary patch literal 24144 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 0 { + e.List[id].SetHead(head) + } + + return e.List[id] +} + +func (e *ExcelMgr) Get(id int) *ExcelData { + return e.List[id] +} + +func (e *ExcelMgr) Save(id int, fileName string) error { + d := e.List[id] + if d == nil { + return nil + } + return d.SaveAs(fileName) +} diff --git a/statistics/task/gamefree/db_gamefree.go b/statistics/task/gamefree/db_gamefree.go new file mode 100644 index 0000000..81d8b55 --- /dev/null +++ b/statistics/task/gamefree/db_gamefree.go @@ -0,0 +1,77 @@ +package gamefree + +import ( + "google.golang.org/protobuf/proto" + "mongo.games.com/game/protocol/server" + "os" +) + +func init() { + buf, err := os.ReadFile("./etc/DB_GameFree.dat") + if err != nil { + panic(err) + } + err = PBDB_GameFreeMgr.unmarshal(buf) + if err != nil { + panic(err) + } +} + +var PBDB_GameFreeMgr = &DB_GameFreeMgr{ + Datas: &server.DB_GameFreeArray{}, + pool: make(map[int32]*server.DB_GameFree), +} + +type DB_GameFreeMgr struct { + Datas *server.DB_GameFreeArray + pool map[int32]*server.DB_GameFree +} + +func (this *DB_GameFreeMgr) unmarshal(data []byte) error { + err := proto.Unmarshal(data, this.Datas) + if err == nil { + this.arrangeData() + } + return err +} + +func (this *DB_GameFreeMgr) reunmarshal(data []byte) error { + newDatas := &server.DB_GameFreeArray{} + err := proto.Unmarshal(data, newDatas) + if err == nil { + for _, item := range newDatas.Arr { + existItem := this.GetData(item.GetId()) + if existItem == nil { + this.pool[item.GetId()] = item + this.Datas.Arr = append(this.Datas.Arr, item) + + } else { + *existItem = *item + } + } + } + return err +} + +func (this *DB_GameFreeMgr) arrangeData() { + if this.Datas == nil { + return + } + + dataArr := this.Datas.GetArr() + if dataArr == nil { + return + } + + for _, data := range dataArr { + this.pool[data.GetId()] = data + + } +} + +func (this *DB_GameFreeMgr) GetData(id int32) *server.DB_GameFree { + if data, ok := this.pool[id]; ok { + return data + } + return nil +} diff --git a/statistics/task/logger.xml b/statistics/task/logger.xml new file mode 100644 index 0000000..f6eb37b --- /dev/null +++ b/statistics/task/logger.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/statistics/task/main.go b/statistics/task/main.go new file mode 100644 index 0000000..a582273 --- /dev/null +++ b/statistics/task/main.go @@ -0,0 +1,427 @@ +package main + +import ( + "fmt" + "sort" + "time" + + "github.com/spf13/viper" + "mongo.games.com/goserver/core/logger" + "mongo.games.com/goserver/core/mongox" + "mongo.games.com/goserver/core/mysqlx" + "mongo.games.com/goserver/core/viperx" + + "mongo.games.com/game/statistics/task/gamefree" + "mongo.games.com/game/statistics/task/task" +) + +const ( + ExcelTypeNewPlayerBankrupt = iota // 新用户游戏破产率 + ExcelTypeGameTimeAvg // 新用户平均游戏时长 + ExcelTypeGameCountAvg // 新用户平均局数 + ExcelTypeGameRate // 平均倍数 + ExcelTypeActiveRate // 活跃破产率 + ExcelTypeCtrlWinRate // 控输赢胜率 + ExcelTypeRobotWinRate // 机器人胜率 + ExcelTypeCoinAvg // 人均获得金币 + ExcelTypeBankruptOffline // 破产后离线 + ExcelTypeOfflineCoin // 充值当天最后金币 +) + +var VP *viper.Viper + +func main() { + defer func() { + logger.Logger.Flush() + logger.Logger.Close() + }() + VP = viperx.GetViper("config", "yaml") + // mongo + vp := viperx.GetViper("mongo", "yaml") + // mongo初始化 + conf := &mongox.Config{} + err := vp.Unmarshal(conf) + if err != nil { + panic(fmt.Errorf("mongo config error: %v", err)) + } + mongox.Init(conf) + defer mongox.Close() + + // mysql + vp = viperx.GetViper("mysql", "yaml") + myConf := &mysqlx.Config{} + err = vp.Unmarshal(myConf) + if err != nil { + panic(fmt.Errorf("mysql config error: %v", err)) + } + mysqlx.Init(myConf) + defer mysqlx.Close() + + startTime, err := time.Parse(time.RFC3339, VP.GetString("StartTime")) + if err != nil { + panic(fmt.Sprintf("time.Parse err: %v", err)) + return + } + endTime, err := time.Parse(time.RFC3339, VP.GetString("EndTime")) + if err != nil { + panic(fmt.Sprintf("time.Parse err: %v", err)) + return + } + + mgr := NewExcelMgr() + mgr.Register(ExcelTypeNewPlayerBankrupt, []string{"日期", "场次id", "破产人数", "参与人数", "破产率"}) + mgr.Register(ExcelTypeGameTimeAvg, []string{"日期", "场次id", "参与人数", "平均游戏时长"}) + mgr.Register(ExcelTypeGameCountAvg, []string{"日期", "场次id", "参与人数", "平均局数"}) + mgr.Register(ExcelTypeGameRate, []string{"日期", "场次id", "总局数", "平均倍数", "有炸弹分局数", "炸弹分平均倍数", "2留在手里的局数"}) + mgr.Register(ExcelTypeActiveRate, []string{"日期", "场次id", "破产人数", "参与人数", "破产率"}) + mgr.Register(ExcelTypeCtrlWinRate, []string{"日期", "场次id", "总局数", "平均倍数", "有炸弹分局数", "炸弹分平均倍数", "2留在手里的局数"}) + mgr.Register(ExcelTypeCtrlWinRate*10, []string{"日期", "场次id", "总局数", "平均倍数", "有炸弹分局数", "炸弹分平均倍数", "2留在手里的局数"}) + mgr.Register(ExcelTypeRobotWinRate, []string{"日期", "场次id", "总局数", "平均倍数", "有炸弹分局数", "炸弹分平均倍数", "2留在手里的局数"}) + mgr.Register(ExcelTypeCoinAvg, []string{"日期", "场次id", "参与人数", "人均获得金币"}) + mgr.Register(ExcelTypeBankruptOffline, []string{"日期", "场次id", "破产人数", "参与人数", "破产率"}) + mgr.Register(ExcelTypeOfflineCoin, []string{"日期", "场次id", "破产人数", "参与人数", "破产率"}) + switchArr := VP.GetIntSlice("Switch") + + for { + if startTime.Unix() >= endTime.Unix() { + break + } + startTimeStr := startTime.Format(time.RFC3339) + et := startTime.AddDate(0, 0, 1) + endTimeStr := et.Format(time.RFC3339) + logger.Logger.Infof("startTime: %v endTime: %v", startTimeStr, endTimeStr) + + if switchArr[ExcelTypeNewPlayerBankrupt] == 1 { + // 新用户游戏破产率 + mgr.GenNewPlayerBankruptRateExcel("1", startTimeStr, endTimeStr) + } + if switchArr[ExcelTypeGameTimeAvg] == 1 { + // 新用户平均游戏时长 + mgr.GenNewPlayerGameTimeAvgExcel("1", startTimeStr, endTimeStr) + } + if switchArr[ExcelTypeGameCountAvg] == 1 { + // 新用户平均局数 + mgr.GenGameCountExcel("1", startTimeStr, endTimeStr) + } + if switchArr[ExcelTypeGameRate] == 1 { + // 平均倍数 + mgr.GenGameRateExcel("1", startTimeStr, endTimeStr) + } + if switchArr[ExcelTypeActiveRate] == 1 { + // 活跃破产率 + mgr.GenActiveBankruptRateExcel("1", startTimeStr, endTimeStr) + } + if switchArr[ExcelTypeCtrlWinRate] == 1 { + // 控赢胜率 + mgr.GenCtrlWinRateExcel("1", startTimeStr, endTimeStr) + } + if switchArr[ExcelTypeRobotWinRate] == 1 { + // 机器人胜率 + mgr.GenRobotWinRateExcel("1", startTimeStr, endTimeStr) + } + if switchArr[ExcelTypeCoinAvg] == 1 { + // 人均获得金币 + mgr.GenCoinAvgExcel("1", startTimeStr, endTimeStr) + } + if switchArr[ExcelTypeBankruptOffline] == 1 { + // 破产后离线 + mgr.GenBankruptOfflineExcel("1", startTimeStr, endTimeStr) + } + if switchArr[ExcelTypeOfflineCoin] == 1 { + // 离线金币 + mgr.GenOfflineCoinExcel("1", startTimeStr, endTimeStr) + } + + startTime = et + } + + mgr.SaveAll(VP.GetString("StartTime")[:10], endTime.AddDate(0, 0, -1).Format(time.DateOnly)) +} + +func (e *ExcelMgr) SaveAll(startTime, endTime string) { + switchArr := VP.GetIntSlice("Switch") + if switchArr[ExcelTypeNewPlayerBankrupt] == 1 { + e.Save(ExcelTypeNewPlayerBankrupt, fmt.Sprintf("新用户破产率_%s_%s.xlsx", startTime, endTime)) + } + if switchArr[ExcelTypeGameTimeAvg] == 1 { + e.Save(ExcelTypeGameTimeAvg, fmt.Sprintf("新用户平局游戏时长_%s_%s.xlsx", startTime, endTime)) + } + if switchArr[ExcelTypeGameCountAvg] == 1 { + e.Save(ExcelTypeGameCountAvg, fmt.Sprintf("新用户平均局数_%s_%s.xlsx", startTime, endTime)) + } + if switchArr[ExcelTypeGameRate] == 1 { + e.Save(ExcelTypeGameRate, fmt.Sprintf("平均倍数_%s_%s.xlsx", startTime, endTime)) + } + if switchArr[ExcelTypeActiveRate] == 1 { + e.Save(ExcelTypeActiveRate, fmt.Sprintf("活跃破产率_%s_%s.xlsx", startTime, endTime)) + } + if switchArr[ExcelTypeCtrlWinRate] == 1 { + e.Save(ExcelTypeCtrlWinRate, fmt.Sprintf("控赢胜率_%s_%s.xlsx", startTime, endTime)) + e.Save(ExcelTypeCtrlWinRate*10, fmt.Sprintf("控输胜率_%s_%s.xlsx", startTime, endTime)) + } + if switchArr[ExcelTypeRobotWinRate] == 1 { + e.Save(ExcelTypeRobotWinRate, fmt.Sprintf("机器人输率_%s_%s.xlsx", startTime, endTime)) + } + if switchArr[ExcelTypeCoinAvg] == 1 { + e.Save(ExcelTypeCoinAvg, fmt.Sprintf("人均获得金币_%s_%s.xlsx", startTime, endTime)) + } + if switchArr[ExcelTypeBankruptOffline] == 1 { + e.Save(ExcelTypeBankruptOffline, fmt.Sprintf("破产后离线_%s_%s.xlsx", startTime, endTime)) + } + if switchArr[ExcelTypeOfflineCoin] == 1 { + e.Save(ExcelTypeOfflineCoin, fmt.Sprintf("离线金币_%s_%s.xlsx", startTime, endTime)) + } +} + +func GetGameFreeName(id int) string { + d := gamefree.PBDB_GameFreeMgr.GetData(int32(id)) + return fmt.Sprintf("%s_%s", d.Name, d.Title) +} + +func (e *ExcelMgr) GenNewPlayerBankruptRateExcel(plt string, startTime, endTime string) { + for _, v := range VP.GetIntSlice("Gamefreeids") { + _, a, b, err := task.NewPlayerBankruptRate(plt, startTime, endTime, v) + if err != nil { + logger.Logger.Errorf("NewPlayerBankruptRate get StartTime:%v EndTime:%v GameFreeId:%v err: %v", startTime, endTime, v, err) + continue + } + ex := e.Get(ExcelTypeNewPlayerBankrupt) + ex.NewLine() + ex.SetCell(startTime[:10]) + ex.SetCell(GetGameFreeName(v)) + ex.SetCell(a) + ex.SetCell(b) + if b > 0 { + ex.SetCell(float64(a) / float64(b)) + } else { + ex.SetCell(0) + } + logger.Logger.Tracef("NewPlayerBankruptRate GameFreeId: %v rate: %v", v, float64(a)/float64(b)) + } +} + +func (e *ExcelMgr) GenNewPlayerGameTimeAvgExcel(plt string, startTime, endTime string) { + for _, v := range VP.GetIntSlice("Gamefreeids") { + a, b, err := task.NewPlayerGameTimeAvg(plt, startTime, endTime, v) + if err != nil { + logger.Logger.Errorf("NewPlayerGameTimeAvg get StartTime:%v EndTime:%v GameFreeId:%v err: %v", startTime, endTime, v, err) + continue + } + ex := e.Get(ExcelTypeGameTimeAvg) + ex.NewLine() + ex.SetCell(startTime[:10]) + ex.SetCell(GetGameFreeName(v)) + ex.SetCell(a) + if a > 0 { + avg := float64(b) / float64(a) + show := fmt.Sprintf("%v", time.Second*time.Duration(avg)) + ex.SetCell(show) + } else { + ex.SetCell(0) + } + logger.Logger.Tracef("NewPlayerGameTimeAvg GameFreeId: %v avg: %v", v, float64(b)/float64(a)) + } +} + +func (e *ExcelMgr) GenGameCountExcel(plt string, startTime, endTime string) { + for _, v := range VP.GetIntSlice("Gamefreeids") { + a, b, err := task.NewPlayerGameCountAvg(plt, startTime, endTime, v) + if err != nil { + logger.Logger.Errorf("NewPlayerGameCountAvg get StartTime:%v EndTime:%v GameFreeId:%v err: %v", startTime, endTime, v, err) + continue + } + ex := e.Get(ExcelTypeGameCountAvg) + ex.NewLine() + ex.SetCell(startTime[:10]) + ex.SetCell(GetGameFreeName(v)) + ex.SetCell(a) + if a > 0 { + ex.SetCell(float64(b) / float64(a)) + } else { + ex.SetCell(0) + } + logger.Logger.Tracef("NewPlayerGameCountAvg GameFreeId: %v avg: %v", v, float64(b)/float64(a)) + } +} + +func (e *ExcelMgr) GenGameRateExcel(plt string, startTime, endTime string) { + for _, v := range VP.GetIntSlice("Gamefreeids") { + total, bombTotal, remain2Total, rateAvg, bombRateAvg, err := task.PlayerGameRate(plt, startTime, endTime, v) + if err != nil { + logger.Logger.Errorf("PlayerGameRate get StartTime:%v EndTime:%v GameFreeId:%v err: %v", startTime, endTime, v, err) + continue + } + ex := e.Get(ExcelTypeGameRate) + ex.NewLine() + ex.SetCell(startTime[:10]) + ex.SetCell(GetGameFreeName(v)) + ex.SetCell(total) + ex.SetCell(rateAvg) + ex.SetCell(bombTotal) + ex.SetCell(bombRateAvg) + ex.SetCell(remain2Total) + logger.Logger.Tracef("PlayerGameRate GameFreeId: %v total: %v rateAvg: %v bombTotal: %v bombRateAvg: %v remain2Total: %v", + v, total, rateAvg, bombTotal, bombRateAvg, remain2Total) + } +} + +func (e *ExcelMgr) GenActiveBankruptRateExcel(plt string, startTime, endTime string) { + for _, v := range VP.GetIntSlice("Gamefreeids") { + b, t, err := task.ActivePlayerBankruptRate(plt, startTime, endTime, v) + if err != nil { + logger.Logger.Errorf("ActivePlayerBankruptRate get StartTime:%v EndTime:%v GameFreeId:%v err: %v", startTime, endTime, v, err) + continue + } + + ex := e.Get(ExcelTypeActiveRate) + ex.NewLine() + ex.SetCell(startTime[:10]) + ex.SetCell(GetGameFreeName(v)) + ex.SetCell(b) + ex.SetCell(t) + if t > 0 { + if b > t { + b = t + } + ex.SetCell(float64(b) / float64(t)) + } else { + ex.SetCell(0) + } + logger.Logger.Tracef("ActivePlayerBankruptRate GameFreeId: %v rate: %v", v, float64(b)/float64(t)) + } +} + +func (e *ExcelMgr) GenCtrlWinRateExcel(plt string, startTime, endTime string) { + for _, v := range append(VP.GetIntSlice("Tienlen")) { + ret, err := task.GameDetailWinRate(plt, startTime, endTime, v) + if err != nil { + logger.Logger.Errorf("GameDetailWinRate get StartTime:%v EndTime:%v GameFreeId:%v err: %v", startTime, endTime, v, err) + continue + } + if len(ret) > 0 { + ex := e.Get(ExcelTypeCtrlWinRate) + ex.NewLine() + ex.SetCell(startTime[:10]) + ex.SetCell(GetGameFreeName(v)) + ex.SetCell(ret[0].First) + ex.SetCell(ret[0].Second) + ex.SetCell(ret[0].Third) + ex.SetCell(ret[0].Total) + if ret[0].Total > 0 { + ex.SetCell(float64(ret[0].First+ret[0].Second) / float64(ret[0].Total)) + } else { + ex.SetCell(0) + } + logger.Logger.Tracef("GameDetailWinRate GameFreeId:%v %+v", v, ret[0]) + } + if len(ret) > 1 { + ex := e.Get(ExcelTypeCtrlWinRate * 10) + ex.NewLine() + ex.SetCell(startTime[:10]) + ex.SetCell(GetGameFreeName(v)) + ex.SetCell(ret[1].First) + ex.SetCell(ret[1].Second) + ex.SetCell(ret[1].Third) + ex.SetCell(ret[1].Total) + if ret[1].Total > 0 { + ex.SetCell(float64(ret[1].First+ret[1].Second) / float64(ret[1].Total)) + } else { + ex.SetCell(0) + } + logger.Logger.Tracef("GameDetailWinRate GameFreeId:%v %+v", v, ret[1]) + } + } +} + +func (e *ExcelMgr) GenRobotWinRateExcel(plt string, startTime, endTime string) { + for _, v := range append(VP.GetIntSlice("Tienlen"), VP.GetIntSlice("Thirteen")...) { + a, b, err := task.RobotWinRate(plt, startTime, endTime, v) + if err != nil { + logger.Logger.Errorf("RobotWinRate get StartTime:%v EndTime:%v GameFreeId:%v err: %v", startTime, endTime, v, err) + continue + } + + ex := e.Get(ExcelTypeRobotWinRate) + ex.NewLine() + ex.SetCell(startTime[:10]) + ex.SetCell(GetGameFreeName(v)) + ex.SetCell(a) + ex.SetCell(b) + if b > 0 { + ex.SetCell(float64(b-a) / float64(b)) + } else { + ex.SetCell(0) + } + logger.Logger.Tracef("RobotWinRate GameFreeId: %v rate: %v", v, float64(a)/float64(b)) + } +} + +func (e *ExcelMgr) GenCoinAvgExcel(plt string, startTime, endTime string) { + type KV struct { + K int + V string + } + + var list []KV + for k, v := range task.CoinName { + list = append(list, KV{K: k, V: v}) + } + + sort.Slice(list, func(i, j int) bool { + return list[i].K < list[j].K + }) + + for _, item := range list { + k, v := item.K, item.V + a, b, err := task.CoinAvg(plt, startTime, endTime, k) + if err != nil { + logger.Logger.Errorf("CoinAvg get StartTime:%v EndTime:%v tp:%v err: %v", startTime, endTime, k, err) + continue + } + ex := e.Get(ExcelTypeCoinAvg) + ex.NewLine() + ex.SetCell(startTime[:10]) + ex.SetCell(v) + ex.SetCell(a) + ex.SetCell(b) + if a > 0 { + ex.SetCell(float64(b) / float64(a)) + } else { + ex.SetCell(0) + } + logger.Logger.Tracef("CoinAvg tp: %v rate: %v", k, float64(b)/float64(a)) + } +} + +func (e *ExcelMgr) GenBankruptOfflineExcel(plt string, startTime, endTime string) { + res, err := task.BankruptOffline(plt, startTime, endTime) + if err != nil { + logger.Logger.Errorf("BankruptOffline get StartTime:%v EndTime:%v err: %v", startTime, endTime, err) + return + } + ex := e.Get(ExcelTypeBankruptOffline) + ex.NewLine() + ex.SetCell(startTime[:10]) + ex.SetCell(res.One) + ex.SetCell(res.Two) + ex.SetCell(res.Three) + ex.SetCell(res.Recharge) + ex.SetCell(fmt.Sprintf("%v", res.D)) + logger.Logger.Tracef("BankruptOffline %+v", res) +} + +func (e *ExcelMgr) GenOfflineCoinExcel(plt string, startTime, endTime string) { + res, err := task.OfflineCoin(plt, startTime, endTime) + if err != nil { + logger.Logger.Errorf("OfflineCoin get StartTime:%v EndTime:%v err: %v", startTime, endTime, err) + return + } + for _, v := range res { + ex := e.Get(ExcelTypeOfflineCoin) + ex.NewLine() + ex.SetCell(startTime[:10]) + ex.SetCell(v.Snid) + ex.SetCell(v.Coin) + } + logger.Logger.Tracef("OfflineCoin %+v", res) +} diff --git a/statistics/task/readme b/statistics/task/readme new file mode 100644 index 0000000..5fdb673 --- /dev/null +++ b/statistics/task/readme @@ -0,0 +1 @@ +查询历史数据 \ No newline at end of file diff --git a/statistics/task/task/bankruptcy.go b/statistics/task/task/bankruptcy.go new file mode 100644 index 0000000..ea4212d --- /dev/null +++ b/statistics/task/task/bankruptcy.go @@ -0,0 +1,189 @@ +package task + +import ( + "context" + "errors" + "fmt" + + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" + "mongo.games.com/goserver/core/logger" + mymongo "mongo.games.com/goserver/core/mongox" + mymysql "mongo.games.com/goserver/core/mysqlx" + + "mongo.games.com/game/common" + mongomodel "mongo.games.com/game/statistics/modelmongo" +) + +// 新用户id +func GetNewPayerIds(plt string, startTime, endTime string) ([]int, error) { + s, e := common.StrRFC3339TimeToTime(startTime), common.StrRFC3339TimeToTime(endTime) + c, err := mymongo.GetUserCollection(plt, mongomodel.UserAccount) + if err != nil { + return nil, err + } + + var res []struct{ Snid int } + dd, err := c.Find(context.TODO(), bson.M{"registetime": bson.M{"$gte": s, "$lt": e}}, options.Find().SetProjection(bson.M{"snid": 1})) + if err != nil { + if errors.Is(err, mongo.ErrNoDocuments) { + return nil, nil + } + logger.Logger.Errorf("find new player snid get err: %v", err) + return nil, err + } + if err := dd.All(context.TODO(), &res); err != nil { + logger.Logger.Errorf("find new player snid decode err: %v", err) + return nil, err + } + var ret []int + for _, v := range res { + ret = append(ret, v.Snid) + } + logger.Logger.Tracef("find new player snid: %v", ret) + return ret, nil +} + +// 场次破产总人数 +func GameFreeIdBankruptPlayerCount(plt string, ids []int, startTime, endTime string, gamefreeid int) (int, error) { + s, e := common.StrRFC3339TimeToTime(startTime), common.StrRFC3339TimeToTime(endTime) + db, err := mymysql.GetDatabase("count") + if err != nil { + return 0, err + } + var ret int + for _, v := range ids { + var n int64 + if err = db.Table("bankrupt_log").Where("snid = ? AND bankrupt_time >= ? AND bankrupt_time < ? AND game_free_id = ?", + v, s.Unix(), e.Unix(), gamefreeid).Count(&n).Error; err != nil { + logger.Logger.Errorf("find bankrupt player count get err: %v", err) + return 0, err + } + if n > 0 { + ret++ + } + } + return ret, nil +} + +// 场次参与总人数 +func PlayingGameCount(plt string, ids []int, startTime, endTime string, gamefreeid int) (int, error) { + s, e := common.StrRFC3339TimeToTime(startTime), common.StrRFC3339TimeToTime(endTime) + c, err := mymongo.GetLogCollection(plt, mongomodel.LogGamePlayerListLog) + if err != nil { + return 0, err + } + + var ret int + for _, v := range ids { + // 参与过游戏 + n, err := c.CountDocuments(context.TODO(), bson.M{"snid": v, "time": bson.M{"$gte": s, "$lt": e}, "gamefreeid": gamefreeid}) + if err != nil { + logger.Logger.Errorf("find playing game count get err: %v", err) + return 0, err + } + if n > 0 { + ret++ + } + } + return ret, nil +} + +// NewPlayerBankruptRate 新用户破产率 +// 新用户游戏破产率 = 新用户游戏破产玩家数量/新用户游戏参与总人数;破产数量,每个玩家每个游戏破产只统计一次;参与人数,每个玩家每个游戏只统计一次; +// 返回 新用户数量,破产人数,参与人数 +func NewPlayerBankruptRate(plt string, startTime, endTime string, gamefreeid int) (n, a, b int, err error) { + s, e := common.StrRFC3339TimeToTime(startTime), common.StrRFC3339TimeToTime(endTime) + if s.IsZero() || e.IsZero() { + return 0, 0, 0, fmt.Errorf("time format error") + } + ids, err := GetNewPayerIds(plt, startTime, endTime) + if err != nil { + return 0, 0, 0, err + } + + a, err = GameFreeIdBankruptPlayerCount(plt, ids, startTime, endTime, gamefreeid) + if err != nil { + return 0, 0, 0, err + } + b, err = PlayingGameCount(plt, ids, startTime, endTime, gamefreeid) + if err != nil { + return 0, 0, 0, err + } + if b == 0 { + return 0, 0, 0, nil + } + return +} + +// ActivePlayerCount 活跃玩家游戏总人数 +func ActivePlayerCount(plt string, startTime, endTime string, gamefreeid int) (int, error) { + s, e := common.StrRFC3339TimeToTime(startTime), common.StrRFC3339TimeToTime(endTime) + c, err := mymongo.GetLogCollection(plt, mongomodel.LogGamePlayerListLog) + if err != nil { + return 0, err + } + + var count []struct { + Count int + } + cur, err := c.Aggregate(context.TODO(), bson.A{ + bson.M{"$match": bson.M{"time": bson.M{"$gte": s, "$lt": e}, "gamefreeid": gamefreeid}}, + bson.M{"$group": bson.M{"_id": "$snid"}}, + bson.M{"$count": "count"}, + }) + if err != nil { + logger.Logger.Errorf("find active player count get err: %v", err) + return 0, err + } + if err := cur.All(context.TODO(), &count); err != nil { + logger.Logger.Errorf("find active player count decode err: %v", err) + return 0, err + } + + if len(count) == 0 { + return 0, nil + } + + return count[0].Count, nil +} + +// ActivePlayerBankruptCount 活跃玩家破产总人数 +func ActivePlayerBankruptCount(plt string, startTime, endTime string, gamefreeid int) (int, error) { + s, e := common.StrRFC3339TimeToTime(startTime), common.StrRFC3339TimeToTime(endTime) + db, err := mymysql.GetDatabase("count") + if err != nil { + return 0, err + } + var n int64 + if err = db.Table("bankrupt_log").Where("bankrupt_time >= ? AND bankrupt_time < ? AND game_free_id = ?", + s.Unix(), e.Unix(), gamefreeid).Group("snid").Count(&n).Error; err != nil { + logger.Logger.Errorf("find bankrupt count get err: %v", err) + return 0, err + } + return int(n), nil +} + +// ActivePlayerBankruptRate 活跃玩家破产率 +// 活跃玩家游戏破产率 = 活跃玩家游戏破产玩家数量/活跃玩家游戏总人数;破产数量,每个玩家每个游戏破产只统计一次;参与人数,每个玩家每个游戏只统计一次; +// 返回 破产人数,参与人数 +func ActivePlayerBankruptRate(plt string, startTime, endTime string, gamefreeid int) (a, b int, err error) { + s, e := common.StrRFC3339TimeToTime(startTime), common.StrRFC3339TimeToTime(endTime) + if s.IsZero() || e.IsZero() { + return 0, 0, fmt.Errorf("time format error") + } + + a, err = ActivePlayerBankruptCount(plt, startTime, endTime, gamefreeid) + if err != nil { + return 0, 0, err + } + b, err = ActivePlayerCount(plt, startTime, endTime, gamefreeid) + if err != nil { + return 0, 0, err + } + if b == 0 { + return 0, 0, nil + } + return +} diff --git a/statistics/task/task/bankruptoffline.go b/statistics/task/task/bankruptoffline.go new file mode 100644 index 0000000..c6f71c1 --- /dev/null +++ b/statistics/task/task/bankruptoffline.go @@ -0,0 +1,153 @@ +package task + +import ( + "context" + "fmt" + "strconv" + "strings" + "time" + + "go.mongodb.org/mongo-driver/bson" + "mongo.games.com/game/common" + mymongo "mongo.games.com/goserver/core/mongox" + mymysql "mongo.games.com/goserver/core/mysqlx" +) + +// 破产后离线;破产后5分钟内有离线行为 + +type BankruptOfflineData struct { + One int + Two int + Three int + Recharge int + D time.Duration +} + +func BankruptOffline(plt string, startTime, endTime string) (ret *BankruptOfflineData, err error) { + s, e := common.StrRFC3339TimeToTime(startTime), common.StrRFC3339TimeToTime(endTime) + if s.IsZero() || e.IsZero() { + return nil, fmt.Errorf("time format error") + } + db, err := mymysql.GetDatabase("count") + if err != nil { + return nil, err + } + + /* + SELECT + snid, + GROUP_CONCAT(bankrupt_time ORDER BY bankrupt_time ASC LIMIT 3) AS top_3_bankrupt_times, + COUNT(*) AS record_count + FROM + bankrupt_log + GROUP BY + snid; + */ + + type BankruptLog struct { + Snid int `gorm:"column:snid"` + MaxBankruptTime string `gorm:"column:top_3_bankrupt_times"` + Times []int64 `gorm:"-"` + } + + var logs []*BankruptLog + tx := db.Raw(` + WITH RankedData AS ( + SELECT + snid, + bankrupt_time, + ROW_NUMBER() OVER (PARTITION BY snid ORDER BY bankrupt_time ASC) AS ranks + FROM bankrupt_log + WHERE bankrupt_time >= ? AND bankrupt_time < ? + ) + SELECT + snid, + GROUP_CONCAT(bankrupt_time ORDER BY bankrupt_time ASC) AS top_3_bankrupt_times + FROM RankedData + WHERE ranks <= 3 + GROUP BY snid +`, s.Unix(), e.Unix()).Scan(&logs) + + if tx.Error != nil { + return nil, tx.Error + } + + var timeSecond int + var total int + + ret = &BankruptOfflineData{} + for _, v := range logs { + if v == nil || len(v.MaxBankruptTime) == 0 { + continue + } + for _, vv := range strings.Split(v.MaxBankruptTime, ",") { + n, err := strconv.Atoi(vv) + if err != nil { + return nil, err + } + v.Times = append(v.Times, int64(n)) + } + + // 破产后5分钟内有离线行为 + db, err = mymysql.GetDatabase(plt) + if err != nil { + return nil, err + } + + var isOffline bool + for k, vv := range v.Times { + var n int64 + stime, etime := time.Unix(vv, 0), time.Unix(vv, 0).Add(5*time.Minute) + if err = db.Table("user_logins").Where("snid = ? AND offline_time >= ? AND offline_time < ?", + v.Snid, stime, etime).Count(&n).Error; err != nil { + return nil, err + } + switch k { + case 0: + if n > 0 { + ret.One++ + isOffline = true + } + case 1: + if n > 0 { + ret.Two++ + isOffline = true + } + case 2: + if n > 0 { + ret.Three++ + isOffline = true + } + } + } + + if isOffline { + // 充值 + c, err := mymongo.GetLogCollection(plt, "log_dbshop") + if err != nil { + return nil, err + } + count, err := c.CountDocuments(context.TODO(), bson.M{"snid": v.Snid, "ts": bson.M{"$gte": s.Unix(), "$lt": e.Unix()}, "consume": 3, "state": 1}) + if err != nil { + return nil, err + } + if count > 0 { + ret.Recharge++ + } + + // 平均对局时长 + times, to, err := NewPlayerGameTime(plt, []int{v.Snid}, startTime, endTime, 0) + if err != nil { + return nil, err + } + timeSecond += times + total += to + } + } + + if total > 0 { + ret.D = time.Second * time.Duration(timeSecond/total) + } + + return ret, nil +} diff --git a/statistics/task/task/coin.go b/statistics/task/task/coin.go new file mode 100644 index 0000000..10747e6 --- /dev/null +++ b/statistics/task/task/coin.go @@ -0,0 +1,77 @@ +package task + +import ( + "context" + "fmt" + "go.mongodb.org/mongo-driver/bson" + "mongo.games.com/game/common" + "mongo.games.com/goserver/core/mongox" +) + +var CoinName = map[int]string{ + 44: "转盘", + 57: "轮盘视频", + 43: "签到", + 58: "签到视频", + 83: "累计签到", + 91: "累计签到进阶奖励", + 47: "vip每日礼包", + 105: "vip等级礼包", + 74: "集卡活动", + 67: "金币存钱罐", + 94: "赛季通行证等级奖励", + 95: "赛季通行证排行奖励", + 52: "排位赛段位奖励", + 65: "周卡奖励", + 5: "兑换", + 49: "礼包码兑换", + 38: "救济金", + 56: "救济金视频", +} + +func CoinHistory(plt string, startTime, endTime string, tp int, f func(data bson.M) error) error { + s, e := common.StrRFC3339TimeToTime(startTime), common.StrRFC3339TimeToTime(endTime) + if s.IsZero() || e.IsZero() { + return fmt.Errorf("time format error") + } + c, err := mongox.GetLogCollection(plt, "log_coinex") + if err != nil { + return err + } + + cur, err := c.Find(context.TODO(), bson.M{"time": bson.M{"$gte": s, "$lt": e}, "logtype": tp, "cointype": 0}) + if err != nil { + return err + } + defer cur.Close(context.Background()) + + for cur.TryNext(context.Background()) { + data := bson.M{} + if err := cur.Decode(data); err != nil { + return err + } + if err := f(data); err != nil { + return err + } + } + + return nil +} + +func CoinAvg(plt string, startTime, endTime string, tp int) (playerNumber int, total int, err error) { + player := make(map[int32]struct{}) + err = CoinHistory(plt, startTime, endTime, tp, func(data bson.M) error { + snid := data["snid"].(int32) + count := int(data["count"].(int64)) + player[snid] = struct{}{} + if count > 0 { + total += count + } + return nil + }) + if err != nil { + return + } + playerNumber = len(player) + return +} diff --git a/statistics/task/task/ctrlrate.go b/statistics/task/task/ctrlrate.go new file mode 100644 index 0000000..25eaf26 --- /dev/null +++ b/statistics/task/task/ctrlrate.go @@ -0,0 +1,214 @@ +package task + +import ( + "context" + "encoding/json" + "fmt" + "sort" + + "go.mongodb.org/mongo-driver/bson" + "mongo.games.com/goserver/core/logger" + "mongo.games.com/goserver/core/mongox" + + "mongo.games.com/game/common" +) + +func GameDetailFunc(plt string, startTime, endTime string, gamefreeid int, f func(data bson.M) error) error { + s, e := common.StrRFC3339TimeToTime(startTime), common.StrRFC3339TimeToTime(endTime) + if s.IsZero() || e.IsZero() { + return fmt.Errorf("time format error") + } + + c, err := mongox.GetLogCollection(plt, "log_gamedetailed") + if err != nil { + return err + } + + cur, err := c.Find(context.TODO(), bson.M{"time": bson.M{"$gte": s, "$lt": e}, "gamefreeid": gamefreeid}) + if err != nil { + return err + } + defer cur.Close(context.Background()) + + for cur.TryNext(context.Background()) { + data := bson.M{} + if err := cur.Decode(data); err != nil { + return err + } + if err := f(data); err != nil { + return err + } + } + + return nil +} + +type GameDetailWinRateRet struct { + First int + Second int + Third int + Total int + IsWin bool +} + +func GameDetailWinRate(plt string, startTime, endTime string, gamefreeid int) (ret []GameDetailWinRateRet, err error) { + ret = make([]GameDetailWinRateRet, 2) + err = GameDetailFunc(plt, startTime, endTime, gamefreeid, func(data bson.M) error { + ff, ss, tt, to, ct := GameDetailCount(data) + if ct == 1 && to > 0 { + ret[0].First += ff + ret[0].Second += ss + ret[0].Third += tt + ret[0].Total += to + } + if ct == 2 && to > 0 { + ret[1].First += ff + ret[1].Second += ss + ret[1].Third += tt + ret[1].Total += to + } + return nil + }) + return +} + +type RabbitMQDataRaw struct { + Source int32 + Data interface{} +} + +func GameDetailCount(data bson.M) (first, second, third, to int, ctrlType int) { + if data == nil { + return + } + gameid := data["gameid"].(int32) + gamefreeid := data["gamefreeid"].(int32) + ctrlType = int(data["ctrltype"].(int32)) + logger.Logger.Tracef("GameDetail gameid:%d, gamefreeid:%d", gameid, gamefreeid) + + if ctrlType != 1 && ctrlType != 2 { + return + } + + detail := data["gamedetailednote"] + if detail == nil { + return + } + + raw := new(RabbitMQDataRaw) + if err := json.Unmarshal([]byte(detail.(string)), raw); err != nil { + logger.Logger.Errorf("GameDetailCount Unmarshal 1 error:%v %v", err, gameid) + return + } + + switch gameid { + case 207, 208, 209, 210, 240, 241, 242, 243, 244, 245, 246, 247: // tienlen + data := new(TienLenType) + b, err := json.Marshal(raw.Data) + if err != nil { + logger.Logger.Errorf("GameDetailCount Marshal error:%v %v", err, gameid) + return + } + if err := json.Unmarshal(b, data); err != nil { + logger.Logger.Errorf("GameDetailCount Unmarshal 2 error:%v %v", err, gameid) + return + } + + var has, hasPlayer bool + for _, v := range data.PlayerData { + if v.IsRob { + has = true + } + if !v.IsRob { + hasPlayer = true + } + } + if !has || !hasPlayer { + // 没有机器人 + return 0, 0, 0, 0, ctrlType + } + + sort.Slice(data.PlayerData, func(i, j int) bool { + a, b := data.PlayerData[i].BillCoin+data.PlayerData[i].BillTaxCoin, data.PlayerData[j].BillCoin+data.PlayerData[j].BillTaxCoin + if a != b { + return a > b + } + if data.PlayerData[i].IsRob != data.PlayerData[j].IsRob { + return !data.PlayerData[i].IsRob + } + return data.PlayerData[i].UserId < data.PlayerData[j].UserId + }) + + for k, v := range data.PlayerData { + if !v.IsRob && v.BillCoin > 0 && k <= 1 { + if k == 0 { + first = 1 + } + if k == 1 { + second = 1 + } + break + } + } + if len(data.PlayerData) > 2 && first+second == 0 && !data.PlayerData[2].IsRob { + third = 1 + } + to = 1 + + case 211, 212, 213, 214: + data := new(ThirteenWaterType) + b, err := json.Marshal(raw.Data) + if err != nil { + logger.Logger.Errorf("GameDetailCount Marshal error:%v %v", err, gameid) + return + } + if err := json.Unmarshal(b, data); err != nil { + logger.Logger.Errorf("GameDetailCount Unmarshal 2 error:%v %v", err, gameid) + return + } + + var has, hasPlayer bool + for _, v := range data.PlayerData { + if v.IsRob { + has = true + } + if !v.IsRob { + hasPlayer = true + } + } + if !has || !hasPlayer { + // 没有机器人 + return 0, 0, 0, 0, ctrlType + } + + sort.Slice(data.PlayerData, func(i, j int) bool { + a, b := data.PlayerData[i].AllScore, data.PlayerData[j].AllScore + if a != b { + return a > b + } + if data.PlayerData[i].IsRob != data.PlayerData[j].IsRob { + return !data.PlayerData[i].IsRob + } + return data.PlayerData[i].UserId < data.PlayerData[j].UserId + }) + + for k, v := range data.PlayerData { + if !v.IsRob && v.AllScore > 0 && k <= 1 { + if k == 0 { + first = 1 + } + if k == 1 { + second = 1 + } + break + } + } + + if len(data.PlayerData) > 2 && first+second == 0 && !data.PlayerData[2].IsRob { + third = 1 + } + + to = 1 + } + return +} diff --git a/statistics/task/task/gamebankruptcy.go b/statistics/task/task/gamebankruptcy.go new file mode 100644 index 0000000..21bbbcf --- /dev/null +++ b/statistics/task/task/gamebankruptcy.go @@ -0,0 +1,69 @@ +package task + +import ( + "context" + "fmt" + "go.mongodb.org/mongo-driver/bson" + "mongo.games.com/game/common" + "mongo.games.com/goserver/core/logger" + mymongo "mongo.games.com/goserver/core/mongox" + mymysql "mongo.games.com/goserver/core/mysqlx" +) + +// 场次破产率 + +// GameFreeIdBankruptcyTimes 场次破产次数 +func GameFreeIdBankruptcyTimes(plt string, startTime, endTime string, gamefreeid int) (int, error) { + s, e := common.StrRFC3339TimeToTime(startTime), common.StrRFC3339TimeToTime(endTime) + db, err := mymysql.GetDatabase("count") + if err != nil { + return 0, err + } + + var n int64 + if err = db.Table("bankrupt_log").Where("bankrupt_time >= ? AND bankrupt_time < ? AND game_free_id = ?", + s.Unix(), e.Unix(), gamefreeid).Count(&n).Error; err != nil { + logger.Logger.Errorf("find bankrupt count get err: %v", err) + return 0, err + } + + return int(n), nil +} + +// GameFreeIdTotalTimes 场次总局数 +func GameFreeIdTotalTimes(plt string, startTime, endTime string, gamefreeid int) (int, error) { + s, e := common.StrRFC3339TimeToTime(startTime), common.StrRFC3339TimeToTime(endTime) + c, err := mymongo.GetLogCollection(plt, "log_gamedetailed") + if err != nil { + return 0, err + } + + n, err := c.CountDocuments(context.TODO(), bson.M{"time": bson.M{"$gte": s, "$lt": e}, "gamefreeid": gamefreeid}) + if err != nil { + logger.Logger.Errorf("find game total times get err: %v", err) + return 0, err + } + + return int(n), nil +} + +// GameBankruptcyRate 场次破产率 +// 返回 破产局数, 总局数, 错误 +func GameBankruptcyRate(plt string, startTime, endTime string, gamefreeid int) (int, int, error) { + s, e := common.StrRFC3339TimeToTime(startTime), common.StrRFC3339TimeToTime(endTime) + if s.IsZero() || e.IsZero() { + return 0, 0, fmt.Errorf("time format error") + } + + b, err := GameFreeIdBankruptcyTimes(plt, startTime, endTime, gamefreeid) + if err != nil { + return 0, 0, err + } + + t, err := GameFreeIdTotalTimes(plt, startTime, endTime, gamefreeid) + if err != nil { + return 0, 0, err + } + + return b, t, nil +} diff --git a/statistics/task/task/gamecount.go b/statistics/task/task/gamecount.go new file mode 100644 index 0000000..911c202 --- /dev/null +++ b/statistics/task/task/gamecount.go @@ -0,0 +1,60 @@ +package task + +import ( + "context" + "fmt" + "go.mongodb.org/mongo-driver/bson" + "mongo.games.com/game/common" + mongomodel "mongo.games.com/game/statistics/modelmongo" + "mongo.games.com/goserver/core/logger" + mymongo "mongo.games.com/goserver/core/mongox" +) + +// 新用户平均局数 + +func NewPlayerGameCount(plt string, ids []int, startTime, endTime string, gamefreeid int) (int, error) { + s, e := common.StrRFC3339TimeToTime(startTime), common.StrRFC3339TimeToTime(endTime) + c, err := mymongo.GetLogCollection(plt, mongomodel.LogGamePlayerListLog) + if err != nil { + return 0, err + } + + var ret int + for _, v := range ids { + n, err := c.CountDocuments(context.TODO(), bson.M{"snid": v, "gamefreeid": gamefreeid, "time": bson.M{"$gte": s, "$lt": e}}) + if err != nil { + logger.Logger.Errorf("find player gamedetailedlogid get err: %v", err) + return 0, err + } + ret += int(n) + } + + return ret, nil +} + +// NewPlayerGameCountAvg 新用户平均局数 +// 返回 参与人数,总局数 +func NewPlayerGameCountAvg(plt string, startTime, endTime string, gamefreeid int) (int, int, error) { + s, e := common.StrRFC3339TimeToTime(startTime), common.StrRFC3339TimeToTime(endTime) + if s.IsZero() || e.IsZero() { + return 0, 0, fmt.Errorf("time format error") + } + ids, err := GetNewPayerIds(plt, startTime, endTime) + if err != nil { + return 0, 0, err + } + n, err := NewPlayerGameCount(plt, ids, startTime, endTime, gamefreeid) + if err != nil { + return 0, 0, err + } + if len(ids) == 0 { + return 0, 0, nil + } + + b, err := PlayingGameCount(plt, ids, startTime, endTime, gamefreeid) + if err != nil { + return 0, 0, err + } + + return b, n, nil +} diff --git a/statistics/task/task/gamelogtype.go b/statistics/task/task/gamelogtype.go new file mode 100644 index 0000000..74cbf60 --- /dev/null +++ b/statistics/task/task/gamelogtype.go @@ -0,0 +1,1625 @@ +package task + +// 赢三张 +type WinThreeType struct { + RoomId int32 //房间ID + RoomRounds int32 //建房局数 + RoomType int32 //房间类型 + NowRound int32 //当前局数 + PlayerCount int //玩家数量 + BaseScore int32 //底分 + PlayerData []WinThreePerson //玩家信息 + Chip []PlayerChip //出牌详情 + ClubRate int32 //俱乐部抽水比例 + IsSmartOperation bool // 是否启用智能化运营 + GamePreUseSmartState int //-1:正常 + GameLastUseSmartState int //-1:正常 + RobotUseSmartState int64 // Robot使用智能化运营状况 +} +type PlayerChip struct { + UserId int32 //玩家ID + BetTotal int64 //玩家总投注 + Chip int64 //玩家得分 + StartCoin int64 //玩家开始前金币 + BetAfterCoin int64 //玩家投注后金币,也就是客户端应该显示的金币 + IsCheck bool //是否看牌 + Round int32 //当前轮次 + Op int32 //操作 +} + +type WinThreePerson struct { + UserId int32 //玩家ID + UserIcon int32 //玩家头像 + ChangeCoin int64 //玩家得分 + Cardinfo []int32 //牌值 + KindOfCard int32 //牌型 + IsWin int32 //输赢 + IsRob bool //是否是机器人 + Tax int64 //税,不一定有值,只是作为一个临时变量使用 + ClubPump int64 //俱乐部额外抽水 + Flag int //标识 + Pos int32 //位置 + StartCoin int64 //开始金币 + BetCoin int64 //押注额度 + RoundCheck int32 //轮次,看牌的 + IsFirst bool //是否第一次 + IsLeave bool + Platform string `json:"-"` + Channel string `json:"-"` + Promoter string `json:"-"` + PackageTag string `json:"-"` + InviterId int32 `json:"-"` + WBLevel int32 //黑白名单等级 + SingleFlag int32 //单控标记 +} + +// 经典牛牛 抢庄牛牛 +type BullFightType struct { + RoomId int32 //房间ID + RoomRounds int32 //建房局数 + RoomType int32 //房间类型 + NowRound int32 //当前局数 + BankId int32 //庄家ID + PlayerCount int //玩家数量 + BaseScore int32 //底分 + PlayerData []BullFightPerson //玩家信息 + ClubRate int32 //俱乐部抽水比例 + IsSmartOperation bool // 是否启用智能化运营 +} +type BullFightPerson struct { + UserId int32 //玩家ID + UserIcon int32 //玩家头像 + ChangeCoin int64 //玩家得分 + Cardinfo []int32 //牌值 + CardBakinfo []int32 //牌值 + IsWin int32 //输赢 + Tax int64 //税,不一定有值,只是作为一个临时变量使用 + TaxLottery int64 //彩金池,增加值 + ClubPump int64 //俱乐部额外抽水 + IsRob bool //是否是机器人 + Flag int //标识 + IsFirst bool + StartCoin int64 //开始金币 + Platform string `json:"-"` + Channel string `json:"-"` + Promoter string `json:"-"` + PackageTag string `json:"-"` + InviterId int32 `json:"-"` + Rate int64 //斗牛倍率 + WBLevel int32 //黑白名单等级 + RobBankRate int64 //抢庄倍率 + SingleAdjust int32 // 单控输赢 1赢 2输 +} + +// 斗地主、跑得快 +type DoudizhuType struct { + RoomId int //房间Id + BasicScore int //基本分 + Spring int //春天 1代表春天 + BombScore int //炸弹分 + BaseScore int32 //底分 + PlayerCount int32 //玩家数量 + BaseCards []int //底牌 + BankerId int32 //斗地主地主Id + PlayerData []DoudizhuPerson //玩家信息 + ClubRate int32 //俱乐部抽水比例 + IsSmartOperation bool // 是否启用智能化运营 +} +type DoudizhuPerson struct { + UserId int32 //玩家ID + UserIcon int32 //玩家头像 + ChangeCoin int64 //玩家得分 + OutCards [][]int64 //出的牌 + SurplusCards []int32 //剩下的牌 + IsWin int64 //输赢 + IsRob bool //是否是机器人 + IsFirst bool + Tax int64 //税,不一定有值,只是作为一个临时变量使用 + ClubPump int64 //俱乐部额外抽水 + StartCoin int64 //开始的金币数量 + Platform string `json:"-"` + Channel string `json:"-"` + Promoter string `json:"-"` + PackageTag string `json:"-"` + InviterId int32 `json:"-"` + WBLevel int32 //黑白名单等级 +} + +// 推饼 +type TuibingType struct { + RoomId int32 //房间ID + RoomRounds int32 //建房局数 + RoomType int32 //房间类型 + NowRound int32 //当前局数 + BankId int32 //庄家ID + PlayerCount int //玩家数量 + BaseScore int32 //底分 + PlayerData []TuibingPerson //玩家信息 + ClubRate int32 //俱乐部抽水比例 + IsSmartOperation bool // 是否启用智能化运营 +} +type TuibingPerson struct { + UserId int32 //玩家ID + UserIcon int32 //玩家头像 + ChangeCoin int64 //玩家得分 + Cardinfo []int32 //牌值 + IsWin int32 //输赢 + IsRob bool //是否是机器人 + IsFirst bool + Tax int64 //税,不一定有值,只是作为一个临时变量使用 + ClubPump int64 //俱乐部额外抽水 + Flag int //标识 + StartCoin int64 //开始金币 + Platform string `json:"-"` + Channel string `json:"-"` + Promoter string `json:"-"` + PackageTag string `json:"-"` + InviterId int32 `json:"-"` + Rate int64 //倍率 + WBLevel int32 //黑白名单等级 +} + +// 十三水 +// 十三水牌值 +type ThirteenWaterType struct { + BaseScore int32 //底分 + PlayerData []ThirteenWaterPerson //玩家信息 +} + +type ThirteenWaterPoker struct { + Head [3]int + Mid [5]int + End [5]int + PokerType int +} + +type ThirteenWaterPerson struct { + UserId int32 //玩家ID + IsRob bool // 是否是机器人 + AllScore int // 总得分 +} + +// 二人麻将 +type MahjongType struct { + RoomId int32 //房间ID + RoomRounds int32 //建房局数 + RoomType int32 //房间类型 + NowRound int32 //当前局数 + BankId int32 //庄家ID + PlayerCount int32 //玩家数量 + BaseScore int32 //底分 + HuType []int64 //本局胡牌牌型 + PlayerData []MahjongPerson //玩家信息 +} +type MahjongPerson struct { + UserId int32 //玩家ID + UserIcon int32 //玩家头像 + ChangeCoin int64 //玩家得分 + SurplusCards []int64 //剩下的牌 + CardsChow [][]int64 //吃的牌 + CardsPong []int64 //碰的牌 + CardsMingKong []int64 //明杠的牌 + CardsAnKong []int64 //暗杠的牌 + IsWin int32 //输赢 + StartCoin int64 //开始金币 + Tax int64 //税,不一定有值,只是作为一个临时变量使用 + ClubPump int64 //俱乐部额外抽水 + IsRob bool //是否是机器人 + IsFirst bool + Platform string `json:"-"` + Channel string `json:"-"` + Promoter string `json:"-"` + PackageTag string `json:"-"` + InviterId int32 `json:"-"` + WBLevel int32 //黑白名单等级 +} + +// 百人牛牛 龙虎斗 百家乐 红黑大战 +type HundredType struct { + RegionId int32 //边池ID 庄家 天 地 玄 黄 + IsWin int //边池输赢 + Rate int //倍数 + CardsInfo []int32 //扑克牌值 + PlayerData []HundredPerson //玩家属性 + CardsKind int32 //牌类型 + CardPoint int32 //点数 + IsSmartOperation bool // 是否启用智能化运营 +} +type HundredPerson struct { + UserId int32 //用户Id + UserBetTotal int64 //用户下注 + BeforeCoin int64 //下注前金额 + AfterCoin int64 //下注后金额 + ChangeCoin int64 //金额变化 + IsRob bool //是否是机器人 + IsFirst bool + WBLevel int32 //黑白名单等级 + Result int32 //单控结果 + UserBetTotalDetail []int64 //用户下注明细 +} + +// 碰撞 +type CrashType struct { + RegionId int32 //边池ID 庄家 天 地 玄 黄 + IsWin int //边池输赢 + Rate int //倍数 + CardsInfo []int32 //扑克牌值 + PlayerData []CrashPerson //玩家属性 + CardsKind int32 //牌类型 + CardPoint int32 //点数 + IsSmartOperation bool // 是否启用智能化运营 + Hash string //Hash + Period int //当前多少期 + Wheel int //第几轮 +} + +// 碰撞 +type CrashPerson struct { + UserId int32 //用户Id + UserBetTotal int64 //用户下注 + UserMultiple int32 //下注倍数 + BeforeCoin int64 //下注前金额 + AfterCoin int64 //下注后金额 + ChangeCoin int64 //金额变化 + IsRob bool //是否是机器人 + IsFirst bool + WBLevel int32 //黑白名单等级 + Result int32 //单控结果 + UserBetTotalDetail []int64 //用户下注明细 + Tax int64 //税收 +} + +// 十点半 +type TenHalfType struct { + RoomId int32 //房间ID + RoomRounds int32 //建房局数 + RoomType int32 //房间类型 + NowRound int32 //当前局数 + BankId int32 //庄家ID + PlayerCount int //玩家数量 + BaseScore int32 //底分 + PlayerData []TenHalfPerson //玩家信息 + ClubRate int32 //俱乐部抽水比例 + IsSmartOperation bool // 是否启用智能化运营 +} + +type TenHalfPerson struct { + UserId int32 //玩家ID + UserIcon int32 //玩家头像 + ChangeCoin int64 //玩家得分 + Cardinfo []int32 //牌值 + IsWin int32 //输赢 + Tax int64 //税,不一定有值,只是作为一个临时变量使用 + ClubPump int64 //俱乐部额外抽水 + IsRob bool //是否是机器人 + Flag int //标识 + IsFirst bool + StartCoin int64 //开始金币 + Platform string `json:"-"` + Channel string `json:"-"` + Promoter string `json:"-"` + PackageTag string `json:"-"` + InviterId int32 `json:"-"` + WBLevel int32 //黑白名单等级 +} + +type GanDengYanType struct { + RoomId int // 房间Id + RoomRounds int32 // 建房局数 + NowRound int32 // 当前局数 + BombScore int // 炸弹倍率 + BaseScore int32 // 底分 + PlayerCount int32 // 玩家数量 + BankerId int32 // 庄家id + PlayerData []GanDengYanPlayer // 玩家信息 + ClubRate int32 // 俱乐部抽水比例 +} + +type GanDengYanHandCards struct { + Cards []int64 + Index int32 +} + +type GanDengYanPlayer struct { + UserId int32 // 玩家ID + UserIcon int32 // 玩家头像 + ChangeCoin int64 // 玩家得分 + OutCards []*GanDengYanHandCards // 出的牌 + SurplusCards []int32 // 剩下的牌 + IsWin int64 // 输赢 + IsRob bool // 是否是机器人 + IsFirst bool + Tax int64 // 税,不一定有值,只是作为一个临时变量使用 + ClubPump int64 // 俱乐部额外抽水 + StartCoin int64 // 开始的金币数量 + Platform string `json:"-"` + Channel string `json:"-"` + Promoter string `json:"-"` + PackageTag string `json:"-"` + InviterId int32 `json:"-"` + WBLevel int32 //黑白名单等级 + NumMagic int32 // 癞子或2倍数 + NumCards int32 // 剩余牌数 + NumHand int32 // 手牌倍数 + Num int32 // 总倍数 +} + +// 红包扫雷 +type RedPackGameType struct { + BankerId int32 //庄家id + BankerBet int32 //庄家下注金额 + BankerWin int32 //庄家赢取 + BankerRest int32 //庄家退回钱数 + Rate int32 //倍数 + BombNum int32 //雷号 + HitBombCnt int32 //中雷的人数 + PlayerData []*RedPackPerson //玩家属性 +} +type RedPackPerson struct { + UserId int32 //用户Id + IsFirst bool + BeforeCoin int64 //抢包前金额 + AfterCoin int64 //抢包后金额 + ChangeCoin int64 //金额变化 + GrabCoin int32 //抢到红包的数量 + IsHit bool //是否中雷 + IsRob bool //是否是机器人 +} + +// 鱼场 +type BulletLevelTimes struct { + Level int32 //等级 + Times int32 //次数 +} +type FishCoinNum struct { + ID int32 // 鱼id + Num int32 //打死数量 + Power int32 //子弹价值 + Coin int32 //金币(总金币) + HitNum int32 //击中次数 +} + +type FishPlayerData struct { + UserId int32 //玩家ID + UserIcon int32 //玩家头像 + TotalIn int64 //玩家该阶段总投入 + TotalOut int64 //玩家该阶段总产出 + CurrCoin int64 //记录时玩家当前金币量 +} + +type FishDetiel struct { + BulletInfo *[]BulletLevelTimes //子弹统计 + HitInfo *[]FishCoinNum // + PlayData *FishPlayerData //统计 +} + +// 拉霸 +// 绝地求生记录详情 +type IslandSurvivalGameType struct { + //all + RoomId int32 //房间Id + BasicScore int32 //基本分 + PlayerSnid int32 //玩家id + BeforeCoin int64 //下注前金额 + AfterCoin int64 //下注后金额 + BetCoin int64 //下注金额 + WinCoin int64 //下注赢取金额 + IsFirst bool + Smallgamewinscore int64 //吃鸡游戏赢取的分数 + ChangeCoin int64 //本局游戏金额总变化 + FreeTimes int32 //免费转动次数 + AllWinNum int32 //中奖的线数 + LeftEnemy int32 //剩余敌人,需保存 + Killed int32 //总击杀敌人,需保存 + HitPoolIdx int //下注索引 + Cards []int //15张牌 +} + +const ( + WaterMarginSmallGame_Unop int32 = iota + WaterMarginSmallGame_AddOp + WaterMarginSmallGame_SubOp +) + +// 水浒传小游戏数据 +type WaterMarginSmallGameInfo struct { + AddOrSub int32 //加减操作 0:表示未操作 1:加 2:减 + Score int64 //本局小游戏参与的分数 + Multiple int32 //倍数 0:表示本局输了 >1:表示猜对小游戏 + Dice1 int32 //骰子1的点数 + Dice2 int32 //骰子2的点数 +} + +type WaterMarginType struct { + RoomId int32 //房间Id + BasicScore int32 //基本分 + PlayerSnid int32 //玩家id + BeforeCoin int64 //下注前金额 + AfterCoin int64 //下注后金额 + IsFirst bool //是否一次游戏 + ChangeCoin int64 //金额变化 + Score int32 //总押注数 + AllWinNum int32 //中奖的线数 + FreeTimes int32 //免费转动次数 + WinScore int32 //中奖的倍率 + AllLine int32 //线路数 + JackpotNowCoin int64 //爆奖金额 + Cards []int //15张牌 + HitPoolIdx int //压分的索引 + JackpotHitFlag int //如果jackpotnowcoin>0;该值标识中了哪些奖池,二进制字段 1:小奖(第0位) 2:中奖(第1位) 4:大奖(第2位) + TrigFree bool //是否触发免费转动 + SMGame []*WaterMarginSmallGameInfo //小游戏数据 +} + +type FootBallHeroesType struct { + RoomId int32 //房间Id + BasicScore int32 //基本分 + PlayerSnid int32 //玩家id + BeforeCoin int64 //下注前金额 + AfterCoin int64 //下注后金额 + ChangeCoin int64 //金额变化 + IsFirst bool + Score int32 //总押注数 + FreeTimes int32 //免费转动次数 + WinScore int32 //中奖的倍率 + Cards []int //15张牌 + CoinReward []int64 //礼物奖励 + Smallgamescore int64 //小游戏分数 + Smallgamewinscore int64 //小游戏赢取的分数 + SmallgameList []int32 //小游戏记录 + HitPoolIdx int //当前命中的奖池 +} +type FruitMachineType struct { + RoomId int32 //房间Id + BasicScore int32 //基本分 + PlayerSnid int32 //玩家id + BeforeCoin int64 //下注前金额 + AfterCoin int64 //下注后金额 + IsFirst bool + ChangeCoin int64 //金额变化 + Score int32 //总押注数 + AllWinNum int32 //中奖的线数 + FreeTimes int32 //免费转动次数 + WinScore int32 //中奖的倍率 + AllLine int32 //线路数 + JackpotNowCoin int64 //爆奖金额 + Cards []int //15张牌 + Smallgamescore int64 //小游戏分数 + HitPoolIdx int //当前命中的奖池 +} +type GoddessType struct { + RoomId int32 //房间Id + BasicScore int32 //基本分 + PlayerSnid int32 //玩家id + BeforeCoin int64 //下注前金额 + AfterCoin int64 //下注后金额 + ChangeCoin int64 //金额变化 + Score int32 //总押注数 + IsFirst bool + Smallgamescore int64 //小游戏分数 + Smallgamewinscore int64 //小游戏赢取的分数 + SmallgameCard int32 //小游戏卡牌 + CardsGoddess [3]int32 //3张牌 + BetMultiple int32 //押倍倍数 + SmallgameList []int32 //小游戏记录 + HitPoolIdx int //当前命中的奖池 +} +type RollLineType struct { + RoomId int32 //房间Id + BasicScore int32 //基本分 + PlayerSnid int32 //玩家id + BeforeCoin int64 //下注前金额 + AfterCoin int64 //下注后金额 + ChangeCoin int64 //金额变化 + Score int32 //总押注数 + IsFirst bool + AllWinNum int32 //中奖的线数 + FreeTimes int32 //免费转动次数 + WinScore int32 //中奖的倍率 + AllLine int32 //线路数 + RoseCount int32 //玫瑰数量 + Cards []int //15张牌 + CoinReward []int64 //礼物奖励 + HitPoolIdx int //当前命中的奖池 +} +type IceAgeType struct { + RoomId int32 //房间Id + BasicScore int32 //基本分 + PlayerSnid int32 //玩家id + BeforeCoin int64 //下注前金额 + AfterCoin int64 //下注后金额 + ChangeCoin int64 //金额变化 + Score int32 //总押注数 + Tax int64 //暗税 + IsFirst bool + AllWinNum int32 //中奖的线数 + FreeTimes int32 //免费转动次数 + WinScore int32 //中奖的倍率 + AllLine int32 //线路数 + Cards [][]int32 // 消除前后的牌(消除前15张,消除后15张...) + BetLines []int64 //下注的线 + UserName string // 昵称 + TotalPriceValue int64 // 总赢分 + IsFree bool // 是否免费 + TotalBonusValue int64 // 总bonus数 + WBLevel int32 //黑白名单等级 + WinLines [][]int // 赢分的线 + WinJackpot int64 // 赢奖池分数 + WinBonus int64 // 赢小游戏分数 +} +type TamQuocType struct { + RoomId int32 //房间Id + BasicScore int32 //基本分 + PlayerSnid int32 //玩家id + BeforeCoin int64 //下注前金额 + AfterCoin int64 //下注后金额 + ChangeCoin int64 //金额变化 + Score int32 //总押注数 + Tax int64 //暗税 + IsFirst bool + AllWinNum int32 //中奖的线数 + FreeTimes int32 //免费转动次数 + WinScore int32 //中奖的倍率 + AllLine int32 //线路数 + Cards []int32 //15张牌 + BetLines []int64 //下注的线 + WBLevel int32 //黑白名单等级 + UserName string // 昵称 + TotalPriceValue int64 // 总赢分 + IsFree bool // 是否免费 + TotalBonusValue int64 // 总bonus数 + WinLines []int // 赢分的线 + WinJackpot int64 // 赢奖池分数 + WinBonus int64 // 赢小游戏分数 +} +type CaiShenType struct { + RoomId int32 //房间Id + BasicScore int32 //基本分 + PlayerSnid int32 //玩家id + BeforeCoin int64 //下注前金额 + AfterCoin int64 //下注后金额 + ChangeCoin int64 //金额变化 + Score int32 //总押注数 + Tax int64 //暗税 + IsFirst bool + AllWinNum int32 //中奖的线数 + FreeTimes int32 //免费转动次数 + WinScore int32 //中奖的倍率 + AllLine int32 //线路数 + Cards []int32 //15张牌 + WBLevel int32 //黑白名单等级 + BetLines []int64 //下注的线 + UserName string // 昵称 + TotalPriceValue int64 // 总赢分 + IsFree bool // 是否免费 + TotalBonusValue int64 // 总bonus数 + WinLines []int // 赢分的线 + WinJackpot int64 // 赢奖池分数 + WinBonus int64 // 赢小游戏分数 +} +type AvengersType struct { + RoomId int32 //房间Id + BasicScore int32 //基本分 + PlayerSnid int32 //玩家id + BeforeCoin int64 //下注前金额 + AfterCoin int64 //下注后金额 + ChangeCoin int64 //金额变化 + Score int32 //总押注数 + Tax int64 //暗税 + IsFirst bool + AllWinNum int32 //中奖的线数 + FreeTimes int32 //免费转动次数 + WinScore int32 //中奖的倍率 + AllLine int32 //线路数 + Cards []int32 //15张牌 + WBLevel int32 //黑白名单等级 + BetLines []int64 //下注的线 + UserName string // 昵称 + TotalPriceValue int64 // 总赢分 + IsFree bool // 是否免费 + TotalBonusValue int64 // 总bonus数 + WinLines []int // 赢分的线 + WinJackpot int64 // 赢奖池分数 + WinBonus int64 // 赢小游戏分数 +} +type EasterIslandType struct { + RoomId int32 //房间Id + BasicScore int32 //基本分 + PlayerSnid int32 //玩家id + BeforeCoin int64 //下注前金额 + AfterCoin int64 //下注后金额 + ChangeCoin int64 //金额变化 + Score int32 //总押注数 + Tax int64 //暗税 + IsFirst bool + AllWinNum int32 //中奖的线数 + FreeTimes int32 //免费转动次数 + WinScore int32 //中奖的倍率 + AllLine int32 //线路数 + Cards []int32 //15张牌 + WBLevel int32 //黑白名单等级 + BetLines []int64 //下注的线 + UserName string // 昵称 + TotalPriceValue int64 // 总赢分 + IsFree bool // 是否免费 + TotalBonusValue int64 // 总bonus数 + WinLines []int // 赢分的线 + WinJackpot int64 // 赢奖池分数 + WinBonus int64 // 赢小游戏分数 +} +type RollTeamType struct { + RoomId int32 //房间Id + BasicScore int32 //基本分 + PlayerSnid int32 //玩家id + BeforeCoin int64 //下注前金额 + AfterCoin int64 //下注后金额 + ChangeCoin int64 //金额变化 + Score int32 //总押注数 + AllWinNum int32 //中奖的线数 + IsFirst bool + FreeTimes int32 //免费转动次数 + WinScore int32 //中奖的倍率 + AllLine int32 //线路数 + PokerBaseCoin int32 //扑克游戏获得的金币 + PokerRate int32 //游戏的翻倍值 + GameCount int32 //游戏次数 + HitPoolIdx int //当前命中的奖池 + Cards []int //15张牌 +} +type RollPerson struct { + UserId int32 //用户Id + UserBetTotal int64 //用户下注 + BeforeCoin int64 //下注前金额 + AfterCoin int64 //下注后金额 + ChangeCoin int64 //金额变化 + IsFirst bool + IsRob bool //是否是机器人 + WBLevel int32 //黑白名单等级 +} +type RollHundredType struct { + RegionId int32 //边池ID -1.庄家 0.大众 1.雷克萨斯 2.宝马 3.奔驰 4.保时捷 5.玛莎拉蒂 6.兰博基尼 7.法拉利 + IsWin int //边池输赢 1.赢 0.平 -1.输 + Rate int //倍数 + SType int32 //特殊牌型 临时使用 + RollPerson []RollPerson +} + +// 梭哈 +type FiveCardType struct { + RoomId int32 //房间ID + RoomRounds int32 //建房局数 + RoomType int32 //房间类型 + PlayerCount int //玩家数量 + BaseScore int32 //底分 + PlayerData []FiveCardPerson //玩家信息 + ClubRate int32 //俱乐部抽水比例 +} + +// 梭哈 +type FiveCardPerson struct { + UserId int32 //玩家ID + UserIcon int32 //玩家头像 + ChangeCoin int64 //玩家得分 + Cardinfo []int32 //牌值 + IsWin int32 //输赢 + Tax int64 //税,不一定有值,只是作为一个临时变量使用 + ClubPump int64 //俱乐部额外抽水 + IsRob bool //是否是机器人 + IsFirst bool //是否第一次 + IsLeave bool //中途离开 + Platform string `json:"-"` + Channel string `json:"-"` + Promoter string `json:"-"` + PackageTag string `json:"-"` + InviterId int32 `json:"-"` + BetTotal int64 //用户当局总下注 + IsAllIn bool //是否全下 + WBLevel int32 //黑白名单等级 +} + +// 骰子 +type RollPointPerson struct { + UserId int32 //用户Id + UserBetTotal int64 //用户下注 + BeforeCoin int64 //下注前金额 + AfterCoin int64 //下注后金额 + ChangeCoin int64 //金额变化 + IsFirst bool + IsRob bool //是否是机器人 + WBLevel int32 //黑白名单等级 + BetCoin []int32 //押注金币 +} +type RollPointType struct { + RoomId int32 + Point []int32 + Score []int32 + BetCoin int64 + WinCoin int64 + Person []RollPointPerson +} + +// 轮盘 +type RouletteType struct { + BankerInfo RouletteBanker //庄家信息 + Person []RoulettePerson //下注玩家列表 + RouletteRegion []RouletteRegion //下区域 +} +type RouletteBanker struct { + Point int //当局开的点数 + TotalBetCoin int64 //总下注金额 + TotalWinCoin int64 //总输赢金额 +} +type RouletteRegion struct { + Id int //0-156 下注位置编号 + IsWin int //是否中奖 + BetCoin int64 //当前区域总下注金额 + WinCoin int64 //当前区域总输赢金额 + Player []RoulettePlayer //当前区域下注玩家列表 +} +type RoulettePlayer struct { + UserId int32 //用户Id + BetCoin int64 //当局下注额 +} +type RoulettePerson struct { + UserId int32 //用户Id + BeforeCoin int64 //下注前金额 + AfterCoin int64 //下注后金额 + UserBetTotal int64 //用户总下注 + UserWinCoin int64 //用户输赢 + IsRob bool //是否是机器人 + WBLevel int32 //黑白名单等级 + BetCoin map[int]int64 //下注区域对应金额 +} + +// 九线拉王 +type NineLineKingType struct { + RoomId int32 //房间Id + BasicScore int32 //基本分 + PlayerSnid int32 //玩家id + BeforeCoin int64 //下注前金额 + AfterCoin int64 //下注后金额 + IsFirst bool + ChangeCoin int64 //金额变化 + Score int32 //总押注数 + AllWinNum int32 //中奖的线数 + FreeTimes int32 //免费转动次数 + WinScore int32 //中奖的倍率 + AllLine int32 //线路数 + JackpotNowCoin int64 //爆奖金额 + Cards []int //15张牌 + HitPoolIdx int //当前命中的奖池 + CommPool int64 //公共奖池 + PersonPool int64 //私人奖池 +} + +// 飞禽走兽 +type RollAnimalsType struct { + BetTotal int64 //总下注 + WinCoin int64 //用户输赢 + WinFlag []int64 //中奖元素 + RollLog []RollHundredType //每个区域下注信息 +} + +// 血战 +type BloodMahjongType struct { + RoomId int32 //房间ID + RoomRounds int32 //建房局数 + RoomType int32 //房间类型 + NowRound int32 //当前局数 + BankId int32 //庄家ID + PlayerCount int32 //玩家数量 + BaseScore int32 //底分 + PlayerData []BloodMahjongPerson //玩家信息 +} + +// 碰杠牌 +type BloodMahjongCardsLog struct { + Card int64 //牌 + Pos []int //0.东 1.南 2.西 3.北 + Flag int //1.碰 2.明杠 3.暗杠 4.补杠 +} + +// 分数类型 +type BloodMahjongScoreTiles struct { + LogType int //0.胡 1.刮风 2.下雨 3.退税 4.查花猪 5.查大叫 6.被抢杠 补杠退钱 7.呼叫转移 + OtherPos []int //源自哪个位置的玩家 + Coin int64 //理论进账 + ActualCoin int64 //实际进账 + Rate int32 //倍率 + Params []int64 //【Honor】//胡牌类型 +} +type BloodMahjongPerson struct { + UserId int32 //玩家ID + UserIcon int32 //玩家头像 + ChangeCoin int64 //玩家得分 + Pos int32 //玩家位置 0.东 1.南 2.西 3.北 + IsLeave bool //是否离场 + Bankruptcy bool //是否破产 + HuNumber int32 //第几胡 1 2 3 + LackColor int64 //定缺花色 + Hands []int64 //手牌 + HuCards []int64 //胡牌 + CardsLog []BloodMahjongCardsLog //碰杠牌 + ScoreTiles []BloodMahjongScoreTiles //分数 + IsWin int32 //输赢 + Tax int64 //税,不一定有值,只是作为一个临时变量使用 + StartCoin int64 //开始金币 + ClubPump int64 //俱乐部额外抽水 + IsRob bool //是否是机器人 + Platform string `json:"-"` + Channel string `json:"-"` + Promoter string `json:"-"` + PackageTag string `json:"-"` + InviterId int32 `json:"-"` + WBLevel int32 //黑白名单等级 +} + +type PCProp struct { + Id uint32 + TypeName string // 金币类型 + AreaType int32 // 所在区域 0平台上 1有效区 2无效区 3小车内 + CoinVal int64 // 金币面值 + X float32 + Y float32 + Z float32 + RotX float32 + RotY float32 + RotZ float32 +} + +// 推币机 +type PushingCoinRecord struct { + RoomId int // 房间id + RoomType int // 房间类型 + GameMode int // 游戏模式 + BaseScore int64 // 底分 + ShakeTimes int32 // 震动次数 + WallUpTimes int32 // 升墙次数 + EventTimes []int32 // 事件次数 + Props []*PCProp // 所有金币 +} + +type HuntingRecord struct { + RoomId int // 房间ID + BaseScore int // 底分 + SnId int32 // 玩家ID + StartCoin int64 // 下注前金额 + Coin int64 // 下注后金额 + ChangeCoin int64 // 金币变化 + CoinPool int64 // 爆奖金额 + Point int64 // 单线点数 + LineNum int64 // 线数 + BetCoin int64 // 下注金额 + WinCoin int64 // 产出金额 + Level int // 当前关卡 + Gain int64 // 翻牌奖励 +} + +// 对战三公 +type SanGongPVPType struct { + RoomId int32 //房间ID + RoomRounds int32 //建房局数 + RoomType int32 //房间类型 + NowRound int32 //当前局数 + BankId int32 //庄家ID + PlayerCount int //玩家数量 + BaseScore int32 //底分 + PlayerData []SanGongPVPPerson //玩家信息 + ClubRate int32 //俱乐部抽水比例 + IsSmartOperation bool //是否启用智能化运营 +} +type SanGongPVPPerson struct { + UserId int32 //玩家ID + UserIcon int32 //玩家头像 + ChangeCoin int64 //玩家得分 + Cardinfo []int32 //牌值 + IsWin int32 //输赢 + Tax int64 //税,不一定有值,只是作为一个临时变量使用 + ClubPump int64 //俱乐部额外抽水 + IsRob bool //是否是机器人 + Flag int //标识 + IsFirst bool + StartCoin int64 //开始金币 + Platform string `json:"-"` + Channel string `json:"-"` + Promoter string `json:"-"` + PackageTag string `json:"-"` + InviterId int32 `json:"-"` + WBLevel int32 //黑白名单等级 +} + +// 德州牛仔 +type DZNZCardInfo struct { + CardId int32 //手牌ID 牛仔 公共牌 公牛 + CardsInfo []int32 //扑克牌值 + CardsKind int32 //牌类型 +} +type DZNZZoneInfo struct { + RegionId int32 //13个下注区域 + IsWin int //边池输赢 + Rate float32 //倍数 + PlayerData []HundredPerson //玩家属性 + IsSmartOperation bool //是否启用智能化运营 +} +type DZNZHundredInfo struct { + CardData []DZNZCardInfo //发牌信息 + ZoneInfo []DZNZZoneInfo //每个下注区域信息 +} + +// 财运之神 +type FortuneZhiShenType struct { + //基本信息 + RoomId int //房间Id + BasicScore int32 //单注 + PlayerSnId int32 //玩家id + BeforeCoin int64 //下注前金额 + AfterCoin int64 //下注后金额 + ChangeCoin int64 //金额变化 + TotalBetCoin int64 //总押注 + TotalLine int32 //总线数(固定) + TotalWinCoin int64 //总派彩 + NowGameState int //当前游戏模式(0,1,2,3)普通/免费/停留旋转/停留旋转2 + NowNRound int //第几轮 + IsOffline int //0,1 正常(不显示)/掉线(显示) + FirstFreeTimes int //免费游戏剩余次数 + SecondFreeTimes int //停留旋转游戏剩余次数 + //中奖统计 + HitPrizePool []int64 //命中奖池(小奖|中奖|大奖|巨奖) + WinLineNum int //中奖线个数 + WinLineRate int64 //中奖线总倍率 + WinLineCoin int64 //中奖线派彩 + GemstoneNum int //宝石数量 + GemstoneWinCoin int64 //宝石派彩 + //详情 + Cards []int32 //元素顺序 横向 + GemstoneRateCoin []int64 //宝石金额 横向 + //中奖线详情 + WinLine []FortuneZhiShenWinLine + WBLevel int32 //黑白名单等级 + TaxCoin int64 //税收 +} +type FortuneZhiShenWinLine struct { + Id int //线号 + EleValue int32 //元素值 + Num int //数量 + Rate int64 //倍率 + WinCoin int64 //单线派彩 + WinFreeGame int //(0,1,2)旋转并停留*3/免费游戏*6/免费游戏*3 +} + +// 金鼓齐鸣记录详情 +type GoldDrumWinLineInfo struct { + EleValue int //元素值 + Rate int64 //倍率 + WinCoin int64 //单线派彩 + GameType int //(0,1,2)无/免费游戏/聚宝盆游戏 +} +type GoldDrumGameType struct { + //all + RoomId int32 //房间Id + BasicScore int32 //单注分 + PlayerSnid int32 //玩家id + BeforeCoin int64 //下注前金额 + AfterCoin int64 //下注后金额 + BetCoin int64 //下注金额 + WinCoin int64 //下注赢取金额总金额 + //Smallgamewinscore int64 //小游戏赢取的分数 + ChangeCoin int64 //本局游戏金额总变化 + FreeTimes int32 //免费转动次数 + AllWinNum int32 //中奖的线数 + HitPoolIdx int //下注索引 + Cards []int //15张牌 + + NowGameState int //当前游戏模式(0,1)普通/免费 + HitPrizePool []int64 //命中奖池(多喜小奖|多寿中奖|多禄大奖|多福巨奖) + WinLineRate int64 //中奖线总倍率 + WinLineCoin int64 //中奖线派彩 + WinLineInfo []GoldDrumWinLineInfo //中奖线详情 + + NowFreeGameTime int32 //当前免费游戏第几次 + CornucopiaCards []int32 //聚宝盆游戏数据 -1 未开启 0小将 1中奖 2大奖 3巨奖 + IsOffline bool //玩家是否掉线 true 掉线 + WBLevel int32 //黑白名单等级 + TaxCoin int64 //税收 +} + +// 金福报喜记录详情 +type CopperInfo struct { + Pos int32 //铜钱元素索引,从0开始 + Coin int64 //铜钱奖励金币 +} +type GoldBlessWinLineInfo struct { + EleValue int //元素值 + Rate int64 //倍率 + WinCoin int64 //单线派彩 + GameType int //(0,1,2,3)无/免费游戏/聚宝盆游戏/招福纳财游戏 +} +type GoldBlessGameType struct { + //all + RoomId int32 //房间Id + BasicScore int32 //单注分 + PlayerSnid int32 //玩家id + BeforeCoin int64 //下注前金额 + AfterCoin int64 //下注后金额 + BetCoin int64 //下注金额 + WinCoin int64 //本局总赢取金额 + //Smallgamewinscore int64 //小游戏赢取的分数 + ChangeCoin int64 //本局游戏金额总变化 + FreeTimes int32 //免费转动次数 + AllWinNum int32 //中奖的线数 + HitPoolIdx int //下注索引 + Cards []int //15张牌 + + NowGameState int //当前游戏模式(0,1,2)普通/免费/招福纳财 + HitPrizePool []int64 //命中奖池(多喜小奖|多寿中奖|多禄大奖|多福巨奖) + WinLineRate int64 //中奖线总倍率 + WinLineCoin int64 //中奖线派彩 + WinLineInfo []GoldBlessWinLineInfo //中奖线详情 + CopperNum int32 //本局铜钱数量 + CopperCoin int64 //本局铜钱金额 + CoppersInfo []CopperInfo //铜钱结构 + + NowFreeGameTime int32 //当前免费游戏第几次 + CornucopiaCards []int32 //聚宝盆游戏数据 -1 未开启 0小将 1中奖 2大奖 3巨奖 + IsOffline bool //玩家是否掉线 true 掉线 + WBLevel int32 //黑白名单等级 + TaxCoin int64 //税收 +} + +// 发发发 +type Classic888Type struct { + //基本信息 + RoomId int //房间Id + BasicScore int32 //单注 + PlayerSnId int32 //玩家id + BeforeCoin int64 //下注前金额 + AfterCoin int64 //下注后金额 + ChangeCoin int64 //金额变化 + TotalBetCoin int64 //总押注 + TotalLine int32 //总线数(固定) + TotalWinCoin int64 //总派彩 + NowGameState int //当前游戏模式(0,1,2)普通/免费/停留旋转 + NowNRound int //第几轮 + IsOffline int //0,1 正常(不显示)/掉线(显示) + FirstFreeTimes int //免费游戏剩余次数 + SecondFreeTimes int //停留旋转游戏剩余次数 + //中奖统计 + HitPrizePool []int64 //命中奖池(小奖|中奖|大奖|巨奖) + WinLineNum int //中奖线个数 + WinLineRate int64 //中奖线总倍率 + WinLineCoin int64 //中奖线派彩 + LanternNum int //灯笼数量 + LanternWinCoin int64 //灯笼派彩 + //详情 + Cards []int32 //元素顺序 横向 + LanternRateCoin []int64 //灯笼金额 横向 + //中奖线详情 + WinLine []Classic888WinLine + WBLevel int32 //黑白名单等级 + TaxCoin int64 //税收 +} +type Classic888WinLine struct { + Id int //线号 + EleValue int32 //元素值 + Num int //数量 + Rate int64 //倍率 + WinCoin int64 //单线派彩 + WinFreeGame int //(0,1,2,3)旋转并停留*3/免费游戏*6/免费游戏*9/免费游戏*15 +} + +// 多福 +type RichBlessedType struct { + //基本信息 + RoomId int //房间Id + BasicScore int32 //单注 + PlayerSnId int32 //玩家id + BeforeCoin int64 //下注前金额 + AfterCoin int64 //下注后金额 + ChangeCoin int64 //金额变化 + TotalBetCoin int64 //总押注 + TotalLine int32 //总线数(固定) + TotalWinCoin int64 //总派彩 + NowGameState int //当前游戏模式(0,1,2)普通/免费/jack小游戏 + NowNRound int //第几轮 + IsOffline int //0,1 正常(不显示)/掉线(显示) + FirstFreeTimes int //免费游戏剩余次数 + //中奖统计 + WinLineNum int //中奖线个数 + WinLineRate int64 //中奖线总倍率 + WinLineCoin int64 //中奖线派彩 + //详情 + Cards []int32 //普通游戏/免费游戏 + //jack游戏 + JackEleValue int32 //元素值 + JackMidCards []int64 //掀开位置 + //中奖线详情 + WinLine []RichBlessedWinLine + WBLevel int32 //黑白名单等级 + TaxCoin int64 //税收 + RealCtrl bool //人工调控 + WBState int32 //调控等级 + WeightKey int32 //当前使用权重 +} +type RichBlessedWinLine struct { + Id int //线号 + EleValue int32 //元素值 + Num int //数量 + Rate int64 //倍率 + WinCoin int64 //单线派彩 +} + +// 经典777 +type FruitsType struct { + //基本信息 + RoomId int //房间Id + BasicScore int32 //单注 + PlayerSnId int32 //玩家id + BeforeCoin int64 //下注前金额 + AfterCoin int64 //下注后金额 + ChangeCoin int64 //金额变化 + TotalBetCoin int64 //总押注 + TotalLine int32 //总线数(固定) + TotalWinCoin int64 //总派彩 + NowGameState int //当前游戏模式(0,1,2)普通/免费/小玛丽 + NowNRound int //第几轮 + IsOffline int //0,1 正常(不显示)/掉线(显示) + FirstFreeTimes int //免费游戏剩余次数 + MaryFreeTimes int //停留旋转游戏剩余次数 + //中奖统计 + HitPrizePool int64 //命中奖池金额 + WinLineNum int //中奖线个数 + WinLineRate int64 //中奖线总倍率 + WinLineCoin int64 //中奖线派彩 + JackPotNum int //777数量 + JackPotWinCoin int64 //777派彩 + //详情 + Cards []int32 //普通游戏/免费游戏 + //玛丽游戏 + MaryOutSide int32 //外圈 + MaryMidCards []int32 //内圈 + //中奖线详情 + WinLine []FruitsWinLine + WBLevel int32 //黑白名单等级 + TaxCoin int64 //税收 + RealCtrl bool //人工调控 + WBState int32 //调控等级 + WeightKey int32 //当前使用权重 +} +type FruitsWinLine struct { + Id int //线号 + EleValue int32 //元素值 + Num int //数量 + Rate int64 //倍率 + WinCoin int64 //单线派彩 + WinFreeGame int //(0,1,2,3,4,5)小玛丽1/小玛丽2/小玛丽3/免费5/免费8/免费10 +} + +// 无尽宝藏记录详情 +type EndlessTreasureWinLineInfo struct { + EleValue int //元素值 + Rate int64 //倍率 + WinCoin int64 //单线派彩 + GameType int //(0,1,2,3)无/免费游戏/聚宝盆游戏/节节高游戏 +} +type EndlessTreasureGameType struct { + //all + RoomId int32 //房间Id + TotalBetScore int32 //总押注 + BasicScore float32 //单注分 + PlayerSnid int32 //玩家id + BeforeCoin int64 //下注前金额 + AfterCoin int64 //下注后金额 + BetCoin int64 //下注金额 + WinCoin int64 //本局总赢取金额 + ChangeCoin int64 //本局游戏金额总变化 + FreeTimes int32 //免费转动次数 + AllWinNum int32 //中奖的线数 + Cards []int //15张牌 + + NowGameState int //当前游戏模式(0,1,2)普通/免费/节节高 + HitPrizePool []int64 //命中奖池(小奖|中奖|大奖|巨奖) + WinLineRate int64 //中奖线总倍率 + WinLineCoin int64 //中奖线派彩 + WinLineInfo []EndlessTreasureWinLineInfo //中奖线详情 + CopperNum int32 //本局铜钱数量 + CopperCoin int64 //本局铜钱金额 + CoppersInfo []CopperInfo //铜钱结构 + + NowFreeGameTime int32 //当前免费游戏第几次 + IsOffline bool //玩家是否掉线 true 掉线 + AddFreeTimes int32 //本局新增免费转动次数 + WBLevel int32 //黑白名单等级 + TaxCoin int64 //税收 +} + +// 拉霸类游戏 基础牌局记录 +type SlotBaseResultType struct { + RoomId int32 //房间Id + BasicBet int32 //基本分(单注金额) + PlayerSnid int32 //玩家id + BeforeCoin int64 //下注前金额 + AfterCoin int64 //下注后金额 + ChangeCoin int64 //金额变化 + IsFirst bool //是否第一次玩游戏 + IsFree bool //是否免费 + TotalBet int32 //总押注金额 + WinRate int32 //中奖的倍率 + FreeTimes int32 //免费转动次数 + AllWinNum int32 //中奖的总线数 + Tax int64 //暗税 + WBLevel int32 //黑白名单等级 + SingleFlag int32 //0不控1单控赢2单控输 + WinLineScore int64 //中奖线赢取分数 + WinJackpot int64 //奖池赢取分数 + WinSmallGame int64 //小游戏赢取分数 + WinTotal int64 //本次游戏总赢取(本次游戏赢取总金额=中奖线赢取+奖池赢取+小游戏赢取) + Cards []int32 //15张牌 + IsFoolPlayer bool //是否是新手 +} + +// 小火箭游戏 每局记录 +type SmallRocketBaseResultType struct { + //all + RoomId int32 //房间Id + TotalBetVal int64 //总押注 + PlayerSnid int32 //玩家id + BeforeCoin int64 //下注前金额 + AfterCoin int64 //下注后金额 + WinCoin int64 //本局总赢取金额 + + BetCoin1 int64 //下注金额1 + BetMul1 float64 //下注倍数1 + IsAutoBetAndTake1 bool //自动领取1 + TakeBetMul1 float64 //提款倍数1 + BetCoin2 int64 //下注金额2 + BetMul2 float64 //下注倍数2 + IsAutoBetAndTake2 bool //自动领取2 + TakeBetMul2 float64 //提款倍数2 + + TaxCoin int64 //税收 +} + +type GameResultLog struct { + BaseResult *SlotBaseResultType + AllLine int32 //线路数 + UserName string //昵称 + WinLines []int //赢分的线 + BetLines []int64 //下注的线 +} + +// 幸运骰子 +type LuckyDiceType struct { + RoomId int32 //房间Id + RoundId int32 //局数编号 + BaseScore int32 //底分 + PlayerSnid int32 //玩家id + UserName string //昵称 + BeforeCoin int64 //本局前金额 + AfterCoin int64 //本局后金额 + ChangeCoin int64 //金额变化 + Bet int64 //总押注数 + Refund int64 //返还押注数 + Award int64 //获奖金额 + BetSide int32 //压大压小 0大 1小 + Dices []int32 //3个骰子值 + Tax int64 //赢家税收 + WBLevel int32 //黑白名单等级 +} + +type CandyType struct { + RoomId int32 //房间Id + SpinID int32 //局数编号 + BasicScore int32 //基本分 + PlayerSnid int32 //玩家id + BeforeCoin int64 //下注前金额 + AfterCoin int64 //下注后金额 + ChangeCoin int64 //金额变化 + Score int32 //总押注数 + Tax int64 //暗税 + IsFirst bool + AllWinNum int32 //中奖的线数 + WinScore int32 //中奖的倍率 + AllLine int32 //线路数 + Cards []int32 //9张牌 + BetLines []int64 //下注的线 + WBLevel int32 //黑白名单等级 + UserName string // 昵称 + TotalPriceValue int64 // 总赢分 + WinLines []int // 赢分的线 + WinJackpot int64 // 赢奖池分数 +} +type MiniPokerType struct { + RoomId int32 //房间Id + SpinID int32 //局数编号 + BasicScore int32 //基本分 + PlayerSnid int32 //玩家id + BeforeCoin int64 //下注前金额 + AfterCoin int64 //下注后金额 + ChangeCoin int64 //金额变化 + Score int32 //总押注数 + Tax int64 //暗税 + IsFirst bool + WinScore int32 //中奖的倍率 + Cards []int32 //5张牌 + WBLevel int32 //黑白名单等级 + UserName string // 昵称 + TotalPriceValue int64 // 总赢分 + WinJackpot int64 // 赢奖池分数 +} +type CaoThapType struct { + RoomId int32 //房间Id + BasicScore int32 //基本分 + PlayerSnid int32 //玩家id + BeforeCoin int64 //下注前金额 + AfterCoin int64 //下注后金额 + ChangeCoin int64 //金额变化 + Score int32 //总押注数 + Tax int64 //暗税 + IsFirst bool + Cards []int32 //翻的牌 + WBLevel int32 //黑白名单等级 + UserName string // 昵称 + TotalPriceValue int64 // 总赢分 + WinJackpot int64 // 赢奖池分数 + BetInfo []CaoThapBetInfo // 每次下注信息 +} +type CaoThapBetInfo struct { + TurnID int32 // 操作ID + TurnTime int64 // 操作时间 + BetValue int64 // 下注金额 + Card int32 // 牌值 + PrizeValue int64 // 赢分 +} + +// 21点 +type BlackJackType struct { + RoomId int32 //房间ID + RoomType int32 //房间类型 + NumOfGames int //当前局数 + PlayerCount int //玩家数量 + PlayerData []*BlackJackPlayer //玩家信息 + BankerCards []int32 //庄家牌 + BankerCardType int32 //牌型 1:黑杰克 2:五小龙 3:其它点数 4:爆牌 + BankerCardPoint []int32 //点数 + BetCoin int64 //总下注 + GainCoinTax int64 //总输赢分(税前) +} + +type BlackJackCardInfo struct { + Cards []int32 //闲家牌 + CardType int32 //牌型 1:黑杰克 2:五小龙 3:其它点数 4:爆牌 + CardPoint []int32 //点数 + BetCoin int64 //下注 + GainCoinNoTax int64 //总输赢分(税后) + IsWin int32 //输赢 1赢 0平 -1输 +} + +type BlackJackPlayer struct { + UserId int32 //玩家ID + UserIcon int32 //玩家头像 + Platform string `json:"-"` + Channel string `json:"-"` + Promoter string `json:"-"` + PackageTag string `json:"-"` + InviterId int32 `json:"-"` + WBLevel int32 //黑白名单等级 + IsRob bool //是否是机器人 + Flag int //标识 + IsFirst bool //是否第一次 + Hands []BlackJackCardInfo //牌值 + IsWin int32 //输赢 + GainCoinNoTax int64 //总输赢分(税后) + Tax int64 //税,不一定有值,只是作为一个临时变量使用 + BaoCoin int64 //保险金 + BaoChange int64 //保险金输赢分 + BetCoin int64 //下注额 + BetChange int64 //下注输赢分 + Seat int //座位号 +} + +type DezhouPots struct { + BetTotal int64 //边池下注 + Player []DezhouPotPlayer //边池的玩家 +} +type DezhouPotPlayer struct { + Snid int32 //玩家ID + IsWin int32 //边池输赢 +} + +// 德州牌局记录 +type DeZhouUserOp struct { + Snid int32 // 操作人 + Op int32 // 操作类型 见 dezhoupoker.proto + Stage int // 所处牌局阶段 见 constants.go + Chip int64 // 操作筹码, (不下注为0) + ChipOnTable int64 // 操作后桌子上筹码 + Round int32 // 轮数 + Sec float64 // 操作时距离本局开始时的秒数 + TargetId int32 // 操作对象ID(没其他玩家为对象为0) +} + +// 德州 +type DezhouType struct { + RoomId int32 //房间ID + RoomType int32 //房间类型 + NumOfGames int32 //当前局数 + BankId int32 //庄家ID + PlayerCount int //玩家数量 + BaseScore int32 //底分 + BaseCards []int32 //公牌 只限于德州用 + PlayerData []DezhouPerson //玩家信息 + Pots []DezhouPots //边池情况 + Actions string //牌局记录 + UserOps []*DeZhouUserOp //牌局记录new +} +type DezhouPerson struct { + UserId int32 //玩家ID + UserIcon int32 //玩家头像 + Platform string `json:"-"` + Channel string `json:"-"` + Promoter string `json:"-"` + PackageTag string `json:"-"` + InviterId int32 `json:"-"` + WBLevel int32 //黑白名单等级 + IsRob bool //是否是机器人 + IsFirst bool //是否第一次 + IsLeave bool //中途离开 + InitCard []int32 //初始牌值 + Cardinfo []int32 //牌值 + IsWin int32 //输赢 + GainCoinNoTax int64 //总输赢分(税后) + Tax int64 //税,不一定有值,只是作为一个临时变量使用 + BetTotal int64 //用户当局总下注 + IsAllIn bool //是否全下 + RoundFold int32 //第几轮弃牌 + CardInfoEnd []int32 //结算时的牌型 + Seat int //座位号 +} + +// tienlen +type TienLenType struct { + GameId int //游戏id + BaseScore int32 //底分 + PlayerData []TienLenPerson //玩家信息 +} + +type TienLenPerson struct { + UserId int32 //玩家ID + IsRob bool //是否是机器人 + BillCoin int64 //最终得分(税后) + BillTaxCoin int64 //最终税收 + + BombCoin int64 //炸弹输赢分(税后) + BombTaxCoin int64 //炸弹税收 + CardInfoEnd []int32 //结算时的牌型 +} + +// chesstitians +type ChesstitiansType struct { + GameId int //游戏id + RoomId int32 //房间ID + RoomType int32 //房间类型 + NumOfGames int32 //当前局数 + BankId int32 //房主ID + PlayerCount int //玩家数量 + BaseScore int32 //底分 + TaxRate int32 //税率(万分比) + PlayerData []*ChesstitiansPerson //玩家信息 + RoomMode int +} +type ChesstitiansPerson struct { + UserId int32 //玩家ID + UserIcon int32 //玩家头像 + Platform string `json:"-"` + Channel string `json:"-"` + Promoter string `json:"-"` + PackageTag string `json:"-"` + InviterId int32 `json:"-"` + WBLevel int32 //黑白名单等级 + IsRob bool //是否是机器人 + IsFirst bool //是否第一次 + IsLeave bool //中途离开 + IsWin int32 //输赢 + Seat int //座位号 + GainCoin int64 //手牌输赢分(税后) + GainTaxCoin int64 //手牌税收 +} + +// tala +type TaLaType struct { + GameId int //游戏id + RoomId int32 //房间ID + RoomType int32 //房间类型 + NumOfGames int32 //当前局数 + BankId int32 //房主ID + PlayerCount int //玩家数量 + BaseScore int32 //底分 + TaxRate int32 //税率(万分比) + RoomMode int + PlayerData []TaLaPerson //玩家信息 +} +type TaLaPerson struct { + UserId int32 //玩家ID + UserIcon int32 //玩家头像 + Platform string `json:"-"` + Channel string `json:"-"` + Promoter string `json:"-"` + PackageTag string `json:"-"` + InviterId int32 `json:"-"` + WBLevel int32 //黑白名单等级 + IsRob bool //是否是机器人 + IsFirst bool //是否第一次 + IsLeave bool //中途离开 + Seat int //座位号 + ChiCoin int64 //吃输赢分(税后) + BillCoin int64 //最终得分(税后) + ChiTaxCoin int64 //吃税收 + BillTaxCoin int64 //最终税收 + IsHu bool //胡 + IsWin int32 //胜负 0平 1胜 2负 + IsLoseHu bool //包赔 + Phoms [][]int32 //phom + IsNoPhom bool //瘪 + Cards []int32 //手牌 + CardsValue int32 //点数 + OpPhom []int32 //寄 + TaLaPersonOp []TaLaPersonOp //操作信息 +} +type TaLaPersonOp struct { + Round int32 + MoCard int32 + ChuCard int32 + ChiCard int32 + Cards []int32 +} + +// samloc +type SamLocType struct { + GameId int //游戏id + RoomId int32 //房间ID + RoomType int32 //房间类型 + NumOfGames int32 //当前局数 + BankId int32 //房主ID + PlayerCount int //玩家数量 + BaseScore int32 //底分 + TaxRate int32 //税率(万分比) + PlayerData []SamLocPerson //玩家信息 + RoomMode int +} +type SamLocPerson struct { + UserId int32 //玩家ID + UserIcon int32 //玩家头像 + Platform string `json:"-"` + Channel string `json:"-"` + Promoter string `json:"-"` + PackageTag string `json:"-"` + InviterId int32 `json:"-"` + WBLevel int32 //黑白名单等级 + IsRob bool //是否是机器人 + IsFirst bool //是否第一次 + IsLeave bool //中途离开 + IsWin int32 //输赢 + Seat int //座位号 + GainCoin int64 //手牌输赢分(税后) + BombCoin int64 //炸弹输赢分(税后) + BillCoin int64 //最终得分(税后) + GainTaxCoin int64 //手牌税收 + BombTaxCoin int64 //炸弹税收 + BillTaxCoin int64 //最终税收 + DelOrderCards map[int][]int32 //已出牌 + CardInfoEnd []int32 //结算时的牌型 + IsTianHu bool //是否天胡 +} + +// 娃娃机 每局记录 +type ClawdollResultType struct { + //all + RoomId int32 //房间Id + MachineId int32 //娃娃机Id + PlayerSnid int32 //玩家id + BeforeClawdollItemNum int64 //变化前娃娃币 + AfterClawdollItemNum int64 //变化后娃娃币 + IsWin bool //是否成功 + Channel string //渠道 + Name string //场次名字 +} diff --git a/statistics/task/task/gamerate.go b/statistics/task/task/gamerate.go new file mode 100644 index 0000000..1fbf2de --- /dev/null +++ b/statistics/task/task/gamerate.go @@ -0,0 +1,110 @@ +package task + +import ( + "encoding/json" + "go.mongodb.org/mongo-driver/bson" + "mongo.games.com/goserver/core/logger" + "slices" +) + +// 场次平均倍数 + +func PlayerGameRate(plt string, startTime, endTime string, gamefreeid int) (total, bombTotal, remain2Total int, rateAvg, bombRateAvg float64, err error) { + var totalRate, totalBombRate float64 + err = GameDetailFunc(plt, startTime, endTime, gamefreeid, func(data bson.M) error { + rate, isBomb, bombRate, remain2 := GameDetailRate(data) + total++ + if isBomb { + bombTotal++ + } + totalRate += rate + totalBombRate += bombRate + if remain2 { + remain2Total++ + } + return nil + }) + if total > 0 { + rateAvg = totalRate / float64(total) + } + if bombTotal > 0 { + bombRateAvg = totalBombRate / float64(bombTotal) + } + return +} + +// rate 赢分/底分 +// isBomb 是否有炸弹 +// bombRate 炸弹倍数,炸弹赢分/底分 +// remain2 是否有剩余2 +func GameDetailRate(data bson.M) (rate float64, isBomb bool, bombRate float64, remain2 bool) { + if data == nil { + return + } + gameid := data["gameid"].(int32) + gamefreeid := data["gamefreeid"].(int32) + logger.Logger.Tracef("GameDetail gameid:%d, gamefreeid:%d", gameid, gamefreeid) + + detail := data["gamedetailednote"] + if detail == nil { + return + } + + raw := new(RabbitMQDataRaw) + if err := json.Unmarshal([]byte(detail.(string)), raw); err != nil { + logger.Logger.Errorf("GameDetailCount Unmarshal 1 error:%v %v", err, gameid) + return + } + + switch gameid { + case 207, 208, 209, 210, 240, 241, 242, 243, 244, 245, 246, 247: // tienlen + d := new(TienLenType) + b, err := json.Marshal(raw.Data) + if err != nil { + logger.Logger.Errorf("GameDetailCount Marshal error:%v %v", err, gameid) + return + } + if err := json.Unmarshal(b, d); err != nil { + logger.Logger.Errorf("GameDetailCount Unmarshal 2 error:%v %v", err, gameid) + return + } + + for _, v := range d.PlayerData { + if v.BillCoin > 0 { + rate = float64(v.BillCoin+v.BillTaxCoin) / float64(d.BaseScore) + } + if v.BombCoin > 0 { + isBomb = true + bombRate = float64(v.BombCoin+v.BombTaxCoin) / float64(d.BaseScore) + } + if slices.ContainsFunc(v.CardInfoEnd, func(i int32) bool { + switch i { + case 51, 38, 25, 12: + return true + } + return false + }) { + remain2 = true + } + } + + case 211, 212, 213, 214: + d := new(ThirteenWaterType) + b, err := json.Marshal(raw.Data) + if err != nil { + logger.Logger.Errorf("GameDetailCount Marshal error:%v %v", err, gameid) + return + } + if err := json.Unmarshal(b, d); err != nil { + logger.Logger.Errorf("GameDetailCount Unmarshal 2 error:%v %v", err, gameid) + return + } + + for _, v := range d.PlayerData { + if v.AllScore > 0 { + rate = float64(v.AllScore) / float64(d.BaseScore) + } + } + } + return +} diff --git a/statistics/task/task/gametime.go b/statistics/task/task/gametime.go new file mode 100644 index 0000000..3c184c7 --- /dev/null +++ b/statistics/task/task/gametime.go @@ -0,0 +1,104 @@ +package task + +import ( + "context" + "errors" + "fmt" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" + "go.mongodb.org/mongo-driver/mongo/options" + "mongo.games.com/game/common" + mongomodel "mongo.games.com/game/statistics/modelmongo" + "mongo.games.com/goserver/core/logger" + mymongo "mongo.games.com/goserver/core/mongox" +) + +// 新用户平均游戏时长 + +// 返回 总游戏时长,总局数,错误 +func NewPlayerGameTime(plt string, ids []int, startTime, endTime string, gamefreeid int) (int, int, error) { + s, e := common.StrRFC3339TimeToTime(startTime), common.StrRFC3339TimeToTime(endTime) + c, err := mymongo.GetLogCollection(plt, mongomodel.LogGamePlayerListLog) + if err != nil { + return 0, 0, err + } + + c2, err := mymongo.GetLogCollection(plt, "log_gamedetailed") + if err != nil { + return 0, 0, err + } + + var ret int + var total int + for _, v := range ids { + // 查询玩家游戏时长 + where := bson.M{"snid": v, "time": bson.M{"$gte": s, "$lt": e}} + if gamefreeid > 0 { + where["gamefreeid"] = gamefreeid + } + cur, err := c.Find(context.TODO(), where, options.Find().SetProjection(bson.M{"gamedetailedlogid": 1})) + if err != nil { + logger.Logger.Errorf("find player gamedetailedlogid get err: %v", err) + return 0, 0, err + } + for cur.TryNext(context.TODO()) { + var vv struct{ Gamedetailedlogid string } + if err = cur.Decode(&vv); err != nil { + logger.Logger.Errorf("find player gamedetailedlogid decode err: %v", err) + cur.Close(context.Background()) + return 0, 0, err + } + // 查询游戏时长 + var res2 struct{ Gametiming int } + r := c2.FindOne(context.TODO(), bson.M{"logid": vv.Gamedetailedlogid}, options.FindOne().SetProjection(bson.M{"gametiming": 1})) + if r.Err() != nil && !errors.Is(r.Err(), mongo.ErrNoDocuments) { + logger.Logger.Errorf("find game time get err: %v", err) + cur.Close(context.Background()) + return 0, 0, err + } + if err := r.Decode(&res2); err != nil { + logger.Logger.Errorf("find game time decode err: %v", err) + cur.Close(context.Background()) + return 0, 0, err + } + ret += res2.Gametiming + total++ + } + cur.Close(context.Background()) + } + + return ret, total, nil +} + +// NewPlayerGameTimeAvg 新用户平均游戏时长 +// 新用户平均游戏时长(不算大厅时间):当天注册的玩家在房间中的总时长/当天注册总人数 +// 返回 参与人数,游戏时长 +func NewPlayerGameTimeAvg(plt string, startTime, endTime string, gamefreeid int) (int, int, error) { + s, e := common.StrRFC3339TimeToTime(startTime), common.StrRFC3339TimeToTime(endTime) + if s.IsZero() || e.IsZero() { + return 0, 0, fmt.Errorf("time format error") + } + ids, err := GetNewPayerIds(plt, startTime, endTime) + if err != nil { + return 0, 0, err + } + if len(ids) == 0 { + return 0, 0, nil + } + a, _, err := NewPlayerGameTime(plt, ids, startTime, endTime, gamefreeid) + if err != nil { + return 0, 0, err + } + if len(ids) == 0 { + return 0, 0, nil + } + + b, err := PlayingGameCount(plt, ids, startTime, endTime, gamefreeid) + if err != nil { + return 0, 0, err + } + if b == 0 { + return 0, 0, nil + } + return b, a, err +} diff --git a/statistics/task/task/rechargeoffline.go b/statistics/task/task/rechargeoffline.go new file mode 100644 index 0000000..fe31c2d --- /dev/null +++ b/statistics/task/task/rechargeoffline.go @@ -0,0 +1,62 @@ +package task + +import ( + "context" + "fmt" + "go.mongodb.org/mongo-driver/mongo/options" + + "go.mongodb.org/mongo-driver/bson" + "mongo.games.com/game/common" + mymongo "mongo.games.com/goserver/core/mongox" +) + +type RechargeOfflineData struct { + Snid int32 + Coin int64 +} + +func OfflineCoin(plt string, startTime, endTime string) (res []*RechargeOfflineData, err error) { + s, e := common.StrRFC3339TimeToTime(startTime), common.StrRFC3339TimeToTime(endTime) + if s.IsZero() || e.IsZero() { + return nil, fmt.Errorf("time format error") + } + c, err := mymongo.GetLogCollection(plt, "log_dbshop") + if err != nil { + return nil, err + } + cur, err := c.Find(context.TODO(), bson.M{"ts": bson.M{"$gte": s.Unix(), "$lt": e.Unix()}, "consume": 3, "state": 1}) + if err != nil { + return nil, err + } + defer cur.Close(context.Background()) + + var list []struct{ Snid int32 } + if err = cur.All(context.Background(), &list); err != nil { + return nil, err + } + + snids := map[int32]struct{}{} + + for _, v := range list { + if _, ok := snids[v.Snid]; ok { + continue + } + snids[v.Snid] = struct{}{} + + // 最后金币数量 + c, err := mymongo.GetLogCollection(plt, "log_coinex") + if err != nil { + return nil, err + } + one := c.FindOne(context.TODO(), bson.M{"snid": v.Snid, "cointype": 0, "ts": bson.M{"$lt": e.Unix()}}, options.FindOne().SetSort(bson.M{"ts": -1})) + if one.Err() != nil { + return nil, one.Err() + } + var data struct{ Restcount int64 } + if err = one.Decode(&data); err != nil { + return nil, err + } + res = append(res, &RechargeOfflineData{Snid: v.Snid, Coin: data.Restcount}) + } + return +} diff --git a/statistics/task/task/robotwin.go b/statistics/task/task/robotwin.go new file mode 100644 index 0000000..37fa8cf --- /dev/null +++ b/statistics/task/task/robotwin.go @@ -0,0 +1,138 @@ +package task + +import ( + "encoding/json" + "go.mongodb.org/mongo-driver/bson" + "mongo.games.com/goserver/core/logger" + "sort" +) + +// RobotWinRate 机器人胜利 +// 返回 玩家胜利局数,总局数 +func RobotWinRate(plt string, startTime, endTime string, gamefreeid int) (a, b int, err error) { + err = GameDetailFunc(plt, startTime, endTime, gamefreeid, func(data bson.M) error { + isPlayerWin, to := GameDetailRobot(data) + if isPlayerWin { + a++ + } + b += to + return nil + }) + return +} + +func GameDetailRobot(data bson.M) (isPlayerWin bool, to int) { + if data == nil { + return + } + gameid := data["gameid"].(int32) + gamefreeid := data["gamefreeid"].(int32) + logger.Logger.Tracef("GameDetailRobot gameid:%d, gamefreeid:%d", gameid, gamefreeid) + + detail := data["gamedetailednote"] + if detail == nil { + return + } + + raw := new(RabbitMQDataRaw) + if err := json.Unmarshal([]byte(detail.(string)), raw); err != nil { + logger.Logger.Errorf("GameDetailRobot Unmarshal 1 error:%v %v", err, gameid) + return + } + + switch gameid { + case 207, 208, 209, 210, 240, 241, 242, 243, 244, 245, 246, 247: // tienlen + data := new(TienLenType) + b, err := json.Marshal(raw.Data) + if err != nil { + logger.Logger.Errorf("GameDetailCount Marshal error:%v %v", err, gameid) + return + } + if err := json.Unmarshal(b, data); err != nil { + logger.Logger.Errorf("GameDetailCount Unmarshal 2 error:%v %v", err, gameid) + return + } + + var has, hasPlayer bool + for _, v := range data.PlayerData { + if v.IsRob { + has = true + } + if !v.IsRob { + hasPlayer = true + } + } + if !has || !hasPlayer { + // 没有机器人 + return + } + + sort.Slice(data.PlayerData, func(i, j int) bool { + a, b := data.PlayerData[i].BillCoin+data.PlayerData[i].BillTaxCoin, data.PlayerData[j].BillCoin+data.PlayerData[j].BillTaxCoin + if a != b { + return a > b + } + if data.PlayerData[i].IsRob != data.PlayerData[j].IsRob { + return !data.PlayerData[i].IsRob + } + return data.PlayerData[i].UserId < data.PlayerData[j].UserId + }) + + for k, v := range data.PlayerData { + if !v.IsRob && v.BillCoin > 0 && k <= 1 { + isPlayerWin = true + break + } + } + + to = 1 + + case 211, 212, 213, 214: + data := new(ThirteenWaterType) + b, err := json.Marshal(raw.Data) + if err != nil { + logger.Logger.Errorf("GameDetailCount Marshal error:%v %v", err, gameid) + return + } + if err := json.Unmarshal(b, data); err != nil { + logger.Logger.Errorf("GameDetailCount Unmarshal 2 error:%v %v", err, gameid) + return + } + + var has, hasPlayer bool + for _, v := range data.PlayerData { + if v.IsRob { + has = true + } + if !v.IsRob { + hasPlayer = true + } + } + if !has || !hasPlayer { + // 没有机器人 + return + } + + sort.Slice(data.PlayerData, func(i, j int) bool { + a, b := data.PlayerData[i].AllScore, data.PlayerData[j].AllScore + if a != b { + return a > b + } + if data.PlayerData[i].IsRob != data.PlayerData[j].IsRob { + return !data.PlayerData[i].IsRob + } + return data.PlayerData[i].UserId < data.PlayerData[j].UserId + }) + + for k, v := range data.PlayerData { + if !v.IsRob && v.AllScore > 0 && k <= 1 { + isPlayerWin = true + break + } + } + + to = 1 + } + + return +} From fd43d57ca4612c0a2669a0ce3ef2cc40972ef649 Mon Sep 17 00:00:00 2001 From: tomas Date: Tue, 3 Dec 2024 14:14:12 +0800 Subject: [PATCH 29/41] fix betmode --- gamesrv/fortunedragon/scenepolicy_fortunedragon.go | 1 + 1 file changed, 1 insertion(+) diff --git a/gamesrv/fortunedragon/scenepolicy_fortunedragon.go b/gamesrv/fortunedragon/scenepolicy_fortunedragon.go index 59b2784..c2041a1 100644 --- a/gamesrv/fortunedragon/scenepolicy_fortunedragon.go +++ b/gamesrv/fortunedragon/scenepolicy_fortunedragon.go @@ -409,6 +409,7 @@ func (this *SceneStateStartFortuneDragon) OnPlayerOp(s *base.Scene, p *base.Play if err == nil { s.SetGameNowTime(time.Now()) data = assemble.DataToCli(Response).(assemble.GameEnd) + data.Results[0].BetMode = playerEx.BetMode if data.Results[0].FreeStatus == 1 || data.Results[0].FreeNumMax == 0 { //logger.Logger.Trace("=====================AddCoin=====TotalBet===", -data.TotalBet) //第一次触发或者正常模式 From 9354ada850308ee1fbe0dcf482d19abcd773e7b4 Mon Sep 17 00:00:00 2001 From: tomas Date: Tue, 3 Dec 2024 14:14:12 +0800 Subject: [PATCH 30/41] fix betmode --- gamesrv/fortunedragon/scenepolicy_fortunedragon.go | 1 + 1 file changed, 1 insertion(+) diff --git a/gamesrv/fortunedragon/scenepolicy_fortunedragon.go b/gamesrv/fortunedragon/scenepolicy_fortunedragon.go index 59b2784..c2041a1 100644 --- a/gamesrv/fortunedragon/scenepolicy_fortunedragon.go +++ b/gamesrv/fortunedragon/scenepolicy_fortunedragon.go @@ -409,6 +409,7 @@ func (this *SceneStateStartFortuneDragon) OnPlayerOp(s *base.Scene, p *base.Play if err == nil { s.SetGameNowTime(time.Now()) data = assemble.DataToCli(Response).(assemble.GameEnd) + data.Results[0].BetMode = playerEx.BetMode if data.Results[0].FreeStatus == 1 || data.Results[0].FreeNumMax == 0 { //logger.Logger.Trace("=====================AddCoin=====TotalBet===", -data.TotalBet) //第一次触发或者正常模式 From 3f35e67a404ee631621c1c9c62a150a573a8759b Mon Sep 17 00:00:00 2001 From: sk <123456@qq.com> Date: Tue, 3 Dec 2024 15:08:08 +0800 Subject: [PATCH 31/41] =?UTF-8?q?=E5=88=9B=E5=BB=BA=E6=B8=B8=E6=88=8F?= =?UTF-8?q?=E5=AF=B9=E5=B1=80=E8=AE=B0=E5=BD=95=E7=BC=93=E5=AD=98=E5=AF=B9?= =?UTF-8?q?=E8=B1=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gamesrv/base/divisionsystem.go | 6 - gamesrv/base/gamedetail.go | 255 ++++++++++++++++++++++++ gamesrv/base/gamewarning.go | 42 ---- gamesrv/base/handredJacklistmgr.go | 300 ----------------------------- gamesrv/base/player.go | 17 +- gamesrv/base/scene.go | 157 --------------- 6 files changed, 270 insertions(+), 507 deletions(-) delete mode 100644 gamesrv/base/divisionsystem.go create mode 100644 gamesrv/base/gamedetail.go delete mode 100644 gamesrv/base/handredJacklistmgr.go diff --git a/gamesrv/base/divisionsystem.go b/gamesrv/base/divisionsystem.go deleted file mode 100644 index f63a62c..0000000 --- a/gamesrv/base/divisionsystem.go +++ /dev/null @@ -1,6 +0,0 @@ -package base - -// 提供税收和流水,根据代理需求后台进行分账 -func ProfitDistribution(p *Player, tax, taxex, validFlow int64) { - //LogChannelSingleton.WriteMQData(model.GenerateTaxDivide(p.SnId, p.Platform, p.Channel, p.BeUnderAgentCode, p.PackageID, tax, taxex, validFlow, p.scene.GameId, p.scene.GameMode, p.scene.GetDBGameFree().GetId(), p.PromoterTree)) -} diff --git a/gamesrv/base/gamedetail.go b/gamesrv/base/gamedetail.go new file mode 100644 index 0000000..9b43209 --- /dev/null +++ b/gamesrv/base/gamedetail.go @@ -0,0 +1,255 @@ +package base + +import ( + "time" + + "github.com/globalsign/mgo/bson" + + "mongo.games.com/game/model" + "mongo.games.com/game/mq" +) + +/* + 记录游戏对局记录 +*/ + +type SaveGameDetailedParam struct { + LogId string // 日志id + Detail string // 游戏详细信息 + GameTime int64 // 游戏时长 + Trend20Lately string // 最近20局开奖结果 + CtrlType int // 调控类型 1控赢 2控输 + PlayerPool map[int]int // 个人水池分 + OnlyLog bool // 只返回日志,不保存 +} + +// SaveGameDetailedLog 保存游戏详细记录 +func (this *Scene) SaveGameDetailedLog(param *SaveGameDetailedParam) *SaveGameDetailedCopy { + if this == nil || param == nil { + return nil + } + + if param.GameTime <= 0 { + param.GameTime = int64(time.Now().Sub(this.GameNowTime).Seconds()) + } + + if param.GameTime < 0 { + param.GameTime = 0 + } + + now := time.Now() + + var ret SaveGameDetailedCopy + ret.Param = param + 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 + } + if param.OnlyLog { + ret.Log = append(ret.Log, log) + } else { + 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) + } + return &ret +} + +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 // 游戏时长 + OnlyLog bool // 只返回日志,不保存 +} + +// SaveGamePlayerListLog 保存玩家对局记录 +func (this *Scene) SaveGamePlayerListLog(param *SaveGamePlayerListLogParam) *SaveGamePlayerListLogCopy { + if this == nil { + return nil + } + if param == nil { + return nil + } + + p := this.GetPlayer(param.Snid) + if p == nil { + return nil + } + + if param.PlayerName == "" { + param.PlayerName = p.Name + } + + var ret SaveGamePlayerListLogCopy + ret.Param = param + + baseScore := this.GetBaseScore() + + // 上报玩家游戏记录 + if !p.IsRob && (param.IsFree || param.TotalIn != 0 || param.TotalOut != 0) { + e := p.ReportGameEvent(&ReportGameEventParam{ + Tax: param.TaxCoin, + Change: param.WinAmountNoAnyTax, + In: param.TotalIn, + Out: param.TotalOut, + GameTime: param.GameTime, + OnlyLog: param.OnlyLog, + }) + if e != nil { + ret.UpLog = e + } + } + + // 保存玩家游戏日志 + 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, + } + if param.OnlyLog { + ret.Log = append(ret.Log, log) + } else { + mq.Write(log) + } + return &ret +} + +// SaveGamePlayerListLogCopy 临时记录 +// 为了拉霸统计游戏时长,需要临时缓存游戏记录 +type SaveGamePlayerListLogCopy struct { + Param *SaveGamePlayerListLogParam + Log []*model.GamePlayerListLog + UpLog *ReportGameEventOnly // mq上报数据 +} + +func (s *SaveGamePlayerListLogCopy) Save() { + for _, v := range s.Log { + mq.Write(v) + } + if s.UpLog != nil { + for _, v := range s.UpLog.Log { + mq.Write(v, mq.BackGameRecord) + } + } +} + +// SaveGameDetailedCopy 临时记录 +// 为了拉霸统计游戏时长,需要临时缓存游戏记录 +type SaveGameDetailedCopy struct { + Param *SaveGameDetailedParam + Log []*model.GameDetailedLog +} + +func (s *SaveGameDetailedCopy) Save() { + for _, v := range s.Log { + mq.Write(v) + } +} + +// LabaLog 拉霸缓存游戏记录 +type LabaLog struct { + PlayerListLog *SaveGamePlayerListLogCopy + GameDetailLog *SaveGameDetailedCopy +} + +// Cache 临时缓存 +func (l *LabaLog) Cache(s *Scene, detailLog *SaveGameDetailedParam, playerListLog *SaveGamePlayerListLogParam) { + if s == nil { + return + } + detailLog.OnlyLog = true + playerListLog.OnlyLog = true + l.GameDetailLog = s.SaveGameDetailedLog(detailLog) + l.PlayerListLog = s.SaveGamePlayerListLog(playerListLog) +} + +// Save 保存 +func (l *LabaLog) Save(f func(log *LabaLog)) { + f(l) + l.PlayerListLog.Save() + l.GameDetailLog.Save() + l.Clear() +} + +// Clear 清空 +func (l *LabaLog) Clear() { + l.PlayerListLog = nil + l.GameDetailLog = nil +} diff --git a/gamesrv/base/gamewarning.go b/gamesrv/base/gamewarning.go index 4a0ddbe..a4e0021 100644 --- a/gamesrv/base/gamewarning.go +++ b/gamesrv/base/gamewarning.go @@ -68,27 +68,6 @@ func NewGameWarning(param string) { }), nil, "NewGameWarning").Start() } -// func WarningLoseCoin(gameFreeId int32, snid int32, loseCoin int64) { -// if model.GameParamData.WarningLoseLimit == 0 { -// return -// } -// if loseCoin < model.GameParamData.WarningLoseLimit { -// return -// } -// NewGameWarning(fmt.Sprintf(`{"WarningType":%v,"WarningGame":%v,"WarningSnid":%v,"LoseCoin":%v}`, -// Warning_LoseCoinLimit, gameFreeId, snid, loseCoin)) -// - -//func WarningBetCoinCheck(sceneId, gameFreeId int32, snid int32, betCoin int64) { -// if model.GameParamData.WarningBetMax == 0 { -// return -// } -// if betCoin > model.GameParamData.WarningBetMax { -// NewGameWarning(fmt.Sprintf(`{"WarningType":%v,"WarningSnid":%v,"WarningGame":%v,"WarningScene":%v}`, -// Warning_BetCoinMax, snid, gameFreeId, sceneId)) -// } -//} - func WarningCoinPool(warnType int, gameFreeId int32) { NewGameWarning(fmt.Sprintf(`{"WarningType":%v,"WarningGame":%v}`, warnType, gameFreeId)) @@ -97,24 +76,3 @@ func WarningBlackPlayer(snid, gameFreeId int32) { NewGameWarning(fmt.Sprintf(`{"WarningType":%v,"WarningSnid":%v,"WarningGame":%v}`, Warning_BlackPlayer, snid, gameFreeId)) } - -//func WarningWinnerRate(snid int32, winCoin, loseCoin int64) { -// if model.GameParamData.WarningWinRate == 0 { -// return -// } -// if (winCoin+1)/(loseCoin+1) < model.GameParamData.WarningWinRate { -// return -// } -// NewGameWarning(fmt.Sprintf(`{"WarningType":%v,"WarningSnid":%v,"WarningRate":%v,"WinCoin":%v,"LoseCoin":%v}`, -// Warning_WinRate, snid, (winCoin+1)/(loseCoin+1), winCoin, loseCoin)) -//} -//func WarningWinnerCoin(snid int32, winCoin, loseCoin int64) { -// if model.GameParamData.WarningWinMoney == 0 { -// return -// } -// if (winCoin - loseCoin) < model.GameParamData.WarningWinMoney { -// return -// } -// NewGameWarning(fmt.Sprintf(`{"WarningType":%v,"WarningSnid":%v,"WarningCoin":%v,"WinCoin":%v,"LoseCoin":%v}`, -// Warning_WinCoin, snid, (winCoin - loseCoin), winCoin, loseCoin)) -//} diff --git a/gamesrv/base/handredJacklistmgr.go b/gamesrv/base/handredJacklistmgr.go deleted file mode 100644 index e444859..0000000 --- a/gamesrv/base/handredJacklistmgr.go +++ /dev/null @@ -1,300 +0,0 @@ -package base - -import ( - "fmt" - "strconv" - "strings" - "time" - - "mongo.games.com/game/model" - - "github.com/globalsign/mgo/bson" - "mongo.games.com/goserver/core/basic" - "mongo.games.com/goserver/core/logger" - "mongo.games.com/goserver/core/module" - "mongo.games.com/goserver/core/task" -) - -// HundredJackListManager 排行榜 key: platform+gamefreeId -type HundredJackListManager struct { - HundredJackTsList map[string][]*HundredJackInfo - HundredJackSortList map[string][]*HundredJackInfo -} - -// HundredJackListMgr 实例化 -var HundredJackListMgr = &HundredJackListManager{ - HundredJackTsList: make(map[string][]*HundredJackInfo), - HundredJackSortList: make(map[string][]*HundredJackInfo), -} - -// HundredJackInfo 数据结构 -type HundredJackInfo struct { - model.HundredjackpotLog - linkSnids []int32 //点赞人数 -} - -// ModuleName . -func (hm *HundredJackListManager) ModuleName() string { - return "HundredJackListManager" -} - -// Init . -func (hm *HundredJackListManager) Init() { - //data := model. -} - -// Update . -func (hm *HundredJackListManager) Update() { -} - -// Shutdown . -func (hm *HundredJackListManager) Shutdown() { - module.UnregisteModule(hm) -} - -// ISInitJackInfo 仅初始化一次 -var ISInitJackInfo bool - -// InitTsJackInfo 初始化TsJackInfo -func (hm *HundredJackListManager) InitTsJackInfo(platform string, freeID int32) { - key := fmt.Sprintf("%v-%v", platform, freeID) - task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} { - datas, err := model.GetHundredjackpotLogTsByPlatformAndGameFreeID(platform, freeID) - if err != nil { - logger.Logger.Error("HundredJackListManager DelOneJackInfo ", err) - return nil - } - return datas - }), task.CompleteNotifyWrapper(func(data interface{}, tt task.Task) { - datas := data.([]model.HundredjackpotLog) - if data != nil && datas != nil { - for i := range datas { - if i == model.HundredjackpotLogMaxLimitPerQuery { - break - } - data := &HundredJackInfo{ - HundredjackpotLog: datas[i], - } - strlikeSnids := strings.Split(datas[i].LinkeSnids, "|") - for _, v := range strlikeSnids { - if v == "" { - break - } - snid, err := strconv.Atoi(v) - if err == nil { - data.linkSnids = append(data.linkSnids, int32(snid)) - } - } - hm.HundredJackTsList[key] = append(hm.HundredJackTsList[key], data) - } - // logger.Logger.Warnf("InitTsJackInfo data:%v", datas) - } else { - hm.HundredJackTsList[key] = []*HundredJackInfo{} - } - return - }), "InitTsJackInfo").Start() -} - -// InitSortJackInfo 初始化SortJackInfo -func (hm *HundredJackListManager) InitSortJackInfo(platform string, freeID int32) { - - key := fmt.Sprintf("%v-%v", platform, freeID) - task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} { - datas, err := model.GetHundredjackpotLogCoinByPlatformAndGameFreeID(platform, freeID) - if err != nil { - logger.Logger.Error("HundredJackListManager DelOneJackInfo ", err) - return nil - } - return datas - }), task.CompleteNotifyWrapper(func(data interface{}, tt task.Task) { - datas := data.([]model.HundredjackpotLog) - if data != nil && datas != nil { - for i := range datas { - if i == model.HundredjackpotLogMaxLimitPerQuery { - break - } - data := &HundredJackInfo{ - HundredjackpotLog: datas[i], - } - strlikeSnids := strings.Split(datas[i].LinkeSnids, "|") - for _, v := range strlikeSnids { - snid, err := strconv.Atoi(v) - if err == nil { - data.linkSnids = append(data.linkSnids, int32(snid)) - } - } - hm.HundredJackSortList[key] = append(hm.HundredJackSortList[key], data) - } - // logger.Logger.Warnf("InitSortJackInfo data:%v", datas) - } else { - hm.HundredJackSortList[key] = []*HundredJackInfo{} - } - return - }), "InitSortJackInfo").Start() -} - -// InitHundredJackListInfo 初始化 HundredJackListInfo -func (hm *HundredJackListManager) InitHundredJackListInfo(platform string, freeID int32) { - if ISInitJackInfo { - return - } - key := fmt.Sprintf("%v-%v", platform, freeID) - if _, exist := hm.HundredJackTsList[key]; !exist { - hm.InitTsJackInfo(platform, freeID) - } - if _, exist := hm.HundredJackSortList[key]; !exist { - hm.InitSortJackInfo(platform, freeID) - } - ISInitJackInfo = true - return -} - -// GetJackTsInfo 返回TsInfo -func (hm *HundredJackListManager) GetJackTsInfo(platform string, freeID int32) []*HundredJackInfo { - key := fmt.Sprintf("%v-%v", platform, freeID) - if _, exist := hm.HundredJackTsList[key]; !exist { // 玩家进入scene 已经初始化 - hm.InitTsJackInfo(platform, freeID) - } - return hm.HundredJackTsList[key] -} - -// GetJackSortInfo 返回SortInfo -func (hm *HundredJackListManager) GetJackSortInfo(platform string, freeID int32) []*HundredJackInfo { - key := fmt.Sprintf("%v-%v", platform, freeID) - if _, exist := hm.HundredJackSortList[key]; !exist { - hm.InitSortJackInfo(platform, freeID) - } - return hm.HundredJackSortList[key] -} - -// Insert 插入 -func (hm *HundredJackListManager) Insert(coin, turncoin int64, snid, roomid, jackType, inGame, vip int32, platform, channel, name string, gamedata []string) { - key := fmt.Sprintf("%v-%v", platform, roomid) - log := model.NewHundredjackpotLogEx(snid, coin, turncoin, roomid, jackType, inGame, vip, platform, channel, name, gamedata) - ///////////////////实际不走这里 - if _, exist := hm.HundredJackTsList[key]; !exist { - hm.InitTsJackInfo(platform, roomid) - } - if _, exist := hm.HundredJackSortList[key]; !exist { - hm.InitSortJackInfo(platform, roomid) - } - ///////////////////// - hm.InsertLog(log) - data := &HundredJackInfo{ - HundredjackpotLog: *log, - } - /*logger.Logger.Trace("HundredJackListManager log 1 ", log.SnID, log.LogID, data.GameData) - for _, v := range hm.HundredJackTsList[key] { - logger.Logger.Trace("HundredJackListManager log 2 ", v.SnID, v.LogID, v.GameData) - }*/ - for i, v := range hm.HundredJackSortList[key] { // 插入 - if v.Coin < log.Coin { - d1 := append([]*HundredJackInfo{}, hm.HundredJackSortList[key][i:]...) - hm.HundredJackSortList[key] = append(hm.HundredJackSortList[key][:i], data) - hm.HundredJackSortList[key] = append(hm.HundredJackSortList[key], d1...) - goto Exit - } - } - if len(hm.HundredJackSortList[key]) < model.HundredjackpotLogMaxLimitPerQuery { - hm.HundredJackSortList[key] = append(hm.HundredJackSortList[key], data) - } -Exit: - d1 := append([]*HundredJackInfo{}, hm.HundredJackTsList[key][0:]...) - hm.HundredJackTsList[key] = append(hm.HundredJackTsList[key][:0], data) - hm.HundredJackTsList[key] = append(hm.HundredJackTsList[key], d1...) - var delList []*HundredJackInfo - if len(hm.HundredJackTsList[key]) > model.HundredjackpotLogMaxLimitPerQuery { - delList = append(delList, hm.HundredJackTsList[key][model.HundredjackpotLogMaxLimitPerQuery:]...) - hm.HundredJackTsList[key] = hm.HundredJackTsList[key][:model.HundredjackpotLogMaxLimitPerQuery] - } - if len(hm.HundredJackSortList[key]) > model.HundredjackpotLogMaxLimitPerQuery { - delList = append(delList, hm.HundredJackSortList[key][model.HundredjackpotLogMaxLimitPerQuery:]...) - hm.HundredJackSortList[key] = hm.HundredJackSortList[key][:model.HundredjackpotLogMaxLimitPerQuery] - } - /*for _, v := range hm.HundredJackTsList[key] { - logger.Logger.Trace("HundredJackListManager log 3 ", v.SnID, v.LogID, v.GameData) - }*/ - for _, v := range delList { - if hm.IsCanDel(v, hm.HundredJackTsList[key], hm.HundredJackSortList[key]) { // 两个排行帮都不包含 - logger.Logger.Info("HundredJackListManager DelOneJackInfo ", v.LogID) - hm.DelOneJackInfo(v.Platform, v.LogID) - } - } -} - -// IsCanDel 能否删除 -func (hm *HundredJackListManager) IsCanDel(deldata *HundredJackInfo, tsList, sortList []*HundredJackInfo) bool { - for _, v := range tsList { - if v.LogID == deldata.LogID { - return false - } - } - for _, v := range sortList { - if v.LogID == deldata.LogID { - return false - } - } - return true -} - -// InsertLog insert db -func (hm *HundredJackListManager) InsertLog(log *model.HundredjackpotLog) { - task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} { - err := model.InsertHundredjackpotLog(log) - if err != nil { - logger.Logger.Error("HundredJackListManager Insert ", err) - } - return err - }), nil, "InsertHundredJack").Start() -} - -// UpdateLikeNum updata likenum -func (hm *HundredJackListManager) UpdateLikeNum(plt string, gid bson.ObjectId, like int32, likesnids string) { - task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} { - err := model.UpdateLikeNum(plt, gid, like, likesnids) - if err != nil { - logger.Logger.Error("HundredJackListManager UpdateHundredLikeNum ", err) - } - return err - }), nil, "UpdateHundredLikeNum").Start() -} - -// UpdatePlayBlackNum updata playblacknum -func (hm *HundredJackListManager) UpdatePlayBlackNum(plt string, gid bson.ObjectId, playblack int32) []string { - var ret []string - task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} { - data, err := model.UpdatePlayBlackNum(plt, gid, playblack) - if err != nil { - logger.Logger.Error("HundredJackListManager DelOneJackInfo ", err) - return nil - } - return data - }), task.CompleteNotifyWrapper(func(data interface{}, tt task.Task) { - if data != nil { - ret = data.([]string) - logger.Logger.Warnf("UpdatePlayBlackNum data:%v", ret) - } - return - }), "UpdatePlayBlackNum").Start() - - logger.Logger.Error("HundredJackListManager UpdatePlayBlackNum ", ret) - if len(ret) == 0 { - return ret - } - return nil -} - -// DelOneJackInfo del -func (hm *HundredJackListManager) DelOneJackInfo(plt string, gid bson.ObjectId) { - task.New(nil, task.CallableWrapper(func(o *basic.Object) interface{} { - err := model.RemoveHundredjackpotLogOne(plt, gid) - if err != nil { - logger.Logger.Error("HundredJackListManager DelOneJackInfo ", err) - } - return err - }), nil, "DelOneJackInfo").Start() -} - -func init() { - module.RegisteModule(HundredJackListMgr, time.Hour, 0) -} diff --git a/gamesrv/base/player.go b/gamesrv/base/player.go index 5f47a55..1bcdf6e 100644 --- a/gamesrv/base/player.go +++ b/gamesrv/base/player.go @@ -627,9 +627,15 @@ type ReportGameEventParam struct { Change int64 // 净输赢,正负值,不带税收 In, Out int64 // 投入,产出(税前) GameTime int64 // 游戏时长,秒 + OnlyLog bool // 只返回数据,不上报 } -func (this *Player) ReportGameEvent(param *ReportGameEventParam) { +type ReportGameEventOnly struct { + Param *ReportGameEventParam + Log []*model.PlayerGameRecEvent +} + +func (this *Player) ReportGameEvent(param *ReportGameEventParam) *ReportGameEventOnly { // 记录玩家 首次参与该场次的游戏时间 游戏次数 var gameFirstTime, gameFreeFirstTime time.Time var gameTimes, gameFreeTimes int64 @@ -659,6 +665,8 @@ func (this *Player) ReportGameEvent(param *ReportGameEventParam) { param.GameTime = 0 } + var ret ReportGameEventOnly + ret.Param = param log := &model.PlayerGameRecEvent{ Platform: this.Platform, RecordId: this.scene.GetRecordId(), @@ -685,7 +693,12 @@ func (this *Player) ReportGameEvent(param *ReportGameEventParam) { LastLoginTime: this.LastLoginTime.Unix(), DeviceId: this.DeviceId, } - mq.Write(log, mq.BackGameRecord) + if param.OnlyLog { + ret.Log = append(ret.Log, log) + } else { + mq.Write(log, mq.BackGameRecord) + } + return &ret } // 汇总玩家该次游戏总产生的税收 diff --git a/gamesrv/base/scene.go b/gamesrv/base/scene.go index 7dfe670..4d6a2e4 100644 --- a/gamesrv/base/scene.go +++ b/gamesrv/base/scene.go @@ -2,7 +2,6 @@ package base import ( "fmt" - "github.com/globalsign/mgo/bson" "math" "math/rand" "strconv" @@ -1457,162 +1456,6 @@ func (this *Scene) SaveFriendRecord(snid int32, isWin int32, billCoin int64, bas } } -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 From 5a67d8f0732534930ee5d0d83177d6e6d8a8489d Mon Sep 17 00:00:00 2001 From: sk <123456@qq.com> Date: Wed, 4 Dec 2024 10:06:59 +0800 Subject: [PATCH 32/41] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=8D=81=E4=B8=89?= =?UTF-8?q?=E5=BC=A0=E8=AE=B0=E5=88=86=E6=98=BE=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gamerule/thirteen/logic.go | 2 +- gamesrv/thirteen/scene.go | 3 +++ gamesrv/thirteen/scenepolicy.go | 10 +++++++++- 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/gamerule/thirteen/logic.go b/gamerule/thirteen/logic.go index 9a72eaa..d6f922f 100644 --- a/gamerule/thirteen/logic.go +++ b/gamerule/thirteen/logic.go @@ -105,7 +105,7 @@ type Group struct { Head [3]int Mid [5]int End [5]int - PokerType int + PokerType int // -1 无牌数据,0 有牌数据, 1-13 特殊牌型 } func (p *Group) String() string { diff --git a/gamesrv/thirteen/scene.go b/gamesrv/thirteen/scene.go index 77b3318..bd04c0f 100644 --- a/gamesrv/thirteen/scene.go +++ b/gamesrv/thirteen/scene.go @@ -487,6 +487,7 @@ func (this *SceneEx) GetScore(player *PlayerEx) { player.winAllPlayers[p.Pos] += rate p.winAllPlayers[player.Pos] -= rate player.tableScore[3] += rate - 1 + p.tableScore[3] -= rate - 1 } //中墩 rate = int64(1) @@ -509,6 +510,7 @@ func (this *SceneEx) GetScore(player *PlayerEx) { player.winAllPlayers[p.Pos] += rate p.winAllPlayers[player.Pos] -= rate player.tableScore[4] += rate - 1 + p.tableScore[4] -= rate - 1 } //尾墩 rate = int64(1) @@ -529,6 +531,7 @@ func (this *SceneEx) GetScore(player *PlayerEx) { player.winAllPlayers[p.Pos] += rate p.winAllPlayers[player.Pos] -= rate player.tableScore[5] += rate - 1 + p.tableScore[5] -= rate - 1 } if s == 3 { player.winThreePos[p.Pos] = score diff --git a/gamesrv/thirteen/scenepolicy.go b/gamesrv/thirteen/scenepolicy.go index 05d9b36..2bb9a47 100644 --- a/gamesrv/thirteen/scenepolicy.go +++ b/gamesrv/thirteen/scenepolicy.go @@ -866,6 +866,10 @@ func (this *StateOp) OnPlayerOp(s *base.Scene, p *base.Player, opcode int, param copy(playerEx.cardsO.Mid[:], common.Int64Toint(params[3:8])) copy(playerEx.cardsO.End[:], common.Int64Toint(params[8:])) playerEx.cardsO.PokerType = 0 + tp := sceneEx.logic.GetSpecialType(playerEx.cards) + if tp > 0 { + playerEx.cardsO.PokerType = tp + } sceneEx.SendSelectCards(playerEx, 0, int64(opcode)) } else { sceneEx.SendSelectCards(playerEx, int(params[0]), int64(opcode)) @@ -912,6 +916,10 @@ func (this *StateOp) OnPlayerOp(s *base.Scene, p *base.Player, opcode int, param copy(playerEx.preCardsO.Mid[:], common.Int64Toint(params[3:8])) copy(playerEx.preCardsO.End[:], common.Int64Toint(params[8:])) playerEx.preCardsO.PokerType = 0 + tp := sceneEx.logic.GetSpecialType(playerEx.cards) + if tp > 0 { + playerEx.preCardsO.PokerType = tp + } } playerEx.SendToClient(int(thirteen.TWMmoPacketID_PACKET_SCThirteenPlayerOp), pack) @@ -948,7 +956,7 @@ func (this *StateOp) OnLeave(s *base.Scene) { } // 判断是否倒水 if player.cardsO != nil && player.cardsO.PokerType != -1 { - if player.cardsO.PokerType < 1000000 { + if player.cardsO.PokerType == 0 { player.isDP = sceneEx.logic.IsDP(player.cardsO.Head, player.cardsO.Mid, player.cardsO.End) } continue From 22dc0a767af4dd24bdb1d0402457cfab5359337c Mon Sep 17 00:00:00 2001 From: sk <123456@qq.com> Date: Wed, 4 Dec 2024 16:35:50 +0800 Subject: [PATCH 33/41] =?UTF-8?q?=E8=87=AA=E5=AE=9A=E4=B9=89=E9=85=8D?= =?UTF-8?q?=E7=BD=AE=E5=8F=82=E6=95=B0=E4=B8=8D=E5=8C=BA=E5=88=86=E5=A4=A7?= =?UTF-8?q?=E5=B0=8F=E5=86=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- common/config.go | 60 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/common/config.go b/common/config.go index 3347b65..a15c366 100644 --- a/common/config.go +++ b/common/config.go @@ -2,6 +2,7 @@ package common import ( "encoding/json" + "strings" "mongo.games.com/goserver/core" ) @@ -53,6 +54,13 @@ func (this *CustomConfiguration) GetString(key string) string { return str } } + + if v, exist := (*this)[strings.ToLower(key)]; exist { + if str, ok := v.(string); ok { + return str + } + } + return "" } @@ -67,6 +75,18 @@ func (this *CustomConfiguration) GetStrings(key string) (strs []string) { return } } + + if v, exist := (*this)[strings.ToLower(key)]; exist { + if vals, ok := v.([]interface{}); ok { + for _, s := range vals { + if str, ok := s.(string); ok { + strs = append(strs, str) + } + } + return + } + } + return } @@ -86,6 +106,23 @@ func (this *CustomConfiguration) GetCustomCfgs(key string) (strs []*CustomConfig return } } + + if v, exist := (*this)[strings.ToLower(key)]; exist { + if vals, ok := v.([]interface{}); ok { + for _, s := range vals { + if data, ok := s.(map[string]interface{}); ok { + var pkg *CustomConfiguration + modelBuff, _ := json.Marshal(data) + err := json.Unmarshal(modelBuff, &pkg) + if err == nil { + strs = append(strs, pkg) + } + } + } + return + } + } + return } @@ -100,6 +137,18 @@ func (this *CustomConfiguration) GetInts(key string) (strs []int) { return } } + + if v, exist := (*this)[strings.ToLower(key)]; exist { + if vals, ok := v.([]interface{}); ok { + for _, s := range vals { + if str, ok := s.(float64); ok { + strs = append(strs, int(str)) + } + } + return + } + } + return } func (this *CustomConfiguration) GetInt(key string) int { @@ -108,6 +157,12 @@ func (this *CustomConfiguration) GetInt(key string) int { return int(val) } } + + if v, exist := (*this)[strings.ToLower(key)]; exist { + if val, ok := v.(float64); ok { + return int(val) + } + } return 0 } @@ -117,5 +172,10 @@ func (this *CustomConfiguration) GetBool(key string) bool { return val } } + if v, exist := (*this)[strings.ToLower(key)]; exist { + if val, ok := v.(bool); ok { + return val + } + } return false } From f78b1edfb3abc6e2af8bc06ddfffd6ae8838950e Mon Sep 17 00:00:00 2001 From: sk <123456@qq.com> Date: Wed, 4 Dec 2024 16:47:38 +0800 Subject: [PATCH 34/41] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E4=BE=9D=E8=B5=96?= =?UTF-8?q?=E5=8C=85=E5=BC=95=E7=94=A8=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gamesrv/slotspkg/internal/generic/errors/init.go | 2 +- gamesrv/slotspkg/slots/handler.go | 2 +- go.mod | 1 - go.sum | 2 -- 4 files changed, 2 insertions(+), 5 deletions(-) diff --git a/gamesrv/slotspkg/internal/generic/errors/init.go b/gamesrv/slotspkg/internal/generic/errors/init.go index b34b914..b67b7ea 100644 --- a/gamesrv/slotspkg/internal/generic/errors/init.go +++ b/gamesrv/slotspkg/internal/generic/errors/init.go @@ -1,6 +1,6 @@ package errors -import "github.com/idealeak/goserver/core/logger" +import "mongo.games.com/goserver/core/logger" var ( begins = []Code{ErrorBegin} diff --git a/gamesrv/slotspkg/slots/handler.go b/gamesrv/slotspkg/slots/handler.go index 1615253..f4b8dd4 100644 --- a/gamesrv/slotspkg/slots/handler.go +++ b/gamesrv/slotspkg/slots/handler.go @@ -1,7 +1,6 @@ package slots import ( - "github.com/idealeak/goserver/core/logger" "mongo.games.com/game/gamesrv/base" "mongo.games.com/game/gamesrv/slotspkg/internal/generic/errors" "mongo.games.com/game/gamesrv/slotspkg/internal/generic/global" @@ -10,6 +9,7 @@ import ( "mongo.games.com/game/gamesrv/slotspkg/internal/module/shared" "mongo.games.com/game/gamesrv/slotspkg/slots/machine" "mongo.games.com/game/gamesrv/slotspkg/slots/types/cli" + "mongo.games.com/goserver/core/logger" ) func (sm *SlotsMgr) Enter(s *base.SlotsSession, gameId int64) (*cli.SlotsEnterResponse, error) { diff --git a/go.mod b/go.mod index 0eee4a1..24ed7df 100644 --- a/go.mod +++ b/go.mod @@ -16,7 +16,6 @@ require ( github.com/golang-jwt/jwt/v4 v4.5.1 github.com/google/go-querystring v1.1.0 github.com/howeyc/fsnotify v0.9.0 - github.com/idealeak/goserver v0.0.0-20201014040547-b8f686262078 github.com/jinzhu/now v1.1.5 github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 github.com/mojocn/base64Captcha v1.3.6 diff --git a/go.sum b/go.sum index 00dcca3..ea89a77 100644 --- a/go.sum +++ b/go.sum @@ -157,8 +157,6 @@ github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T github.com/howeyc/fsnotify v0.9.0 h1:0gtV5JmOKH4A8SsFxG2BczSeXWWPvcMT0euZt5gDAxY= github.com/howeyc/fsnotify v0.9.0/go.mod h1:41HzSPxBGeFRQKEEwgh49TRw/nKBsYZ2cF1OzPjSJsA= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/idealeak/goserver v0.0.0-20201014040547-b8f686262078 h1:0Z5Im7EJiMKEiIQPPApdK0uOtyV5Ylo9wA3N9jWrfsU= -github.com/idealeak/goserver v0.0.0-20201014040547-b8f686262078/go.mod h1:ozCWDPw33jhq/GX7nsWS0cFCm5Jyag/Fy0LSQpKXT1I= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/innopals/sls-logrus-hook v0.0.0-20190808032145-2fe1d6f7ce00 h1:QfdUfoZWIzBZ/FMtdUE/3wUwzsMU+PGTld17NDBld3k= github.com/innopals/sls-logrus-hook v0.0.0-20190808032145-2fe1d6f7ce00/go.mod h1:Q24O6QMGImDU3WY71P4YAxNb36NNn5qaznCfMUoXVfc= From 2ea5226a14dfaab98d1c2653bbb6bae3421e8748 Mon Sep 17 00:00:00 2001 From: sk <123456@qq.com> Date: Wed, 4 Dec 2024 17:40:39 +0800 Subject: [PATCH 35/41] no message --- data/activity/activity_51game.json | 16 - data/activity/activity_guess.json | 20 - data/activity/activity_invite.json | 11 - data/activity/activity_new_reg.json | 14 - data/activity/activity_rebate.json | 11 - data/activity/activity_reply_word.json | 21 - data/botai/dvtfollowwin.json | 1173 --------------------- data/botai/dvtinvertwin.json | 1284 ----------------------- data/botai/dvtrandom.json | 1059 ------------------- data/botai/rvbfollowwin.json | 1174 ---------------------- data/botai/rvbinvertwin.json | 1285 ------------------------ data/botai/rvbrandom.json | 1026 ------------------- data/fishpath/path.json | 1 - tools/upload/config.json | 3 +- 14 files changed, 2 insertions(+), 7096 deletions(-) delete mode 100644 data/activity/activity_51game.json delete mode 100644 data/activity/activity_guess.json delete mode 100644 data/activity/activity_invite.json delete mode 100644 data/activity/activity_new_reg.json delete mode 100644 data/activity/activity_rebate.json delete mode 100644 data/activity/activity_reply_word.json delete mode 100644 data/botai/dvtfollowwin.json delete mode 100644 data/botai/dvtinvertwin.json delete mode 100644 data/botai/dvtrandom.json delete mode 100644 data/botai/rvbfollowwin.json delete mode 100644 data/botai/rvbinvertwin.json delete mode 100644 data/botai/rvbrandom.json delete mode 100644 data/fishpath/path.json diff --git a/data/activity/activity_51game.json b/data/activity/activity_51game.json deleted file mode 100644 index 270de94..0000000 --- a/data/activity/activity_51game.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "Id":5, - "Name":"51活动", - "Desc":"对局领福袋", - "StartTime":"2018-04-20 00:00:00", - "EndTime":"2018-05-02 23:59:59", - "TaskIds":[], - "IsDelTaskWhenEnd":true, - "IsDelActIdWhenEnd":true, - "Data":[ - {"Name":"PerDayLimit", "IntVal":3 }, - {"Name":"CostTimes", "IntArr":[5,3] }, - {"Name":"Prize1", "IntArr":[1,1500,60,1,2000,20,1,3000,10,4,100,6,4,200,3,4,500,1] }, - {"Name":"Prize2", "IntArr":[1,200,40,1,300,25,1,500,15,1,800,10,1,1000,5,4,100,5] } - ] -} \ No newline at end of file diff --git a/data/activity/activity_guess.json b/data/activity/activity_guess.json deleted file mode 100644 index bede4ae..0000000 --- a/data/activity/activity_guess.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "Id":3, - "Name":"元宵猜灯谜", - "Desc":"元宵猜灯谜", - "StartTime":"2018-03-02 00:00:00", - "EndTime":"2018-03-02 23:59:59", - "TaskIds":[], - "IsDelTaskWhenEnd":true, - "IsDelActIdWhenEnd":true, - "Data":[ - {"Name":"Count", "IntVal":6 }, - {"Name":"Prize", "IntArr":[1,2000,50,1,3000,30,3,20,15,3,50,5] }, - {"Name":"1", "StrArr":["2018-03-02 00:00:00","1","弟兄五六个,围着圆柱坐,大家一分手,衣服都扯破。","A:花生","B:大蒜","C:向日葵","D:糖葫芦"] }, - {"Name":"2", "StrArr":["2018-03-02 04:00:00","2","红公鸡,绿尾巴,身体钻到地底下,又甜又脆营养大。","A:番茄","B:红薯","C:红萝卜","D:花生"] }, - {"Name":"3", "StrArr":["2018-03-02 08:00:00","3","纸老虎(打一成语)","A:狐假虎威","B:狗仗人势","C:仗势欺人","D:外强中干"] }, - {"Name":"4", "StrArr":["2018-03-02 12:00:00","0","笑死人(打一成语)","A:乐极生悲","B:笑里藏刀","C:哭笑不得","D:强颜欢笑"] }, - {"Name":"5", "StrArr":["2018-03-02 16:00:00","3","兔子请老虎(打一成语)","A:狐假虎威","B:为虎作伥","C:与虎谋皮","D:寅吃卯粮"] }, - {"Name":"6", "StrArr":["2018-03-02 20:00:00","1", "白又方,嫩又香,能做菜,能煮汤,豆子是它爹和妈,它和爹妈不一样。","A:土豆","B:豆腐","C:大米","D:萝卜"] } - ] -} \ No newline at end of file diff --git a/data/activity/activity_invite.json b/data/activity/activity_invite.json deleted file mode 100644 index e60e5aa..0000000 --- a/data/activity/activity_invite.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "Id":4, - "Name":"邀请新人", - "Desc":"邀请新人", - "StartTime":"2018-03-23 00:00:00", - "EndTime":"2018-05-31 23:59:59", - "TaskIds":[], - "IsDelTaskWhenEnd":true, - "IsDelActIdWhenEnd":true, - "Data":[] -} \ No newline at end of file diff --git a/data/activity/activity_new_reg.json b/data/activity/activity_new_reg.json deleted file mode 100644 index 15c40a0..0000000 --- a/data/activity/activity_new_reg.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "Id":1, - "Name":"新人注册领红包", - "Desc":"新人注册领红包", - "StartTime":"2018-02-05 12:00:00", - "EndTime":"2020-05-30 12:00:00", - "TaskIds":[1,2,3,4,5,6,7,8,9,10], - "IsDelTaskWhenEnd":false, - "IsDelActIdWhenEnd":false, - "Data":[ - {"Name":"MaxNum", "IntVal":2000 }, - {"Name":"AcceptRate", "IntArr":[1001,100,2001,20] } - ] -} \ No newline at end of file diff --git a/data/activity/activity_rebate.json b/data/activity/activity_rebate.json deleted file mode 100644 index eb82bfc..0000000 --- a/data/activity/activity_rebate.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "Id":6, - "Name":"投资返利", - "Desc":"投资返利", - "StartTime":"2018-04-20 00:00:00", - "EndTime":"2025-05-02 23:59:59", - "TaskIds":[], - "IsDelTaskWhenEnd":true, - "IsDelActIdWhenEnd":true, - "Data":[] -} \ No newline at end of file diff --git a/data/activity/activity_reply_word.json b/data/activity/activity_reply_word.json deleted file mode 100644 index 6abd634..0000000 --- a/data/activity/activity_reply_word.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "Id":2, - "Name":"对暗号拿红包", - "Desc":"对暗号拿红包", - "StartTime":"2018-02-16 00:00:00", - "EndTime":"2018-02-23 00:00:00", - "TaskIds":[], - "IsDelTaskWhenEnd":false, - "IsDelActIdWhenEnd":false, - "Data":[ - {"Name":"Count", "IntVal":7 }, - {"Name":"UnOpenTip", "StrVal":"0" }, - {"Name":"1", "StrVal":"2018-02-16 19:00:00|1" }, - {"Name":"2", "StrVal":"2018-02-17 19:00:00|2" }, - {"Name":"3", "StrVal":"2018-02-18 19:00:00|3" }, - {"Name":"4", "StrVal":"2018-02-19 19:00:00|4" }, - {"Name":"5", "StrVal":"2018-02-20 19:00:00|5" }, - {"Name":"6", "StrVal":"2018-02-21 19:00:00|6" }, - {"Name":"7", "StrVal":"2018-02-22 19:00:00|7" } - ] -} \ No newline at end of file diff --git a/data/botai/dvtfollowwin.json b/data/botai/dvtfollowwin.json deleted file mode 100644 index a75f1df..0000000 --- a/data/botai/dvtfollowwin.json +++ /dev/null @@ -1,1173 +0,0 @@ -{ - "version": "0.3.0", - "scope": "tree", - "id": "37bd2b7b-fa98-4e95-9574-d1f14a8c3422", - "title": "DVTFollowWinBot", - "description": "龙虎跟注", - "root": "e1363bca-78ca-4923-995e-074cdcb803cf", - "properties": {}, - "nodes": { - "d1b6d256-4b76-441b-a455-bdf592c0a722": { - "id": "d1b6d256-4b76-441b-a455-bdf592c0a722", - "name": "Sequence", - "category": "composite", - "title": "Sequence", - "description": "", - "properties": {}, - "display": { - "x": 324, - "y": -108 - }, - "children": [ - "3cecf744-3e4b-4ca1-85b0-323aaa576314", - "2a567791-009a-43ac-842b-3ebf763ecd20", - "2a8386b7-8dfe-4057-84cc-d55f7b027611", - "910076bb-4d07-471e-8280-a55a802ba13f", - "09d39c93-a081-4fe1-8ec3-389a1c5f9617", - "273444a5-6648-42c2-868b-a6a5d869fc9e" - ] - }, - "8ad1b951-ff76-4a7d-81f5-e934737d3842": { - "id": "8ad1b951-ff76-4a7d-81f5-e934737d3842", - "name": "RandIntAction", - "category": "action", - "title": "RandIntAction(,,)", - "description": "随机获得一个[min,max)的整数,保存到黑板的index key中", - "properties": { - "index": "betSrcCoin", - "min": 2, - "max": 6 - }, - "display": { - "x": 324, - "y": -480 - } - }, - "da6163be-5079-428a-aa43-2c5e53d840a7": { - "id": "da6163be-5079-428a-aa43-2c5e53d840a7", - "name": "RandWait", - "category": "action", - "title": "RandWait(,)", - "description": "节点暂停[minTime,maxTime)毫秒", - "properties": { - "minTime": 600, - "maxTime": 1200 - }, - "display": { - "x": 1044, - "y": 204 - } - }, - "df0cd7eb-848f-49e0-87b6-d0ba50c282f1": { - "id": "df0cd7eb-848f-49e0-87b6-d0ba50c282f1", - "name": "Sequence", - "category": "composite", - "title": "Sequence", - "description": "", - "properties": {}, - "display": { - "x": 24, - "y": 1044 - }, - "children": [ - "094558c6-747d-48d0-8846-3e648f1b58b6", - "c19613b3-0961-4c38-8680-c1e4a88df0b8", - "feac41f1-9450-431c-8bea-30fee992e269", - "7083a59f-1953-421e-9356-6b636a4ddc57" - ] - }, - "95dc5d8f-69a4-4b0d-b22e-0bab989c82f8": { - "id": "95dc5d8f-69a4-4b0d-b22e-0bab989c82f8", - "name": "CheckPlayerCoin", - "category": "condition", - "title": "CheckPlayerCoin(,)", - "description": "检查用户金币\ngIPCoin 支持@ 用户需要比较的金币\ncmp 比较\t\n 0 //小于\n 1 //小于等于\n 2 //等于\n 3 //大于\n 4 //大于等于", - "properties": { - "gIPCoin": "saveLimit", - "cmp": 0 - }, - "display": { - "x": 912, - "y": 948 - } - }, - "ec1cdd41-d944-4d3f-8918-c5971e8dc21c": { - "id": "ec1cdd41-d944-4d3f-8918-c5971e8dc21c", - "name": "GetOutLimitCoin", - "category": "action", - "title": "GetOutLimitCoin()", - "description": "获得玩家游戏踢出限制\ngINKey 保存到黑板key", - "properties": { - "gINKey": "saveLimit" - }, - "display": { - "x": 900, - "y": 876 - } - }, - "feac41f1-9450-431c-8bea-30fee992e269": { - "id": "feac41f1-9450-431c-8bea-30fee992e269", - "name": "RandWait", - "category": "action", - "title": "RandWait(,)", - "description": "节点暂停[minTime,maxTime)毫秒", - "properties": { - "minTime": 500, - "maxTime": 3500 - }, - "display": { - "x": 252, - "y": 1200 - } - }, - "7083a59f-1953-421e-9356-6b636a4ddc57": { - "id": "7083a59f-1953-421e-9356-6b636a4ddc57", - "name": "LeaveGame", - "category": "action", - "title": "LeaveGame", - "description": "离开游戏", - "properties": {}, - "display": { - "x": 216, - "y": 1344 - } - }, - "593b4c1a-5cd1-4782-8cbb-faedf41e4464": { - "id": "593b4c1a-5cd1-4782-8cbb-faedf41e4464", - "name": "CheckPlayerGameNum", - "category": "condition", - "title": "CheckPlayerGameNum(,)", - "description": "检查用户游戏次数\ngIPGameNum支持@ 用户需要游戏次数\ncmp 比较\t\n 0 //小于\n 1 //小于等于\n 2 //等于\n 3 //大于\n 4 //大于等于", - "properties": { - "gIPGameNum": "maxGameNum", - "cmp": 4 - }, - "display": { - "x": 960, - "y": 1128 - } - }, - "4c83ed6e-f99f-4be7-953e-f5ff06a2f9f5": { - "id": "4c83ed6e-f99f-4be7-953e-f5ff06a2f9f5", - "name": "RandIntAction", - "category": "action", - "title": "RandIntAction(,,)", - "description": "随机获得一个[min,max)的整数,保存到黑板的index key中", - "properties": { - "index": "maxGameNum", - "min": 5, - "max": 30 - }, - "display": { - "x": 936, - "y": 1044 - } - }, - "521239f8-2829-471e-ab43-e0a98d77aab7": { - "id": "521239f8-2829-471e-ab43-e0a98d77aab7", - "name": "Sequence", - "category": "composite", - "title": "Sequence", - "description": "生成初始押注额度", - "properties": {}, - "display": { - "x": 12, - "y": -456 - }, - "children": [ - "c764dcd1-7d5e-4e39-a068-8c309dff1484", - "7a8a52d3-1a69-4df7-8de2-a4d71afae499", - "ece5c421-9448-453e-99b6-460323cbed9b", - "8ad1b951-ff76-4a7d-81f5-e934737d3842", - "b3ffd6fa-1fd7-4640-812d-d1c6d55f6224", - "b9b8737c-ece2-4e1a-8af6-542dc08d5b59", - "6bc3ed88-f412-49c3-8b32-70641b703747", - "9d30f3ac-f772-48fb-852e-1acdec9d474f" - ] - }, - "7a8a52d3-1a69-4df7-8de2-a4d71afae499": { - "id": "7a8a52d3-1a69-4df7-8de2-a4d71afae499", - "name": "CheckInt", - "category": "condition", - "title": "CheckInt(,,)", - "description": "检查黑板的一个值和待比较值\n 0 //小于\n 1 //小于等于\n 2 //等于\n 3 //大于\n 4 //大于等于", - "properties": { - "keyName": "needStartBet", - "value": 0, - "cmp": 2 - }, - "display": { - "x": 300, - "y": -576 - } - }, - "ece5c421-9448-453e-99b6-460323cbed9b": { - "id": "ece5c421-9448-453e-99b6-460323cbed9b", - "name": "SetIntAction", - "category": "action", - "title": "SetIntAction(,)", - "description": "设置int参数值\ngINKey 黑版key值\ngIPValue 设置的值,支持@", - "properties": { - "gINKey": "needStartBet", - "gIPValue": "@1" - }, - "display": { - "x": 324, - "y": -528 - } - }, - "09d39c93-a081-4fe1-8ec3-389a1c5f9617": { - "id": "09d39c93-a081-4fe1-8ec3-389a1c5f9617", - "name": "SetIntMulti", - "category": "action", - "title": "SetIntMulti(,,)", - "description": "设置乘法,保存数值\ngINKey 保存黑版key\ngIPValue1 v1 支持@\ngIPValue2 v2 支持@", - "properties": { - "gINKey": "betCoin", - "gIPValue1": "betSrcCoin", - "gIPValue2": "needStartBet" - }, - "display": { - "x": 816, - "y": -36 - } - }, - "273444a5-6648-42c2-868b-a6a5d869fc9e": { - "id": "273444a5-6648-42c2-868b-a6a5d869fc9e", - "name": "SetIntMulti", - "category": "action", - "title": "SetIntMulti(,,)", - "description": "设置乘法,保存数值\ngINKey 保存黑版key\ngIPValue1 v1 支持@\ngIPValue2 v2 支持@", - "properties": { - "gINKey": "needStartBet", - "gIPValue1": "needStartBet", - "gIPValue2": "@2" - }, - "display": { - "x": 804, - "y": 12 - } - }, - "6e65f94a-05f4-410f-be23-01ee2da43240": { - "id": "6e65f94a-05f4-410f-be23-01ee2da43240", - "name": "Sequence", - "category": "composite", - "title": "Sequence", - "description": "", - "properties": {}, - "display": { - "x": 192, - "y": 684 - }, - "children": [ - "5bfdcdcf-57e3-4a15-8f02-5403d8447550", - "8d131988-67e9-4d44-99d8-7d838f5a7410", - "83b27986-aa7b-40e1-87b6-46067b5fa504" - ] - }, - "8d131988-67e9-4d44-99d8-7d838f5a7410": { - "id": "8d131988-67e9-4d44-99d8-7d838f5a7410", - "name": "CheckPlayerLastWinOrLost", - "category": "condition", - "title": "CheckPlayerLastWinOrLost(,)", - "description": "检查玩家上次输赢情况\ngIPLResult 比较值 支持@\ncmp 比较", - "properties": { - "gIPLResult": "@1", - "cmp": 2 - }, - "display": { - "x": 480, - "y": 684 - } - }, - "83b27986-aa7b-40e1-87b6-46067b5fa504": { - "id": "83b27986-aa7b-40e1-87b6-46067b5fa504", - "name": "SetIntAction", - "category": "action", - "title": "SetIntAction(,)", - "description": "设置int参数值\ngINKey 黑版key值\ngIPValue 设置的值,支持@", - "properties": { - "gINKey": "needStartBet", - "gIPValue": "@0" - }, - "display": { - "x": 468, - "y": 756 - } - }, - "b3ffd6fa-1fd7-4640-812d-d1c6d55f6224": { - "id": "b3ffd6fa-1fd7-4640-812d-d1c6d55f6224", - "name": "GetPlayerCoin", - "category": "action", - "title": "GetPlayerCoin()", - "description": "得到玩家金币\ngINKey 保存key", - "properties": { - "gINKey": "playerCoin" - }, - "display": { - "x": 312, - "y": -432 - } - }, - "b9b8737c-ece2-4e1a-8af6-542dc08d5b59": { - "id": "b9b8737c-ece2-4e1a-8af6-542dc08d5b59", - "name": "SetIntMulti", - "category": "action", - "title": "SetIntMulti(,,)", - "description": "设置乘法,保存数值\ngINKey 保存黑版key\ngIPValue1 v1 支持@\ngIPValue2 v2 支持@", - "properties": { - "gINKey": "betSrcCoin", - "gIPValue1": "betSrcCoin", - "gIPValue2": "playerCoin" - }, - "display": { - "x": 384, - "y": -384 - } - }, - "6bc3ed88-f412-49c3-8b32-70641b703747": { - "id": "6bc3ed88-f412-49c3-8b32-70641b703747", - "name": "SetIntDiv", - "category": "action", - "title": "SetIntDiv(,,)", - "description": "设定除法保存数据到黑板\ngINKey \ngIPValue1\ngIPValue2", - "properties": { - "gINKey": "betSrcCoin", - "gIPValue1": "betSrcCoin", - "gIPValue2": "@100" - }, - "display": { - "x": 360, - "y": -336 - } - }, - "c19613b3-0961-4c38-8680-c1e4a88df0b8": { - "id": "c19613b3-0961-4c38-8680-c1e4a88df0b8", - "name": "Priority", - "category": "composite", - "title": "Priority", - "description": "", - "properties": {}, - "display": { - "x": 336, - "y": 1056 - }, - "children": [ - "9986d0ac-48cd-4707-b24a-fdcb96f02a58", - "c95924ef-c6b1-480c-ab7b-aefbc84bd635", - "406d653d-e148-4722-aecf-ef77500ac21b", - "f08511cc-fa3c-4729-a434-69986d8db842" - ] - }, - "9986d0ac-48cd-4707-b24a-fdcb96f02a58": { - "id": "9986d0ac-48cd-4707-b24a-fdcb96f02a58", - "name": "Sequence", - "category": "composite", - "title": "Sequence", - "description": "", - "properties": {}, - "display": { - "x": 576, - "y": 972 - }, - "children": [ - "ec1cdd41-d944-4d3f-8918-c5971e8dc21c", - "95dc5d8f-69a4-4b0d-b22e-0bab989c82f8" - ] - }, - "c95924ef-c6b1-480c-ab7b-aefbc84bd635": { - "id": "c95924ef-c6b1-480c-ab7b-aefbc84bd635", - "name": "Sequence", - "category": "composite", - "title": "Sequence", - "description": "", - "properties": {}, - "display": { - "x": 576, - "y": 1128 - }, - "children": [ - "4c83ed6e-f99f-4be7-953e-f5ff06a2f9f5", - "593b4c1a-5cd1-4782-8cbb-faedf41e4464" - ] - }, - "2a567791-009a-43ac-842b-3ebf763ecd20": { - "id": "2a567791-009a-43ac-842b-3ebf763ecd20", - "name": "RandIntAction", - "category": "action", - "title": "RandIntAction(,,)", - "description": "随机获得一个[min,max)的整数,保存到黑板的index key中", - "properties": { - "index": "sameNum", - "min": 2, - "max": 4 - }, - "display": { - "x": 768, - "y": -180 - } - }, - "455ac069-63e9-4f5c-97ff-a0800e3e813d": { - "id": "455ac069-63e9-4f5c-97ff-a0800e3e813d", - "name": "Sequence", - "category": "composite", - "title": "Sequence", - "description": "", - "properties": {}, - "display": { - "x": 768, - "y": 144 - }, - "children": [ - "ac131866-e93e-4df5-8b18-646af0ffa070", - "7bf79e28-4232-43f6-8002-4cedb5b72cd7", - "da6163be-5079-428a-aa43-2c5e53d840a7", - "ad2737f1-015c-42c1-88af-d34099656ad5" - ] - }, - "ad2737f1-015c-42c1-88af-d34099656ad5": { - "id": "ad2737f1-015c-42c1-88af-d34099656ad5", - "name": "Priority", - "category": "composite", - "title": "Priority", - "description": "", - "properties": {}, - "display": { - "x": 852, - "y": 288 - }, - "children": [ - "2710b442-af43-4350-baf9-eee1e00c2c67", - "3ef5c0b6-9106-42b8-99a2-30b4b16afeed" - ] - }, - "3ef5c0b6-9106-42b8-99a2-30b4b16afeed": { - "id": "3ef5c0b6-9106-42b8-99a2-30b4b16afeed", - "name": "SetIntAction", - "category": "action", - "title": "SetIntAction(,)", - "description": "设置int参数值\ngINKey 黑版key值\ngIPValue 设置的值,支持@", - "properties": { - "gINKey": "betIsOk", - "gIPValue": "@1" - }, - "display": { - "x": 1056, - "y": 348 - } - }, - "7bf79e28-4232-43f6-8002-4cedb5b72cd7": { - "id": "7bf79e28-4232-43f6-8002-4cedb5b72cd7", - "name": "CheckInt", - "category": "condition", - "title": "CheckInt(,,)", - "description": "检查黑板的一个值和待比较值\n 0 //小于\n 1 //小于等于\n 2 //等于\n 3 //大于\n 4 //大于等于", - "properties": { - "keyName": "betIsOk", - "value": 0, - "cmp": 2 - }, - "display": { - "x": 1032, - "y": 144 - } - }, - "c3807aad-a77d-4a6e-8941-aceb75e75f26": { - "id": "c3807aad-a77d-4a6e-8941-aceb75e75f26", - "name": "SetIntAction", - "category": "action", - "title": "SetIntAction(,)", - "description": "设置int参数值\ngINKey 黑版key值\ngIPValue 设置的值,支持@", - "properties": { - "gINKey": "betIsOk", - "gIPValue": "@0" - }, - "display": { - "x": 372, - "y": 360 - } - }, - "f08511cc-fa3c-4729-a434-69986d8db842": { - "id": "f08511cc-fa3c-4729-a434-69986d8db842", - "name": "CheckPlayerCoin", - "category": "condition", - "title": "CheckPlayerCoin(,)", - "description": "检查用户金币\ngIPCoin 支持@ 用户需要比较的金币\ncmp 比较\t\n 0 //小于\n 1 //小于等于\n 2 //等于\n 3 //大于\n 4 //大于等于", - "properties": { - "gIPCoin": "betCoin", - "cmp": 0 - }, - "display": { - "x": 648, - "y": 1536 - } - }, - "cfb3bfdf-67e8-4bb9-9731-be379743e042": { - "id": "cfb3bfdf-67e8-4bb9-9731-be379743e042", - "name": "Sequence", - "category": "composite", - "title": "Sequence", - "description": "", - "properties": {}, - "display": { - "x": 132, - "y": 396 - }, - "children": [ - "c3807aad-a77d-4a6e-8941-aceb75e75f26", - "6d6f636d-a02a-42b5-9b4c-255c11352a68", - "43ad54ad-0bdc-4b6d-8ff5-f838f87d3bce" - ] - }, - "43ad54ad-0bdc-4b6d-8ff5-f838f87d3bce": { - "id": "43ad54ad-0bdc-4b6d-8ff5-f838f87d3bce", - "name": "Runner", - "category": "action", - "title": "Runner", - "description": "", - "properties": {}, - "display": { - "x": 348, - "y": 504 - } - }, - "6728318e-fb51-4f59-8c60-72d0f3b8c8b1": { - "id": "6728318e-fb51-4f59-8c60-72d0f3b8c8b1", - "name": "Runner", - "category": "action", - "title": "Runner", - "description": "", - "properties": {}, - "display": { - "x": 996, - "y": 420 - } - }, - "e1363bca-78ca-4923-995e-074cdcb803cf": { - "id": "e1363bca-78ca-4923-995e-074cdcb803cf", - "name": "Priority", - "category": "composite", - "title": "Priority", - "description": "", - "properties": {}, - "display": { - "x": -312, - "y": 192 - }, - "children": [ - "521239f8-2829-471e-ab43-e0a98d77aab7", - "07529410-ecf9-4d54-ac6e-16982e4b0b25", - "6e65f94a-05f4-410f-be23-01ee2da43240", - "df0cd7eb-848f-49e0-87b6-d0ba50c282f1" - ] - }, - "07529410-ecf9-4d54-ac6e-16982e4b0b25": { - "id": "07529410-ecf9-4d54-ac6e-16982e4b0b25", - "name": "MemSequence", - "category": "composite", - "title": "MemSequence", - "description": "", - "properties": {}, - "display": { - "x": 0, - "y": 108 - }, - "children": [ - "d1b6d256-4b76-441b-a455-bdf592c0a722", - "752d8fae-ade7-4c2f-9d4e-ad066773b1bb", - "cfb3bfdf-67e8-4bb9-9731-be379743e042" - ] - }, - "752d8fae-ade7-4c2f-9d4e-ad066773b1bb": { - "id": "752d8fae-ade7-4c2f-9d4e-ad066773b1bb", - "name": "Priority", - "category": "composite", - "title": "Priority", - "description": "", - "properties": {}, - "display": { - "x": 516, - "y": 240 - }, - "children": [ - "6ffd1efe-4d56-44f8-87a4-e88201b51b48", - "6728318e-fb51-4f59-8c60-72d0f3b8c8b1" - ] - }, - "6ffd1efe-4d56-44f8-87a4-e88201b51b48": { - "id": "6ffd1efe-4d56-44f8-87a4-e88201b51b48", - "name": "Inverter", - "category": "decorator", - "title": "Inverter", - "description": "", - "properties": {}, - "display": { - "x": 636, - "y": 120 - }, - "child": "455ac069-63e9-4f5c-97ff-a0800e3e813d" - }, - "272ca19a-1e93-4de4-915f-f7142312b4bd": { - "id": "272ca19a-1e93-4de4-915f-f7142312b4bd", - "name": "RandIntAction", - "category": "action", - "title": "RandIntAction(,,)", - "description": "随机获得一个[min,max)的整数,保存到黑板的index key中", - "properties": { - "index": "takeCoinDiv", - "min": 10, - "max": 30 - }, - "display": { - "x": 984, - "y": 1236 - } - }, - "406d653d-e148-4722-aecf-ef77500ac21b": { - "id": "406d653d-e148-4722-aecf-ef77500ac21b", - "name": "Sequence", - "category": "composite", - "title": "Sequence", - "description": "", - "properties": {}, - "display": { - "x": 576, - "y": 1272 - }, - "children": [ - "96e4f37b-302f-4fb9-809f-ef0e6d80f3b1", - "272ca19a-1e93-4de4-915f-f7142312b4bd", - "7156278f-75b4-45aa-89aa-e436899fe51b", - "4df6815d-1ff7-4395-8666-aca24a7213b4", - "02997ae9-a706-4e08-8947-e550200db1ca" - ] - }, - "7156278f-75b4-45aa-89aa-e436899fe51b": { - "id": "7156278f-75b4-45aa-89aa-e436899fe51b", - "name": "GetPlayerTakeCoin", - "category": "action", - "title": "GetPlayerTakeCoin()", - "description": "获得玩家入场携带金币\ngINKey 保存黑板key", - "properties": { - "gINKey": "takeCoin" - }, - "display": { - "x": 972, - "y": 1284 - } - }, - "02997ae9-a706-4e08-8947-e550200db1ca": { - "id": "02997ae9-a706-4e08-8947-e550200db1ca", - "name": "CheckPlayerCoin", - "category": "condition", - "title": "CheckPlayerCoin(,)", - "description": "检查用户金币\ngIPCoin 支持@ 用户需要比较的金币\ncmp 比较\t\n 0 //小于\n 1 //小于等于\n 2 //等于\n 3 //大于\n 4 //大于等于", - "properties": { - "gIPCoin": "takeCoin", - "cmp": 0 - }, - "display": { - "x": 960, - "y": 1476 - } - }, - "96e4f37b-302f-4fb9-809f-ef0e6d80f3b1": { - "id": "96e4f37b-302f-4fb9-809f-ef0e6d80f3b1", - "name": "SetIntMulti", - "category": "action", - "title": "SetIntMulti(,,)", - "description": "设置乘法,保存数值\ngINKey 保存黑版key\ngIPValue1 v1 支持@\ngIPValue2 v2 支持@", - "properties": { - "gINKey": "takeCoin", - "gIPValue1": "takeCoin", - "gIPValue2": "takeCoinDiv" - }, - "display": { - "x": 1020, - "y": 1188 - } - }, - "4df6815d-1ff7-4395-8666-aca24a7213b4": { - "id": "4df6815d-1ff7-4395-8666-aca24a7213b4", - "name": "SetIntDiv", - "category": "action", - "title": "SetIntDiv(,,)", - "description": "设定除法保存数据到黑板\ngINKey \ngIPValue1\ngIPValue2", - "properties": { - "gINKey": "takeCoin", - "gIPValue1": "takeCoin", - "gIPValue2": "@100" - }, - "display": { - "x": 984, - "y": 1392 - } - }, - "c764dcd1-7d5e-4e39-a068-8c309dff1484": { - "id": "c764dcd1-7d5e-4e39-a068-8c309dff1484", - "name": "DVTSceneState", - "category": "condition", - "title": "DVTSceneState()", - "description": "龙虎状态检查\n0 准备押注\n1 押注\n2 准备开牌\n3 开牌\n4 准备结算\n5 结算", - "properties": { - "state": 1 - }, - "display": { - "x": 276, - "y": -636 - } - }, - "9d30f3ac-f772-48fb-852e-1acdec9d474f": { - "id": "9d30f3ac-f772-48fb-852e-1acdec9d474f", - "name": "DVTCheckBetCoin", - "category": "action", - "title": "DVTCheckBetCoin(,)", - "description": "龙虎检查下注额度", - "properties": { - "gIPSrcCoin": "betSrcCoin", - "gINSaveCoin": "betSrcCoin" - }, - "display": { - "x": 372, - "y": -276 - } - }, - "3cecf744-3e4b-4ca1-85b0-323aaa576314": { - "id": "3cecf744-3e4b-4ca1-85b0-323aaa576314", - "name": "DVTSceneState", - "category": "condition", - "title": "DVTSceneState()", - "description": "龙虎状态检查\n0 准备押注\n1 押注\n2 准备开牌\n3 开牌\n4 准备结算\n5 结算", - "properties": { - "state": 1 - }, - "display": { - "x": 744, - "y": -240 - } - }, - "2a8386b7-8dfe-4057-84cc-d55f7b027611": { - "id": "2a8386b7-8dfe-4057-84cc-d55f7b027611", - "name": "DVTHistoryIsSame", - "category": "condition", - "title": "DVTHistoryIsSame()", - "description": "判定是上几局都是相同的结果\ngIPNum 支持@", - "properties": { - "gIPNum": "sameNum" - }, - "display": { - "x": 768, - "y": -132 - } - }, - "910076bb-4d07-471e-8280-a55a802ba13f": { - "id": "910076bb-4d07-471e-8280-a55a802ba13f", - "name": "DVTLastWinArea", - "category": "action", - "title": "DVTLastWinArea()", - "description": "龙虎最后获胜的区域保存到黑板", - "properties": { - "gINKey": "betArea" - }, - "display": { - "x": 756, - "y": -84 - } - }, - "ac131866-e93e-4df5-8b18-646af0ffa070": { - "id": "ac131866-e93e-4df5-8b18-646af0ffa070", - "name": "DVTSceneState", - "category": "condition", - "title": "DVTSceneState()", - "description": "龙虎状态检查\n0 准备押注\n1 押注\n2 准备开牌\n3 开牌\n4 准备结算\n5 结算", - "properties": { - "state": 1 - }, - "display": { - "x": 1020, - "y": 84 - } - }, - "6d6f636d-a02a-42b5-9b4c-255c11352a68": { - "id": "6d6f636d-a02a-42b5-9b4c-255c11352a68", - "name": "DVTSceneState", - "category": "condition", - "title": "DVTSceneState()", - "description": "龙虎状态检查\n0 准备押注\n1 押注\n2 准备开牌\n3 开牌\n4 准备结算\n5 结算", - "properties": { - "state": 1 - }, - "display": { - "x": 360, - "y": 432 - } - }, - "2710b442-af43-4350-baf9-eee1e00c2c67": { - "id": "2710b442-af43-4350-baf9-eee1e00c2c67", - "name": "DVTBetCoin", - "category": "action", - "title": "DVTBetCoin(,)", - "description": "龙虎押注", - "properties": { - "gIPBetCoin": "betCoin", - "gIPArea": "betArea" - }, - "display": { - "x": 1068, - "y": 276 - } - }, - "5bfdcdcf-57e3-4a15-8f02-5403d8447550": { - "id": "5bfdcdcf-57e3-4a15-8f02-5403d8447550", - "name": "DVTSceneState", - "category": "condition", - "title": "DVTSceneState()", - "description": "龙虎状态检查\n0 准备押注\n1 押注\n2 准备开牌\n3 开牌\n4 准备结算\n5 结算", - "properties": { - "state": 4 - }, - "display": { - "x": 420, - "y": 612 - } - }, - "094558c6-747d-48d0-8846-3e648f1b58b6": { - "id": "094558c6-747d-48d0-8846-3e648f1b58b6", - "name": "DVTSceneState", - "category": "condition", - "title": "DVTSceneState()", - "description": "龙虎状态检查\n0 准备押注\n1 押注\n2 准备开牌\n3 开牌\n4 准备结算\n5 结算", - "properties": { - "state": 4 - }, - "display": { - "x": 240, - "y": 936 - } - } - }, - "display": { - "camera_x": 575.9850000012666, - "camera_y": -21.6749999972526, - "camera_z": 0.75, - "x": -456, - "y": 192 - }, - "custom_nodes": [ - { - "version": "0.3.0", - "scope": "node", - "name": "RVBSceneState", - "category": "condition", - "title": "RVBSceneState()", - "description": "红黑场景状态判定\n0 准备押注\n1 押注\n2 准备开牌\n3 开牌\n4 结算", - "properties": { - "state": 0 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "RandIntAction", - "category": "action", - "title": "RandIntAction(,,)", - "description": "随机获得一个[min,max)的整数,保存到黑板的index key中", - "properties": { - "index": "key", - "min": 0, - "max": 1 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "RandWait", - "category": "action", - "title": "RandWait(,)", - "description": "节点暂停[minTime,maxTime)毫秒", - "properties": { - "minTime": 0, - "maxTime": 1 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "RandomWeightComposite", - "category": "composite", - "title": "RandomWeightComposite()", - "description": "根据权重随机,选择一个子节点。\n权重使用|分割。\n需要注意子节点的顺序,个数需要和权重对应", - "properties": { - "weight": "\"\"" - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "CheckBool", - "category": "condition", - "title": "CheckBool()", - "description": "检查一个黑板的key值", - "properties": { - "keyName": "key" - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "CheckInt", - "category": "condition", - "title": "CheckInt(,,)", - "description": "检查黑板的一个值和待比较值\n 0 //小于\n 1 //小于等于\n 2 //等于\n 3 //大于\n 4 //大于等于", - "properties": { - "keyName": "key", - "value": 0, - "cmp": 0 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "LogAction", - "category": "action", - "title": "LogAction(,)", - "description": "输出日志", - "properties": { - "info": "info", - "level": 0 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "RVBBetPct", - "category": "action", - "title": "RVBBetPct(,)", - "description": "红黑下注\ngIPpct 下注百分比,黑板key 支持@\ngIPArea 下注区域,黑板key 支持@", - "properties": { - "gIPpct": "key", - "gIPArea": 1 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "RVBLastWinArea", - "category": "action", - "title": "RVBLastWinArea()", - "description": "获得最后的下注结果保存到key,没有返回失败", - "properties": { - "gINKey": "key" - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "LeaveGame", - "category": "action", - "title": "LeaveGame", - "description": "离开游戏", - "properties": {} - }, - { - "version": "0.3.0", - "scope": "node", - "name": "CheckPlayerCoin", - "category": "condition", - "title": "CheckPlayerCoin(,)", - "description": "检查用户金币\ngIPCoin 支持@ 用户需要比较的金币\ncmp 比较\t\n 0 //小于\n 1 //小于等于\n 2 //等于\n 3 //大于\n 4 //大于等于", - "properties": { - "gIPCoin": "key", - "cmp": 0 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "GetOutLimitCoin", - "category": "action", - "title": "GetOutLimitCoin()", - "description": "获得玩家游戏踢出限制\ngINKey 保存到黑板key", - "properties": { - "gINKey": "key" - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "CheckPlayerGameNum", - "category": "condition", - "title": "CheckPlayerGameNum(,)", - "description": "检查用户游戏次数\ngIPGameNum支持@ 用户需要游戏次数\ncmp 比较\t\n 0 //小于\n 1 //小于等于\n 2 //等于\n 3 //大于\n 4 //大于等于", - "properties": { - "gIPGameNum": "key", - "cmp": 0 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "CheckPlayerLastWinOrLost", - "category": "condition", - "title": "CheckPlayerLastWinOrLost(,)", - "description": "检查玩家上次输赢情况\ngIPLResult 比较值 支持@\ncmp 比较", - "properties": { - "gIPLResult": "key", - "cmp": 0 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "SetIntAction", - "category": "action", - "title": "SetIntAction(,)", - "description": "设置int参数值\ngINKey 黑版key值\ngIPValue 设置的值,支持@", - "properties": { - "gINKey": "key", - "gIPValue": 0 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "RVBBetCoin", - "category": "action", - "title": "RVBBetCoin(,)", - "description": "红黑押注\ngIPBetCoin 押注金额 支持@\ngIPArea 押注区域支持@", - "properties": { - "gIPBetCoin": "key", - "gIPArea": 0 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "RVBCheckBetCoin", - "category": "action", - "title": "RVBCheckBetCoin(,)", - "description": "修正押注金额,保存到黑板key\ngIPSrcCoin 押注金额支持@\ngINSaveCoin 保存后key", - "properties": { - "gIPSrcCoin": "key", - "gINSaveCoin": 0 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "SetIntMulti", - "category": "action", - "title": "SetIntMulti(,,)", - "description": "设置乘法,保存数值\ngINKey 保存黑版key\ngIPValue1 v1 支持@\ngIPValue2 v2 支持@", - "properties": { - "gINKey": "key", - "gIPValue1": 0, - "gIPValue2": 0 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "GetPlayerCoin", - "category": "action", - "title": "GetPlayerCoin()", - "description": "得到玩家金币\ngINKey 保存key", - "properties": { - "gINKey": "key" - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "SetIntDiv", - "category": "action", - "title": "SetIntDiv(,,)", - "description": "设定除法保存数据到黑板\ngINKey \ngIPValue1\ngIPValue2", - "properties": { - "gINKey": "key", - "gIPValue1": 0, - "gIPValue2": 0 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "RVBHistoryIsSame", - "category": "condition", - "title": "RVBHistoryIsSame()", - "description": "判定是上几局都是相同的结果", - "properties": { - "gIPNum": "key", - "num": 0 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "GetPlayerTakeCoin", - "category": "action", - "title": "GetPlayerTakeCoin()", - "description": "获得玩家入场携带金币\ngINKey 保存黑板key", - "properties": { - "gINKey": "key" - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "DVTHistoryIsSame", - "category": "condition", - "title": "DVTHistoryIsSame()", - "description": "判定是上几局都是相同的结果\ngIPNum 支持@", - "properties": { - "gIPNum": "key" - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "DVTLastWinArea", - "category": "action", - "title": "DVTLastWinArea()", - "description": "龙虎最后获胜的区域保存到黑板", - "properties": { - "gINKey": "key" - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "DVTBetCoin", - "category": "action", - "title": "DVTBetCoin(,)", - "description": "龙虎押注", - "properties": { - "gIPBetCoin": "key", - "gIPArea": 0 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "DVTCheckBetCoin", - "category": "action", - "title": "DVTCheckBetCoin(,)", - "description": "龙虎检查下注额度", - "properties": { - "gIPSrcCoin": 0, - "gINSaveCoin": 0 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "DVTSceneState", - "category": "condition", - "title": "DVTSceneState()", - "description": "龙虎状态检查\n0 准备押注\n1 押注\n2 准备开牌\n3 开牌\n4 结算", - "properties": { - "state": 0 - } - } - ] -} \ No newline at end of file diff --git a/data/botai/dvtinvertwin.json b/data/botai/dvtinvertwin.json deleted file mode 100644 index a0dbd91..0000000 --- a/data/botai/dvtinvertwin.json +++ /dev/null @@ -1,1284 +0,0 @@ -{ - "version": "0.3.0", - "scope": "tree", - "id": "b5731d3a-691c-4271-b818-444f5ba03491", - "title": "DVTInvertWinBot", - "description": "龙虎 反手", - "root": "c56e902a-2191-47b2-a231-b285b27707f6", - "properties": {}, - "nodes": { - "3867ed0e-725c-48eb-894e-3aa618a6c5c9": { - "id": "3867ed0e-725c-48eb-894e-3aa618a6c5c9", - "name": "Sequence", - "category": "composite", - "title": "Sequence", - "description": "", - "properties": {}, - "display": { - "x": 408, - "y": -36 - }, - "children": [ - "6822b96d-08af-4d7f-8cba-9c3807b37e8e", - "774f427b-e3e6-4d3d-9521-f8b9adfcce19", - "3df61c16-0be3-4ef7-8b5a-25da08835e63", - "1e66e380-efd6-41fb-8a44-a3abf61e8ed3", - "ad07b001-3deb-4e63-80fb-dbd36cbc8c8c", - "aaccb693-07ea-487a-81e9-c5cc722f93d7", - "ff99a45d-d3ee-4d94-8339-49a315ffe90c" - ] - }, - "f9d918a1-7bde-4331-82ef-00e607dd09c2": { - "id": "f9d918a1-7bde-4331-82ef-00e607dd09c2", - "name": "RandIntAction", - "category": "action", - "title": "RandIntAction(,,)", - "description": "随机获得一个[min,max)的整数,保存到黑板的index key中", - "properties": { - "index": "betSrcCoin", - "min": 2, - "max": 6 - }, - "display": { - "x": 372, - "y": -432 - } - }, - "ec2fbcaa-a1ec-44b0-8976-6b00ea0a20b3": { - "id": "ec2fbcaa-a1ec-44b0-8976-6b00ea0a20b3", - "name": "RandWait", - "category": "action", - "title": "RandWait(,)", - "description": "节点暂停[minTime,maxTime)毫秒", - "properties": { - "minTime": 600, - "maxTime": 1200 - }, - "display": { - "x": 1140, - "y": 384 - } - }, - "586f564f-4237-441e-9a97-04c7a9b78043": { - "id": "586f564f-4237-441e-9a97-04c7a9b78043", - "name": "Sequence", - "category": "composite", - "title": "Sequence", - "description": "", - "properties": {}, - "display": { - "x": 72, - "y": 1092 - }, - "children": [ - "49df9afd-f126-4814-a45c-9b5372af2f7b", - "bd9d99c8-e75e-442e-aaa5-7aac04258a1c", - "4cf8eb59-7a37-49b7-83a2-331bf817da20", - "7312a87b-d3f7-42c5-b7fb-d0773b0051e1" - ] - }, - "7ab20fd5-902d-4839-9fca-4c52ee5f580a": { - "id": "7ab20fd5-902d-4839-9fca-4c52ee5f580a", - "name": "CheckPlayerCoin", - "category": "condition", - "title": "CheckPlayerCoin(,)", - "description": "检查用户金币\ngIPCoin 支持@ 用户需要比较的金币\ncmp 比较\t\n 0 //小于\n 1 //小于等于\n 2 //等于\n 3 //大于\n 4 //大于等于", - "properties": { - "gIPCoin": "saveLimit", - "cmp": 0 - }, - "display": { - "x": 960, - "y": 996 - } - }, - "330dfd90-d165-444a-9ccb-fca9888d864c": { - "id": "330dfd90-d165-444a-9ccb-fca9888d864c", - "name": "GetOutLimitCoin", - "category": "action", - "title": "GetOutLimitCoin()", - "description": "获得玩家游戏踢出限制\ngINKey 保存到黑板key", - "properties": { - "gINKey": "saveLimit" - }, - "display": { - "x": 948, - "y": 924 - } - }, - "4cf8eb59-7a37-49b7-83a2-331bf817da20": { - "id": "4cf8eb59-7a37-49b7-83a2-331bf817da20", - "name": "RandWait", - "category": "action", - "title": "RandWait(,)", - "description": "节点暂停[minTime,maxTime)毫秒", - "properties": { - "minTime": 500, - "maxTime": 3500 - }, - "display": { - "x": 300, - "y": 1248 - } - }, - "7312a87b-d3f7-42c5-b7fb-d0773b0051e1": { - "id": "7312a87b-d3f7-42c5-b7fb-d0773b0051e1", - "name": "LeaveGame", - "category": "action", - "title": "LeaveGame", - "description": "离开游戏", - "properties": {}, - "display": { - "x": 264, - "y": 1392 - } - }, - "605190eb-13f1-4636-8726-8bae569b4f3a": { - "id": "605190eb-13f1-4636-8726-8bae569b4f3a", - "name": "CheckPlayerGameNum", - "category": "condition", - "title": "CheckPlayerGameNum(,)", - "description": "检查用户游戏次数\ngIPGameNum支持@ 用户需要游戏次数\ncmp 比较\t\n 0 //小于\n 1 //小于等于\n 2 //等于\n 3 //大于\n 4 //大于等于", - "properties": { - "gIPGameNum": "maxGameNum", - "cmp": 4 - }, - "display": { - "x": 1008, - "y": 1176 - } - }, - "fe24c868-4d2e-4736-8a20-6d394654e830": { - "id": "fe24c868-4d2e-4736-8a20-6d394654e830", - "name": "RandIntAction", - "category": "action", - "title": "RandIntAction(,,)", - "description": "随机获得一个[min,max)的整数,保存到黑板的index key中", - "properties": { - "index": "maxGameNum", - "min": 5, - "max": 30 - }, - "display": { - "x": 984, - "y": 1092 - } - }, - "7cde24c8-9874-4a78-a506-171133d3e99e": { - "id": "7cde24c8-9874-4a78-a506-171133d3e99e", - "name": "Sequence", - "category": "composite", - "title": "Sequence", - "description": "生成初始押注额度", - "properties": {}, - "display": { - "x": 132, - "y": -372 - }, - "children": [ - "f215847a-03fe-4790-81cc-e19a50a41d1c", - "d90b1fa5-51c2-4432-86c0-ac31f91fe880", - "9a6c0d30-d420-4451-b515-5c79c726703c", - "f9d918a1-7bde-4331-82ef-00e607dd09c2", - "78f3f7d0-b86b-434e-8d16-d0268571be3f", - "b7a65e1f-333f-4b4f-8c45-e1928cfabe73", - "8a859274-7f02-48f8-81b9-99f92a8a36a4", - "f98e90d0-eb06-41ac-b6af-3e9c812f5a62" - ] - }, - "d90b1fa5-51c2-4432-86c0-ac31f91fe880": { - "id": "d90b1fa5-51c2-4432-86c0-ac31f91fe880", - "name": "CheckInt", - "category": "condition", - "title": "CheckInt(,,)", - "description": "检查黑板的一个值和待比较值\n 0 //小于\n 1 //小于等于\n 2 //等于\n 3 //大于\n 4 //大于等于", - "properties": { - "keyName": "needStartBet", - "value": 0, - "cmp": 2 - }, - "display": { - "x": 348, - "y": -528 - } - }, - "9a6c0d30-d420-4451-b515-5c79c726703c": { - "id": "9a6c0d30-d420-4451-b515-5c79c726703c", - "name": "SetIntAction", - "category": "action", - "title": "SetIntAction(,)", - "description": "设置int参数值\ngINKey 黑版key值\ngIPValue 设置的值,支持@", - "properties": { - "gINKey": "needStartBet", - "gIPValue": "@1" - }, - "display": { - "x": 372, - "y": -480 - } - }, - "ad07b001-3deb-4e63-80fb-dbd36cbc8c8c": { - "id": "ad07b001-3deb-4e63-80fb-dbd36cbc8c8c", - "name": "SetIntMulti", - "category": "action", - "title": "SetIntMulti(,,)", - "description": "设置乘法,保存数值\ngINKey 保存黑版key\ngIPValue1 v1 支持@\ngIPValue2 v2 支持@", - "properties": { - "gINKey": "betCoin", - "gIPValue1": "betSrcCoin", - "gIPValue2": "needStartBet" - }, - "display": { - "x": 864, - "y": 24 - } - }, - "aaccb693-07ea-487a-81e9-c5cc722f93d7": { - "id": "aaccb693-07ea-487a-81e9-c5cc722f93d7", - "name": "SetIntMulti", - "category": "action", - "title": "SetIntMulti(,,)", - "description": "设置乘法,保存数值\ngINKey 保存黑版key\ngIPValue1 v1 支持@\ngIPValue2 v2 支持@", - "properties": { - "gINKey": "needStartBet", - "gIPValue1": "needStartBet", - "gIPValue2": "@2" - }, - "display": { - "x": 852, - "y": 72 - } - }, - "b5f58277-0cfe-4c4e-96b7-20b1d72d580c": { - "id": "b5f58277-0cfe-4c4e-96b7-20b1d72d580c", - "name": "Sequence", - "category": "composite", - "title": "Sequence", - "description": "", - "properties": {}, - "display": { - "x": 228, - "y": 744 - }, - "children": [ - "37c3cb74-8b30-4a5f-8df5-55b8dc8e46ac", - "aed37422-3a02-4ab7-806d-84554f73c28a", - "b3dd5c17-cca0-4dfa-8ace-1944fb37749f" - ] - }, - "aed37422-3a02-4ab7-806d-84554f73c28a": { - "id": "aed37422-3a02-4ab7-806d-84554f73c28a", - "name": "CheckPlayerLastWinOrLost", - "category": "condition", - "title": "CheckPlayerLastWinOrLost(,)", - "description": "检查玩家上次输赢情况\ngIPLResult 比较值 支持@\ncmp 比较", - "properties": { - "gIPLResult": "@1", - "cmp": 2 - }, - "display": { - "x": 528, - "y": 732 - } - }, - "b3dd5c17-cca0-4dfa-8ace-1944fb37749f": { - "id": "b3dd5c17-cca0-4dfa-8ace-1944fb37749f", - "name": "SetIntAction", - "category": "action", - "title": "SetIntAction(,)", - "description": "设置int参数值\ngINKey 黑版key值\ngIPValue 设置的值,支持@", - "properties": { - "gINKey": "needStartBet", - "gIPValue": "@0" - }, - "display": { - "x": 516, - "y": 804 - } - }, - "78f3f7d0-b86b-434e-8d16-d0268571be3f": { - "id": "78f3f7d0-b86b-434e-8d16-d0268571be3f", - "name": "GetPlayerCoin", - "category": "action", - "title": "GetPlayerCoin()", - "description": "得到玩家金币\ngINKey 保存key", - "properties": { - "gINKey": "playerCoin" - }, - "display": { - "x": 360, - "y": -384 - } - }, - "b7a65e1f-333f-4b4f-8c45-e1928cfabe73": { - "id": "b7a65e1f-333f-4b4f-8c45-e1928cfabe73", - "name": "SetIntMulti", - "category": "action", - "title": "SetIntMulti(,,)", - "description": "设置乘法,保存数值\ngINKey 保存黑版key\ngIPValue1 v1 支持@\ngIPValue2 v2 支持@", - "properties": { - "gINKey": "betSrcCoin", - "gIPValue1": "betSrcCoin", - "gIPValue2": "playerCoin" - }, - "display": { - "x": 432, - "y": -336 - } - }, - "8a859274-7f02-48f8-81b9-99f92a8a36a4": { - "id": "8a859274-7f02-48f8-81b9-99f92a8a36a4", - "name": "SetIntDiv", - "category": "action", - "title": "SetIntDiv(,,)", - "description": "设定除法保存数据到黑板\ngINKey \ngIPValue1\ngIPValue2", - "properties": { - "gINKey": "betSrcCoin", - "gIPValue1": "betSrcCoin", - "gIPValue2": "@100" - }, - "display": { - "x": 408, - "y": -288 - } - }, - "bd9d99c8-e75e-442e-aaa5-7aac04258a1c": { - "id": "bd9d99c8-e75e-442e-aaa5-7aac04258a1c", - "name": "Priority", - "category": "composite", - "title": "Priority", - "description": "", - "properties": {}, - "display": { - "x": 384, - "y": 1104 - }, - "children": [ - "3ea8c5e0-83b1-44c3-94ed-022c74c81632", - "1abc8dc0-7dd3-4b58-834b-ff96a7d4f781", - "3a901eb5-8890-41fb-8b6a-598d30478429", - "51676728-ebe5-4481-8387-30b840749182" - ] - }, - "3ea8c5e0-83b1-44c3-94ed-022c74c81632": { - "id": "3ea8c5e0-83b1-44c3-94ed-022c74c81632", - "name": "Sequence", - "category": "composite", - "title": "Sequence", - "description": "", - "properties": {}, - "display": { - "x": 624, - "y": 1020 - }, - "children": [ - "330dfd90-d165-444a-9ccb-fca9888d864c", - "7ab20fd5-902d-4839-9fca-4c52ee5f580a" - ] - }, - "1abc8dc0-7dd3-4b58-834b-ff96a7d4f781": { - "id": "1abc8dc0-7dd3-4b58-834b-ff96a7d4f781", - "name": "Sequence", - "category": "composite", - "title": "Sequence", - "description": "", - "properties": {}, - "display": { - "x": 624, - "y": 1176 - }, - "children": [ - "fe24c868-4d2e-4736-8a20-6d394654e830", - "605190eb-13f1-4636-8726-8bae569b4f3a" - ] - }, - "774f427b-e3e6-4d3d-9521-f8b9adfcce19": { - "id": "774f427b-e3e6-4d3d-9521-f8b9adfcce19", - "name": "RandIntAction", - "category": "action", - "title": "RandIntAction(,,)", - "description": "随机获得一个[min,max)的整数,保存到黑板的index key中", - "properties": { - "index": "sameNum", - "min": 3, - "max": 5 - }, - "display": { - "x": 816, - "y": -132 - } - }, - "7a10ce37-bf1b-4a54-9969-3dac615b4f3f": { - "id": "7a10ce37-bf1b-4a54-9969-3dac615b4f3f", - "name": "Sequence", - "category": "composite", - "title": "Sequence", - "description": "", - "properties": {}, - "display": { - "x": 864, - "y": 324 - }, - "children": [ - "bf3a8e66-e69a-4b99-98a9-c5ad44c0a72a", - "a36141c4-c760-4400-b6a1-4509723f1f50", - "ec2fbcaa-a1ec-44b0-8976-6b00ea0a20b3", - "618f7726-459b-4d7e-8b0f-77d4ee097fa5" - ] - }, - "618f7726-459b-4d7e-8b0f-77d4ee097fa5": { - "id": "618f7726-459b-4d7e-8b0f-77d4ee097fa5", - "name": "Priority", - "category": "composite", - "title": "Priority", - "description": "", - "properties": {}, - "display": { - "x": 948, - "y": 468 - }, - "children": [ - "1d79bf2a-0d2b-448b-8db5-fffc8b3be7b1", - "88f78ad3-58c7-494a-8979-b87b63ce74ea" - ] - }, - "88f78ad3-58c7-494a-8979-b87b63ce74ea": { - "id": "88f78ad3-58c7-494a-8979-b87b63ce74ea", - "name": "SetIntAction", - "category": "action", - "title": "SetIntAction(,)", - "description": "设置int参数值\ngINKey 黑版key值\ngIPValue 设置的值,支持@", - "properties": { - "gINKey": "betIsOk", - "gIPValue": "@1" - }, - "display": { - "x": 1152, - "y": 528 - } - }, - "a36141c4-c760-4400-b6a1-4509723f1f50": { - "id": "a36141c4-c760-4400-b6a1-4509723f1f50", - "name": "CheckInt", - "category": "condition", - "title": "CheckInt(,,)", - "description": "检查黑板的一个值和待比较值\n 0 //小于\n 1 //小于等于\n 2 //等于\n 3 //大于\n 4 //大于等于", - "properties": { - "keyName": "betIsOk", - "value": 0, - "cmp": 2 - }, - "display": { - "x": 1128, - "y": 324 - } - }, - "2348b6b7-1a1d-4d43-8023-8a3b49216095": { - "id": "2348b6b7-1a1d-4d43-8023-8a3b49216095", - "name": "SetIntAction", - "category": "action", - "title": "SetIntAction(,)", - "description": "设置int参数值\ngINKey 黑版key值\ngIPValue 设置的值,支持@", - "properties": { - "gINKey": "betIsOk", - "gIPValue": "@0" - }, - "display": { - "x": 420, - "y": 408 - } - }, - "51676728-ebe5-4481-8387-30b840749182": { - "id": "51676728-ebe5-4481-8387-30b840749182", - "name": "CheckPlayerCoin", - "category": "condition", - "title": "CheckPlayerCoin(,)", - "description": "检查用户金币\ngIPCoin 支持@ 用户需要比较的金币\ncmp 比较\t\n 0 //小于\n 1 //小于等于\n 2 //等于\n 3 //大于\n 4 //大于等于", - "properties": { - "gIPCoin": "betCoin", - "cmp": 0 - }, - "display": { - "x": 708, - "y": 1572 - } - }, - "fecdf0a9-1d1a-478b-9e92-9211c580b3b9": { - "id": "fecdf0a9-1d1a-478b-9e92-9211c580b3b9", - "name": "Sequence", - "category": "composite", - "title": "Sequence", - "description": "", - "properties": {}, - "display": { - "x": 180, - "y": 444 - }, - "children": [ - "2348b6b7-1a1d-4d43-8023-8a3b49216095", - "f0371824-9be3-4dc0-b447-cf9b56700fbf", - "f0330c18-245c-4d33-865b-489577e03d1d" - ] - }, - "f0330c18-245c-4d33-865b-489577e03d1d": { - "id": "f0330c18-245c-4d33-865b-489577e03d1d", - "name": "Runner", - "category": "action", - "title": "Runner", - "description": "", - "properties": {}, - "display": { - "x": 396, - "y": 552 - } - }, - "054cdb7e-e898-445a-ac1b-0b9692477a42": { - "id": "054cdb7e-e898-445a-ac1b-0b9692477a42", - "name": "Runner", - "category": "action", - "title": "Runner", - "description": "", - "properties": {}, - "display": { - "x": 1092, - "y": 600 - } - }, - "c56e902a-2191-47b2-a231-b285b27707f6": { - "id": "c56e902a-2191-47b2-a231-b285b27707f6", - "name": "Priority", - "category": "composite", - "title": "Priority", - "description": "", - "properties": {}, - "display": { - "x": -264, - "y": 240 - }, - "children": [ - "7cde24c8-9874-4a78-a506-171133d3e99e", - "4263203b-9944-43e9-aaf6-3590c05b5e4f", - "b5f58277-0cfe-4c4e-96b7-20b1d72d580c", - "586f564f-4237-441e-9a97-04c7a9b78043" - ] - }, - "4263203b-9944-43e9-aaf6-3590c05b5e4f": { - "id": "4263203b-9944-43e9-aaf6-3590c05b5e4f", - "name": "MemSequence", - "category": "composite", - "title": "MemSequence", - "description": "", - "properties": {}, - "display": { - "x": 48, - "y": 156 - }, - "children": [ - "3867ed0e-725c-48eb-894e-3aa618a6c5c9", - "d889262c-2397-47ad-8eee-43d7e3057ffd", - "fecdf0a9-1d1a-478b-9e92-9211c580b3b9" - ] - }, - "d889262c-2397-47ad-8eee-43d7e3057ffd": { - "id": "d889262c-2397-47ad-8eee-43d7e3057ffd", - "name": "Priority", - "category": "composite", - "title": "Priority", - "description": "", - "properties": {}, - "display": { - "x": 612, - "y": 360 - }, - "children": [ - "50c7c380-4ccc-4062-8681-e12e1b7fc9a7", - "054cdb7e-e898-445a-ac1b-0b9692477a42" - ] - }, - "50c7c380-4ccc-4062-8681-e12e1b7fc9a7": { - "id": "50c7c380-4ccc-4062-8681-e12e1b7fc9a7", - "name": "Inverter", - "category": "decorator", - "title": "Inverter", - "description": "", - "properties": {}, - "display": { - "x": 732, - "y": 300 - }, - "child": "7a10ce37-bf1b-4a54-9969-3dac615b4f3f" - }, - "ff99a45d-d3ee-4d94-8339-49a315ffe90c": { - "id": "ff99a45d-d3ee-4d94-8339-49a315ffe90c", - "name": "Priority", - "category": "composite", - "title": "Priority", - "description": "", - "properties": {}, - "display": { - "x": 708, - "y": 144 - }, - "children": [ - "df2b9c40-653c-471d-8cdc-c222dfdcf7ec", - "fb863925-3ebf-4e50-84e4-d7748e72a54f" - ] - }, - "df2b9c40-653c-471d-8cdc-c222dfdcf7ec": { - "id": "df2b9c40-653c-471d-8cdc-c222dfdcf7ec", - "name": "Sequence", - "category": "composite", - "title": "Sequence", - "description": "", - "properties": {}, - "display": { - "x": 1044, - "y": 120 - }, - "children": [ - "3ebb51ae-3e7f-4746-8cc9-7f5188db0eb9", - "1dca51b7-6ed4-4a50-b07a-1d7b04d9575e" - ] - }, - "3ebb51ae-3e7f-4746-8cc9-7f5188db0eb9": { - "id": "3ebb51ae-3e7f-4746-8cc9-7f5188db0eb9", - "name": "CheckInt", - "category": "condition", - "title": "CheckInt(,,)", - "description": "检查黑板的一个值和待比较值\n 0 //小于\n 1 //小于等于\n 2 //等于\n 3 //大于\n 4 //大于等于", - "properties": { - "keyName": "betArea", - "value": 1, - "cmp": 2 - }, - "display": { - "x": 1308, - "y": 0 - } - }, - "1dca51b7-6ed4-4a50-b07a-1d7b04d9575e": { - "id": "1dca51b7-6ed4-4a50-b07a-1d7b04d9575e", - "name": "SetIntAction", - "category": "action", - "title": "SetIntAction(,)", - "description": "设置int参数值\ngINKey 黑版key值\ngIPValue 设置的值,支持@", - "properties": { - "gINKey": "betArea", - "gIPValue": "@2" - }, - "display": { - "x": 1332, - "y": 60 - } - }, - "fb863925-3ebf-4e50-84e4-d7748e72a54f": { - "id": "fb863925-3ebf-4e50-84e4-d7748e72a54f", - "name": "Sequence", - "category": "composite", - "title": "Sequence", - "description": "", - "properties": {}, - "display": { - "x": 1044, - "y": 168 - }, - "children": [ - "e09fcf87-4ff0-4550-8364-b069fe0ffe63", - "5b1368c6-5692-4ed7-a79b-1d606a08e97d" - ] - }, - "e09fcf87-4ff0-4550-8364-b069fe0ffe63": { - "id": "e09fcf87-4ff0-4550-8364-b069fe0ffe63", - "name": "CheckInt", - "category": "condition", - "title": "CheckInt(,,)", - "description": "检查黑板的一个值和待比较值\n 0 //小于\n 1 //小于等于\n 2 //等于\n 3 //大于\n 4 //大于等于", - "properties": { - "keyName": "betArea", - "value": 2, - "cmp": 2 - }, - "display": { - "x": 1332, - "y": 108 - } - }, - "5b1368c6-5692-4ed7-a79b-1d606a08e97d": { - "id": "5b1368c6-5692-4ed7-a79b-1d606a08e97d", - "name": "SetIntAction", - "category": "action", - "title": "SetIntAction(,)", - "description": "设置int参数值\ngINKey 黑版key值\ngIPValue 设置的值,支持@", - "properties": { - "gINKey": "betArea", - "gIPValue": "@1" - }, - "display": { - "x": 1356, - "y": 168 - } - }, - "279f1942-b1da-42a5-a73e-69ad9def364f": { - "id": "279f1942-b1da-42a5-a73e-69ad9def364f", - "name": "RandIntAction", - "category": "action", - "title": "RandIntAction(,,)", - "description": "随机获得一个[min,max)的整数,保存到黑板的index key中", - "properties": { - "index": "takeCoinDiv", - "min": 10, - "max": 30 - }, - "display": { - "x": 972, - "y": 1236 - } - }, - "3a901eb5-8890-41fb-8b6a-598d30478429": { - "id": "3a901eb5-8890-41fb-8b6a-598d30478429", - "name": "Sequence", - "category": "composite", - "title": "Sequence", - "description": "", - "properties": {}, - "display": { - "x": 624, - "y": 1284 - }, - "children": [ - "279f1942-b1da-42a5-a73e-69ad9def364f", - "7386ae1b-1eea-4c9c-86cf-bcf4e11bebdf", - "cc25360e-6225-446d-85f6-edb4fe41d2e8", - "28b467fc-e6e0-4e9d-99f6-2765ff6abb87", - "7f241929-d17b-4693-84ae-642e22c82f87" - ] - }, - "7386ae1b-1eea-4c9c-86cf-bcf4e11bebdf": { - "id": "7386ae1b-1eea-4c9c-86cf-bcf4e11bebdf", - "name": "GetPlayerTakeCoin", - "category": "action", - "title": "GetPlayerTakeCoin()", - "description": "获得玩家入场携带金币\ngINKey 保存黑板key", - "properties": { - "gINKey": "takeCoin" - }, - "display": { - "x": 960, - "y": 1284 - } - }, - "7f241929-d17b-4693-84ae-642e22c82f87": { - "id": "7f241929-d17b-4693-84ae-642e22c82f87", - "name": "CheckPlayerCoin", - "category": "condition", - "title": "CheckPlayerCoin(,)", - "description": "检查用户金币\ngIPCoin 支持@ 用户需要比较的金币\ncmp 比较\t\n 0 //小于\n 1 //小于等于\n 2 //等于\n 3 //大于\n 4 //大于等于", - "properties": { - "gIPCoin": "takeCoin", - "cmp": 0 - }, - "display": { - "x": 948, - "y": 1476 - } - }, - "cc25360e-6225-446d-85f6-edb4fe41d2e8": { - "id": "cc25360e-6225-446d-85f6-edb4fe41d2e8", - "name": "SetIntMulti", - "category": "action", - "title": "SetIntMulti(,,)", - "description": "设置乘法,保存数值\ngINKey 保存黑版key\ngIPValue1 v1 支持@\ngIPValue2 v2 支持@", - "properties": { - "gINKey": "takeCoin", - "gIPValue1": "takeCoin", - "gIPValue2": "takeCoinDiv" - }, - "display": { - "x": 1008, - "y": 1344 - } - }, - "28b467fc-e6e0-4e9d-99f6-2765ff6abb87": { - "id": "28b467fc-e6e0-4e9d-99f6-2765ff6abb87", - "name": "SetIntDiv", - "category": "action", - "title": "SetIntDiv(,,)", - "description": "设定除法保存数据到黑板\ngINKey \ngIPValue1\ngIPValue2", - "properties": { - "gINKey": "takeCoin", - "gIPValue1": "takeCoin", - "gIPValue2": "@100" - }, - "display": { - "x": 972, - "y": 1404 - } - }, - "f215847a-03fe-4790-81cc-e19a50a41d1c": { - "id": "f215847a-03fe-4790-81cc-e19a50a41d1c", - "name": "DVTSceneState", - "category": "condition", - "title": "DVTSceneState()", - "description": "龙虎状态检查\n0 准备押注\n1 押注\n2 准备开牌\n3 开牌\n4 准备结算\n5 结算", - "properties": { - "state": 1 - }, - "display": { - "x": 312, - "y": -588 - } - }, - "f98e90d0-eb06-41ac-b6af-3e9c812f5a62": { - "id": "f98e90d0-eb06-41ac-b6af-3e9c812f5a62", - "name": "DVTCheckBetCoin", - "category": "action", - "title": "DVTCheckBetCoin(,)", - "description": "龙虎检查下注额度", - "properties": { - "gIPSrcCoin": "betSrcCoin", - "gINSaveCoin": "betSrcCoin" - }, - "display": { - "x": 420, - "y": -228 - } - }, - "6822b96d-08af-4d7f-8cba-9c3807b37e8e": { - "id": "6822b96d-08af-4d7f-8cba-9c3807b37e8e", - "name": "DVTSceneState", - "category": "condition", - "title": "DVTSceneState()", - "description": "龙虎状态检查\n0 准备押注\n1 押注\n2 准备开牌\n3 开牌\n4 准备结算\n5 结算", - "properties": { - "state": 1 - }, - "display": { - "x": 768, - "y": -192 - } - }, - "3df61c16-0be3-4ef7-8b5a-25da08835e63": { - "id": "3df61c16-0be3-4ef7-8b5a-25da08835e63", - "name": "DVTHistoryIsSame", - "category": "condition", - "title": "DVTHistoryIsSame()", - "description": "判定是上几局都是相同的结果\ngIPNum 支持@", - "properties": { - "gIPNum": "sameNum" - }, - "display": { - "x": 804, - "y": -84 - } - }, - "1e66e380-efd6-41fb-8a44-a3abf61e8ed3": { - "id": "1e66e380-efd6-41fb-8a44-a3abf61e8ed3", - "name": "DVTLastWinArea", - "category": "action", - "title": "DVTLastWinArea()", - "description": "龙虎最后获胜的区域保存到黑板", - "properties": { - "gINKey": "betArea" - }, - "display": { - "x": 792, - "y": -36 - } - }, - "bf3a8e66-e69a-4b99-98a9-c5ad44c0a72a": { - "id": "bf3a8e66-e69a-4b99-98a9-c5ad44c0a72a", - "name": "DVTSceneState", - "category": "condition", - "title": "DVTSceneState()", - "description": "龙虎状态检查\n0 准备押注\n1 押注\n2 准备开牌\n3 开牌\n4 准备结算\n5 结算", - "properties": { - "state": 1 - }, - "display": { - "x": 1104, - "y": 264 - } - }, - "1d79bf2a-0d2b-448b-8db5-fffc8b3be7b1": { - "id": "1d79bf2a-0d2b-448b-8db5-fffc8b3be7b1", - "name": "DVTBetCoin", - "category": "action", - "title": "DVTBetCoin(,)", - "description": "龙虎押注", - "properties": { - "gIPBetCoin": "betCoin", - "gIPArea": "betArea" - }, - "display": { - "x": 1164, - "y": 456 - } - }, - "f0371824-9be3-4dc0-b447-cf9b56700fbf": { - "id": "f0371824-9be3-4dc0-b447-cf9b56700fbf", - "name": "DVTSceneState", - "category": "condition", - "title": "DVTSceneState()", - "description": "龙虎状态检查\n0 准备押注\n1 押注\n2 准备开牌\n3 开牌\n4 准备结算\n5 结算", - "properties": { - "state": 1 - }, - "display": { - "x": 396, - "y": 480 - } - }, - "37c3cb74-8b30-4a5f-8df5-55b8dc8e46ac": { - "id": "37c3cb74-8b30-4a5f-8df5-55b8dc8e46ac", - "name": "DVTSceneState", - "category": "condition", - "title": "DVTSceneState()", - "description": "龙虎状态检查\n0 准备押注\n1 押注\n2 准备开牌\n3 开牌\n4 准备结算\n5 结算", - "properties": { - "state": 4 - }, - "display": { - "x": 468, - "y": 672 - } - }, - "49df9afd-f126-4814-a45c-9b5372af2f7b": { - "id": "49df9afd-f126-4814-a45c-9b5372af2f7b", - "name": "DVTSceneState", - "category": "condition", - "title": "DVTSceneState()", - "description": "龙虎状态检查\n0 准备押注\n1 押注\n2 准备开牌\n3 开牌\n4 准备结算\n5 结算", - "properties": { - "state": 4 - }, - "display": { - "x": 300, - "y": 996 - } - } - }, - "display": { - "camera_x": 222.7900000035297, - "camera_y": -608.9149999988731, - "camera_z": 1, - "x": -444, - "y": 240 - }, - "custom_nodes": [ - { - "version": "0.3.0", - "scope": "node", - "name": "RVBSceneState", - "category": "condition", - "title": "RVBSceneState()", - "description": "红黑场景状态判定\n0 准备押注\n1 押注\n2 准备开牌\n3 开牌\n4 结算", - "properties": { - "state": 0 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "RandIntAction", - "category": "action", - "title": "RandIntAction(,,)", - "description": "随机获得一个[min,max)的整数,保存到黑板的index key中", - "properties": { - "index": "key", - "min": 0, - "max": 1 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "RandWait", - "category": "action", - "title": "RandWait(,)", - "description": "节点暂停[minTime,maxTime)毫秒", - "properties": { - "minTime": 0, - "maxTime": 1 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "RandomWeightComposite", - "category": "composite", - "title": "RandomWeightComposite()", - "description": "根据权重随机,选择一个子节点。\n权重使用|分割。\n需要注意子节点的顺序,个数需要和权重对应", - "properties": { - "weight": "\"\"" - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "CheckBool", - "category": "condition", - "title": "CheckBool()", - "description": "检查一个黑板的key值", - "properties": { - "keyName": "key" - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "CheckInt", - "category": "condition", - "title": "CheckInt(,,)", - "description": "检查黑板的一个值和待比较值\n 0 //小于\n 1 //小于等于\n 2 //等于\n 3 //大于\n 4 //大于等于", - "properties": { - "keyName": "key", - "value": 0, - "cmp": 0 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "LogAction", - "category": "action", - "title": "LogAction(,)", - "description": "输出日志", - "properties": { - "info": "info", - "level": 0 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "RVBBetPct", - "category": "action", - "title": "RVBBetPct(,)", - "description": "红黑下注\ngIPpct 下注百分比,黑板key 支持@\ngIPArea 下注区域,黑板key 支持@", - "properties": { - "gIPpct": "key", - "gIPArea": 1 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "RVBLastWinArea", - "category": "action", - "title": "RVBLastWinArea()", - "description": "获得最后的下注结果保存到key,没有返回失败", - "properties": { - "gINKey": "key" - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "LeaveGame", - "category": "action", - "title": "LeaveGame", - "description": "离开游戏", - "properties": {} - }, - { - "version": "0.3.0", - "scope": "node", - "name": "CheckPlayerCoin", - "category": "condition", - "title": "CheckPlayerCoin(,)", - "description": "检查用户金币\ngIPCoin 支持@ 用户需要比较的金币\ncmp 比较\t\n 0 //小于\n 1 //小于等于\n 2 //等于\n 3 //大于\n 4 //大于等于", - "properties": { - "gIPCoin": "key", - "cmp": 0 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "GetOutLimitCoin", - "category": "action", - "title": "GetOutLimitCoin()", - "description": "获得玩家游戏踢出限制\ngINKey 保存到黑板key", - "properties": { - "gINKey": "key" - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "CheckPlayerGameNum", - "category": "condition", - "title": "CheckPlayerGameNum(,)", - "description": "检查用户游戏次数\ngIPGameNum支持@ 用户需要游戏次数\ncmp 比较\t\n 0 //小于\n 1 //小于等于\n 2 //等于\n 3 //大于\n 4 //大于等于", - "properties": { - "gIPGameNum": "key", - "cmp": 0 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "CheckPlayerLastWinOrLost", - "category": "condition", - "title": "CheckPlayerLastWinOrLost(,)", - "description": "检查玩家上次输赢情况\ngIPLResult 比较值 支持@\ncmp 比较", - "properties": { - "gIPLResult": "key", - "cmp": 0 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "SetIntAction", - "category": "action", - "title": "SetIntAction(,)", - "description": "设置int参数值\ngINKey 黑版key值\ngIPValue 设置的值,支持@", - "properties": { - "gINKey": "key", - "gIPValue": 0 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "RVBBetCoin", - "category": "action", - "title": "RVBBetCoin(,)", - "description": "红黑押注\ngIPBetCoin 押注金额 支持@\ngIPArea 押注区域支持@", - "properties": { - "gIPBetCoin": "key", - "gIPArea": 0 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "RVBCheckBetCoin", - "category": "action", - "title": "RVBCheckBetCoin(,)", - "description": "修正押注金额,保存到黑板key\ngIPSrcCoin 押注金额支持@\ngINSaveCoin 保存后key", - "properties": { - "gIPSrcCoin": "key", - "gINSaveCoin": 0 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "SetIntMulti", - "category": "action", - "title": "SetIntMulti(,,)", - "description": "设置乘法,保存数值\ngINKey 保存黑版key\ngIPValue1 v1 支持@\ngIPValue2 v2 支持@", - "properties": { - "gINKey": "key", - "gIPValue1": 0, - "gIPValue2": 0 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "GetPlayerCoin", - "category": "action", - "title": "GetPlayerCoin()", - "description": "得到玩家金币\ngINKey 保存key", - "properties": { - "gINKey": "key" - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "SetIntDiv", - "category": "action", - "title": "SetIntDiv(,,)", - "description": "设定除法保存数据到黑板\ngINKey \ngIPValue1\ngIPValue2", - "properties": { - "gINKey": "key", - "gIPValue1": 0, - "gIPValue2": 0 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "RVBHistoryIsSame", - "category": "condition", - "title": "RVBHistoryIsSame()", - "description": "判定是上几局都是相同的结果", - "properties": { - "gIPNum": "key", - "num": 0 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "GetPlayerTakeCoin", - "category": "action", - "title": "GetPlayerTakeCoin()", - "description": "获得玩家入场携带金币\ngINKey 保存黑板key", - "properties": { - "gINKey": "key" - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "DVTHistoryIsSame", - "category": "condition", - "title": "DVTHistoryIsSame()", - "description": "判定是上几局都是相同的结果\ngIPNum 支持@", - "properties": { - "gIPNum": "key" - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "DVTLastWinArea", - "category": "action", - "title": "DVTLastWinArea()", - "description": "龙虎最后获胜的区域保存到黑板", - "properties": { - "gINKey": "key" - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "DVTBetCoin", - "category": "action", - "title": "DVTBetCoin(,)", - "description": "龙虎押注", - "properties": { - "gIPBetCoin": "key", - "gIPArea": 0 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "DVTCheckBetCoin", - "category": "action", - "title": "DVTCheckBetCoin(,)", - "description": "龙虎检查下注额度", - "properties": { - "gIPSrcCoin": 0, - "gINSaveCoin": 0 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "DVTSceneState", - "category": "condition", - "title": "DVTSceneState()", - "description": "龙虎状态检查\n0 准备押注\n1 押注\n2 准备开牌\n3 开牌\n4 结算", - "properties": { - "state": 0 - } - } - ] -} \ No newline at end of file diff --git a/data/botai/dvtrandom.json b/data/botai/dvtrandom.json deleted file mode 100644 index a864e9e..0000000 --- a/data/botai/dvtrandom.json +++ /dev/null @@ -1,1059 +0,0 @@ -{ - "version": "0.3.0", - "scope": "tree", - "id": "e48a3128-ccf5-40fa-825e-85a778c46954", - "title": "DVTRandomBot", - "description": "龙虎随机机器人", - "root": "17a798f7-5270-4c07-b56b-90854a8617a6", - "properties": {}, - "nodes": { - "40bb4ee0-c1e3-4399-8af9-4edba593f737": { - "id": "40bb4ee0-c1e3-4399-8af9-4edba593f737", - "name": "MemSequence", - "category": "composite", - "title": "MemSequence", - "description": "", - "properties": {}, - "display": { - "x": 360, - "y": -300 - }, - "children": [ - "2600c6ff-388f-405d-802f-857a2bc5049e", - "fdc39a2b-01cd-4544-b8fa-fd95f2425e5c", - "f0f1f6db-6623-4152-8879-d15181967caa", - "98e13cbc-ed04-4e85-8b06-4689e5432c2a" - ] - }, - "fdc39a2b-01cd-4544-b8fa-fd95f2425e5c": { - "id": "fdc39a2b-01cd-4544-b8fa-fd95f2425e5c", - "name": "RandWait", - "category": "action", - "title": "RandWait(,)", - "description": "节点暂停[minTime,maxTime)毫秒", - "properties": { - "minTime": 100, - "maxTime": 4000 - }, - "display": { - "x": 744, - "y": -372 - } - }, - "f0f1f6db-6623-4152-8879-d15181967caa": { - "id": "f0f1f6db-6623-4152-8879-d15181967caa", - "name": "RandomWeightComposite", - "category": "composite", - "title": "RandomWeightComposite()", - "description": "根据权重随机,选择一个子节点。\n权重使用|分割。\n需要注意子节点的顺序,个数需要和权重对应", - "properties": { - "weight": "7|100" - }, - "display": { - "x": 732, - "y": -216 - }, - "children": [ - "8cb03d04-efbb-45c4-87ec-8bc7d56dc073", - "8fa27d60-d1bf-4180-86fa-0f7df43964aa" - ] - }, - "17a798f7-5270-4c07-b56b-90854a8617a6": { - "id": "17a798f7-5270-4c07-b56b-90854a8617a6", - "name": "Priority", - "category": "composite", - "title": "Priority", - "description": "", - "properties": {}, - "display": { - "x": 156, - "y": 372 - }, - "children": [ - "40bb4ee0-c1e3-4399-8af9-4edba593f737", - "851f539f-606e-404c-a981-32201499a7c0" - ] - }, - "851f539f-606e-404c-a981-32201499a7c0": { - "id": "851f539f-606e-404c-a981-32201499a7c0", - "name": "Sequence", - "category": "composite", - "title": "Sequence", - "description": "", - "properties": {}, - "display": { - "x": 408, - "y": 612 - }, - "children": [ - "c99835ea-a71f-4259-9a55-a3a47c53ce4c", - "ecfdebd2-e48d-4501-8ffd-33771ea788cd", - "4f583aa3-2fce-482b-87e9-7a23cd10790f", - "2f80c20e-c2ca-4802-9975-b0face24b105" - ] - }, - "6fb0e1c1-6464-4b40-8bfa-883377fb7778": { - "id": "6fb0e1c1-6464-4b40-8bfa-883377fb7778", - "name": "CheckPlayerCoin", - "category": "condition", - "title": "CheckPlayerCoin(,)", - "description": "检查用户金币\ngIPCoin 支持@ 用户需要比较的金币\ncmp 比较\t\n 0 //小于\n 1 //小于等于\n 2 //等于\n 3 //大于\n 4 //大于等于", - "properties": { - "gIPCoin": "saveLimit", - "cmp": 0 - }, - "display": { - "x": 1296, - "y": 516 - } - }, - "716444a6-5f39-44f2-80c0-2181ca3d7689": { - "id": "716444a6-5f39-44f2-80c0-2181ca3d7689", - "name": "GetOutLimitCoin", - "category": "action", - "title": "GetOutLimitCoin()", - "description": "获得玩家游戏踢出限制\ngINKey 保存到黑板key", - "properties": { - "gINKey": "saveLimit" - }, - "display": { - "x": 1284, - "y": 444 - } - }, - "4f583aa3-2fce-482b-87e9-7a23cd10790f": { - "id": "4f583aa3-2fce-482b-87e9-7a23cd10790f", - "name": "RandWait", - "category": "action", - "title": "RandWait(,)", - "description": "节点暂停[minTime,maxTime)毫秒", - "properties": { - "minTime": 500, - "maxTime": 3000 - }, - "display": { - "x": 636, - "y": 768 - } - }, - "2f80c20e-c2ca-4802-9975-b0face24b105": { - "id": "2f80c20e-c2ca-4802-9975-b0face24b105", - "name": "LeaveGame", - "category": "action", - "title": "LeaveGame", - "description": "离开游戏", - "properties": {}, - "display": { - "x": 612, - "y": 960 - } - }, - "e89733da-8e7f-48b9-a0ca-6c7f7b3e0afc": { - "id": "e89733da-8e7f-48b9-a0ca-6c7f7b3e0afc", - "name": "CheckPlayerGameNum", - "category": "condition", - "title": "CheckPlayerGameNum(,)", - "description": "检查用户游戏次数\ngIPGameNum支持@ 用户需要游戏次数\ncmp 比较\t\n 0 //小于\n 1 //小于等于\n 2 //等于\n 3 //大于\n 4 //大于等于", - "properties": { - "gIPGameNum": "maxGameNum", - "cmp": 4 - }, - "display": { - "x": 1344, - "y": 696 - } - }, - "bfc09d8b-40ef-4697-823e-f6c28371a18b": { - "id": "bfc09d8b-40ef-4697-823e-f6c28371a18b", - "name": "RandIntAction", - "category": "action", - "title": "RandIntAction(,,)", - "description": "随机获得一个[min,max)的整数,保存到黑板的index key中", - "properties": { - "index": "maxGameNum", - "min": 5, - "max": 30 - }, - "display": { - "x": 1320, - "y": 612 - } - }, - "ecfdebd2-e48d-4501-8ffd-33771ea788cd": { - "id": "ecfdebd2-e48d-4501-8ffd-33771ea788cd", - "name": "Priority", - "category": "composite", - "title": "Priority", - "description": "", - "properties": {}, - "display": { - "x": 720, - "y": 624 - }, - "children": [ - "801fa819-f99c-4b29-8a4c-6b422614f5ea", - "aeb1db0a-ce87-4673-bfd2-47044ba43af8", - "f927fad5-6bab-4a2e-be7c-98939b76dd32", - "74dc3d66-3022-4aac-8d34-85a52a50f601" - ] - }, - "801fa819-f99c-4b29-8a4c-6b422614f5ea": { - "id": "801fa819-f99c-4b29-8a4c-6b422614f5ea", - "name": "Sequence", - "category": "composite", - "title": "Sequence", - "description": "", - "properties": {}, - "display": { - "x": 960, - "y": 540 - }, - "children": [ - "716444a6-5f39-44f2-80c0-2181ca3d7689", - "6fb0e1c1-6464-4b40-8bfa-883377fb7778" - ] - }, - "aeb1db0a-ce87-4673-bfd2-47044ba43af8": { - "id": "aeb1db0a-ce87-4673-bfd2-47044ba43af8", - "name": "Sequence", - "category": "composite", - "title": "Sequence", - "description": "", - "properties": {}, - "display": { - "x": 960, - "y": 696 - }, - "children": [ - "bfc09d8b-40ef-4697-823e-f6c28371a18b", - "e89733da-8e7f-48b9-a0ca-6c7f7b3e0afc" - ] - }, - "74dc3d66-3022-4aac-8d34-85a52a50f601": { - "id": "74dc3d66-3022-4aac-8d34-85a52a50f601", - "name": "CheckPlayerCoin", - "category": "condition", - "title": "CheckPlayerCoin(,)", - "description": "检查用户金币\ngIPCoin 支持@ 用户需要比较的金币\ncmp 比较\t\n 0 //小于\n 1 //小于等于\n 2 //等于\n 3 //大于\n 4 //大于等于", - "properties": { - "gIPCoin": "betCoin", - "cmp": 0 - }, - "display": { - "x": 1056, - "y": 1152 - } - }, - "ff0cfe0e-b25b-4e57-8350-a988ee16da04": { - "id": "ff0cfe0e-b25b-4e57-8350-a988ee16da04", - "name": "RandIntAction", - "category": "action", - "title": "RandIntAction(,,)", - "description": "随机获得一个[min,max)的整数,保存到黑板的index key中", - "properties": { - "index": "betSrcCoin", - "min": 15, - "max": 35 - }, - "display": { - "x": 768, - "y": -744 - } - }, - "2600c6ff-388f-405d-802f-857a2bc5049e": { - "id": "2600c6ff-388f-405d-802f-857a2bc5049e", - "name": "Sequence", - "category": "composite", - "title": "Sequence", - "description": "生成初始押注额度", - "properties": {}, - "display": { - "x": 516, - "y": -624 - }, - "children": [ - "44aa2c38-49cc-4b47-935c-478671025ebc", - "ff0cfe0e-b25b-4e57-8350-a988ee16da04", - "fca64ef6-59fe-459a-b17b-15f2cb444494", - "f02189b7-d510-4c72-9c90-a6d8d8b22618", - "95b19b79-ba48-4458-85d0-348e30cb89eb", - "a0925c1e-0a2b-4cf3-8ca2-c7b51c80d145", - "524d7dcd-ad9c-49d9-9112-8979a4e5178d" - ] - }, - "fca64ef6-59fe-459a-b17b-15f2cb444494": { - "id": "fca64ef6-59fe-459a-b17b-15f2cb444494", - "name": "GetPlayerCoin", - "category": "action", - "title": "GetPlayerCoin()", - "description": "得到玩家金币\ngINKey 保存key", - "properties": { - "gINKey": "playerCoin" - }, - "display": { - "x": 756, - "y": -684 - } - }, - "95b19b79-ba48-4458-85d0-348e30cb89eb": { - "id": "95b19b79-ba48-4458-85d0-348e30cb89eb", - "name": "SetIntDiv", - "category": "action", - "title": "SetIntDiv(,,)", - "description": "设定除法保存数据到黑板\ngINKey \ngIPValue1\ngIPValue2", - "properties": { - "gINKey": "betSrcCoin", - "gIPValue1": "betSrcCoin", - "gIPValue2": "@100" - }, - "display": { - "x": 804, - "y": -564 - } - }, - "524d7dcd-ad9c-49d9-9112-8979a4e5178d": { - "id": "524d7dcd-ad9c-49d9-9112-8979a4e5178d", - "name": "RandIntAction", - "category": "action", - "title": "RandIntAction(,,)", - "description": "随机获得一个[min,max)的整数,保存到黑板的index key中", - "properties": { - "index": "betArea", - "min": 1, - "max": 3 - }, - "display": { - "x": 756, - "y": -444 - } - }, - "98e13cbc-ed04-4e85-8b06-4689e5432c2a": { - "id": "98e13cbc-ed04-4e85-8b06-4689e5432c2a", - "name": "Sequence", - "category": "composite", - "title": "Sequence", - "description": "", - "properties": {}, - "display": { - "x": 492, - "y": -24 - }, - "children": [ - "edc549af-53dc-4866-b6a8-c8d104f5eb5f", - "8ac94f1b-5ac2-484e-b47e-077f11116c1f" - ] - }, - "8ac94f1b-5ac2-484e-b47e-077f11116c1f": { - "id": "8ac94f1b-5ac2-484e-b47e-077f11116c1f", - "name": "Runner", - "category": "action", - "title": "Runner", - "description": "", - "properties": {}, - "display": { - "x": 672, - "y": 36 - } - }, - "13c0d7af-9312-45e0-89be-bcf852972c7a": { - "id": "13c0d7af-9312-45e0-89be-bcf852972c7a", - "name": "RandWait", - "category": "action", - "title": "RandWait(,)", - "description": "节点暂停[minTime,maxTime)毫秒", - "properties": { - "minTime": 300, - "maxTime": 900 - }, - "display": { - "x": 1524, - "y": -432 - } - }, - "333c338a-edc1-46df-8640-ce69553ec829": { - "id": "333c338a-edc1-46df-8640-ce69553ec829", - "name": "Sequence", - "category": "composite", - "title": "Sequence", - "description": "", - "properties": {}, - "display": { - "x": 1332, - "y": -372 - }, - "children": [ - "18f20a87-f766-48c3-866b-d88a27b25f9e", - "28932c02-c37d-4060-8253-b10cd2c9d224", - "13c0d7af-9312-45e0-89be-bcf852972c7a", - "1297e23e-f652-4224-81b1-645a65bab464" - ] - }, - "f564c5ce-896f-46e3-90b9-3bea59defa88": { - "id": "f564c5ce-896f-46e3-90b9-3bea59defa88", - "name": "Runner", - "category": "action", - "title": "Runner", - "description": "", - "properties": {}, - "display": { - "x": 1488, - "y": -228 - } - }, - "8cb03d04-efbb-45c4-87ec-8bc7d56dc073": { - "id": "8cb03d04-efbb-45c4-87ec-8bc7d56dc073", - "name": "Priority", - "category": "composite", - "title": "Priority", - "description": "", - "properties": {}, - "display": { - "x": 1056, - "y": -240 - }, - "children": [ - "3959a9c9-ea71-4034-b5f9-e3f014cc17fc", - "f564c5ce-896f-46e3-90b9-3bea59defa88" - ] - }, - "3959a9c9-ea71-4034-b5f9-e3f014cc17fc": { - "id": "3959a9c9-ea71-4034-b5f9-e3f014cc17fc", - "name": "Inverter", - "category": "decorator", - "title": "Inverter", - "description": "", - "properties": {}, - "display": { - "x": 1212, - "y": -312 - }, - "child": "333c338a-edc1-46df-8640-ce69553ec829" - }, - "4a212c84-5d1d-4e5d-8c0f-a9f9d11e439d": { - "id": "4a212c84-5d1d-4e5d-8c0f-a9f9d11e439d", - "name": "RandWait", - "category": "action", - "title": "RandWait(,)", - "description": "节点暂停[minTime,maxTime)毫秒", - "properties": { - "minTime": 200, - "maxTime": 600 - }, - "display": { - "x": 1524, - "y": -132 - } - }, - "c10ca763-66cf-4b6c-87d7-ca835f7974e9": { - "id": "c10ca763-66cf-4b6c-87d7-ca835f7974e9", - "name": "Sequence", - "category": "composite", - "title": "Sequence", - "description": "", - "properties": {}, - "display": { - "x": 1332, - "y": -96 - }, - "children": [ - "4a212c84-5d1d-4e5d-8c0f-a9f9d11e439d", - "11948c7f-5c40-4107-8d56-6125dd54e5e2" - ] - }, - "a9e5ea0d-ac6c-49e9-96d4-6581cdb7c470": { - "id": "a9e5ea0d-ac6c-49e9-96d4-6581cdb7c470", - "name": "Runner", - "category": "action", - "title": "Runner", - "description": "", - "properties": {}, - "display": { - "x": 1476, - "y": 60 - } - }, - "8fa27d60-d1bf-4180-86fa-0f7df43964aa": { - "id": "8fa27d60-d1bf-4180-86fa-0f7df43964aa", - "name": "Priority", - "category": "composite", - "title": "Priority", - "description": "", - "properties": {}, - "display": { - "x": 1068, - "y": 24 - }, - "children": [ - "45e66071-e115-49e6-abc6-9e4e3451c183", - "a9e5ea0d-ac6c-49e9-96d4-6581cdb7c470" - ] - }, - "45e66071-e115-49e6-abc6-9e4e3451c183": { - "id": "45e66071-e115-49e6-abc6-9e4e3451c183", - "name": "Inverter", - "category": "decorator", - "title": "Inverter", - "description": "", - "properties": {}, - "display": { - "x": 1200, - "y": -60 - }, - "child": "c10ca763-66cf-4b6c-87d7-ca835f7974e9" - }, - "f02189b7-d510-4c72-9c90-a6d8d8b22618": { - "id": "f02189b7-d510-4c72-9c90-a6d8d8b22618", - "name": "SetIntMulti", - "category": "action", - "title": "SetIntMulti(,,)", - "description": "设置乘法,保存数值\ngINKey 保存黑版key\ngIPValue1 v1 支持@\ngIPValue2 v2 支持@", - "properties": { - "gINKey": "betSrcCoin", - "gIPValue1": "betSrcCoin", - "gIPValue2": "playerCoin" - }, - "display": { - "x": 828, - "y": -624 - } - }, - "2008f23e-56e8-4818-be5c-b2519e5234fa": { - "id": "2008f23e-56e8-4818-be5c-b2519e5234fa", - "name": "RandIntAction", - "category": "action", - "title": "RandIntAction(,,)", - "description": "随机获得一个[min,max)的整数,保存到黑板的index key中", - "properties": { - "index": "takeCoinDiv", - "min": 20, - "max": 40 - }, - "display": { - "x": 1332, - "y": 768 - } - }, - "f927fad5-6bab-4a2e-be7c-98939b76dd32": { - "id": "f927fad5-6bab-4a2e-be7c-98939b76dd32", - "name": "Sequence", - "category": "composite", - "title": "Sequence", - "description": "", - "properties": {}, - "display": { - "x": 960, - "y": 816 - }, - "children": [ - "2008f23e-56e8-4818-be5c-b2519e5234fa", - "ccc49727-0ca1-4694-9fdd-c471621bf8ae", - "68ec252c-c055-4c2d-a1be-2985696ce689", - "1873d62c-2aa1-456b-8cbc-e56b2f2d1299", - "604b38aa-b2ca-40ac-9f89-1581ce12a281" - ] - }, - "ccc49727-0ca1-4694-9fdd-c471621bf8ae": { - "id": "ccc49727-0ca1-4694-9fdd-c471621bf8ae", - "name": "GetPlayerTakeCoin", - "category": "action", - "title": "GetPlayerTakeCoin()", - "description": "获得玩家入场携带金币\ngINKey 保存黑板key", - "properties": { - "gINKey": "takeCoin" - }, - "display": { - "x": 1320, - "y": 816 - } - }, - "604b38aa-b2ca-40ac-9f89-1581ce12a281": { - "id": "604b38aa-b2ca-40ac-9f89-1581ce12a281", - "name": "CheckPlayerCoin", - "category": "condition", - "title": "CheckPlayerCoin(,)", - "description": "检查用户金币\ngIPCoin 支持@ 用户需要比较的金币\ncmp 比较\t\n 0 //小于\n 1 //小于等于\n 2 //等于\n 3 //大于\n 4 //大于等于", - "properties": { - "gIPCoin": "takeCoin", - "cmp": 0 - }, - "display": { - "x": 1308, - "y": 1008 - } - }, - "68ec252c-c055-4c2d-a1be-2985696ce689": { - "id": "68ec252c-c055-4c2d-a1be-2985696ce689", - "name": "SetIntMulti", - "category": "action", - "title": "SetIntMulti(,,)", - "description": "设置乘法,保存数值\ngINKey 保存黑版key\ngIPValue1 v1 支持@\ngIPValue2 v2 支持@", - "properties": { - "gINKey": "takeCoin", - "gIPValue1": "takeCoin", - "gIPValue2": "takeCoinDiv" - }, - "display": { - "x": 1368, - "y": 876 - } - }, - "1873d62c-2aa1-456b-8cbc-e56b2f2d1299": { - "id": "1873d62c-2aa1-456b-8cbc-e56b2f2d1299", - "name": "SetIntDiv", - "category": "action", - "title": "SetIntDiv(,,)", - "description": "设定除法保存数据到黑板\ngINKey \ngIPValue1\ngIPValue2", - "properties": { - "gINKey": "takeCoin", - "gIPValue1": "takeCoin", - "gIPValue2": "@100" - }, - "display": { - "x": 1332, - "y": 936 - } - }, - "1297e23e-f652-4224-81b1-645a65bab464": { - "id": "1297e23e-f652-4224-81b1-645a65bab464", - "name": "DVTBetCoin", - "category": "action", - "title": "DVTBetCoin(,)", - "description": "龙虎押注", - "properties": { - "gIPBetCoin": "betSrcCoin", - "gIPArea": "@0" - }, - "display": { - "x": 1548, - "y": -348 - } - }, - "11948c7f-5c40-4107-8d56-6125dd54e5e2": { - "id": "11948c7f-5c40-4107-8d56-6125dd54e5e2", - "name": "DVTBetCoin", - "category": "action", - "title": "DVTBetCoin(,)", - "description": "龙虎押注", - "properties": { - "gIPBetCoin": "betCoin", - "gIPArea": "betArea" - }, - "display": { - "x": 1548, - "y": -48 - } - }, - "edc549af-53dc-4866-b6a8-c8d104f5eb5f": { - "id": "edc549af-53dc-4866-b6a8-c8d104f5eb5f", - "name": "DVTSceneState", - "category": "condition", - "title": "DVTSceneState()", - "description": "龙虎状态检查\n0 准备押注\n1 押注\n2 准备开牌\n3 开牌\n4 结算", - "properties": { - "state": 1 - }, - "display": { - "x": 672, - "y": -72 - } - }, - "44aa2c38-49cc-4b47-935c-478671025ebc": { - "id": "44aa2c38-49cc-4b47-935c-478671025ebc", - "name": "DVTSceneState", - "category": "condition", - "title": "DVTSceneState()", - "description": "龙虎状态检查\n0 准备押注\n1 押注\n2 准备开牌\n3 开牌\n4 准备结算\n5 结算", - "properties": { - "state": 1 - }, - "display": { - "x": 708, - "y": -816 - } - }, - "a0925c1e-0a2b-4cf3-8ca2-c7b51c80d145": { - "id": "a0925c1e-0a2b-4cf3-8ca2-c7b51c80d145", - "name": "DVTCheckBetCoin", - "category": "action", - "title": "DVTCheckBetCoin(,)", - "description": "龙虎检查下注额度", - "properties": { - "gIPSrcCoin": "betSrcCoin", - "gINSaveCoin": "betCoin" - }, - "display": { - "x": 804, - "y": -504 - } - }, - "c99835ea-a71f-4259-9a55-a3a47c53ce4c": { - "id": "c99835ea-a71f-4259-9a55-a3a47c53ce4c", - "name": "DVTSceneState", - "category": "condition", - "title": "DVTSceneState()", - "description": "龙虎状态检查\n0 准备押注\n1 押注\n2 准备开牌\n3 开牌\n4 准备结算\n5 结算", - "properties": { - "state": 4 - }, - "display": { - "x": 636, - "y": 540 - } - }, - "18f20a87-f766-48c3-866b-d88a27b25f9e": { - "id": "18f20a87-f766-48c3-866b-d88a27b25f9e", - "name": "SetIntDiv", - "category": "action", - "title": "SetIntDiv(,,)", - "description": "设定除法保存数据到黑板\ngINKey \ngIPValue1\ngIPValue2", - "properties": { - "gINKey": "betSrcCoin", - "gIPValue1": "betCoin", - "gIPValue2": "@2" - }, - "display": { - "x": 1548, - "y": -552 - } - }, - "28932c02-c37d-4060-8253-b10cd2c9d224": { - "id": "28932c02-c37d-4060-8253-b10cd2c9d224", - "name": "DVTCheckBetCoin", - "category": "action", - "title": "DVTCheckBetCoin(,)", - "description": "龙虎检查下注额度", - "properties": { - "gIPSrcCoin": "betSrcCoin", - "gINSaveCoin": "betSrcCoin" - }, - "display": { - "x": 1596, - "y": -492 - } - } - }, - "display": { - "camera_x": 220.14000000315718, - "camera_y": 153.3199999993667, - "camera_z": 0.75, - "x": -60, - "y": 372 - }, - "custom_nodes": [ - { - "version": "0.3.0", - "scope": "node", - "name": "RVBSceneState", - "category": "condition", - "title": "RVBSceneState()", - "description": "红黑场景状态判定\n0 准备押注\n1 押注\n2 准备开牌\n3 开牌\n4 结算", - "properties": { - "state": 0 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "RandIntAction", - "category": "action", - "title": "RandIntAction(,,)", - "description": "随机获得一个[min,max)的整数,保存到黑板的index key中", - "properties": { - "index": "key", - "min": 0, - "max": 1 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "RandWait", - "category": "action", - "title": "RandWait(,)", - "description": "节点暂停[minTime,maxTime)毫秒", - "properties": { - "minTime": 0, - "maxTime": 1 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "RandomWeightComposite", - "category": "composite", - "title": "RandomWeightComposite()", - "description": "根据权重随机,选择一个子节点。\n权重使用|分割。\n需要注意子节点的顺序,个数需要和权重对应", - "properties": { - "weight": "\"\"" - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "CheckBool", - "category": "condition", - "title": "CheckBool()", - "description": "检查一个黑板的key值", - "properties": { - "keyName": "key" - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "CheckInt", - "category": "condition", - "title": "CheckInt(,,)", - "description": "检查黑板的一个值和待比较值\n 0 //小于\n 1 //小于等于\n 2 //等于\n 3 //大于\n 4 //大于等于", - "properties": { - "keyName": "key", - "value": 0, - "cmp": 0 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "LogAction", - "category": "action", - "title": "LogAction(,)", - "description": "输出日志", - "properties": { - "info": "info", - "level": 0 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "RVBBetPct", - "category": "action", - "title": "RVBBetPct(,)", - "description": "红黑下注\ngIPpct 下注百分比,黑板key 支持@\ngIPArea 下注区域,黑板key 支持@", - "properties": { - "gIPpct": "key", - "gIPArea": 1 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "RVBLastWinArea", - "category": "action", - "title": "RVBLastWinArea()", - "description": "获得最后的下注结果保存到key,没有返回失败", - "properties": { - "gINKey": "key" - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "LeaveGame", - "category": "action", - "title": "LeaveGame", - "description": "离开游戏", - "properties": {} - }, - { - "version": "0.3.0", - "scope": "node", - "name": "CheckPlayerCoin", - "category": "condition", - "title": "CheckPlayerCoin(,)", - "description": "检查用户金币\ngIPCoin 支持@ 用户需要比较的金币\ncmp 比较\t\n 0 //小于\n 1 //小于等于\n 2 //等于\n 3 //大于\n 4 //大于等于", - "properties": { - "gIPCoin": "key", - "cmp": 0 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "GetOutLimitCoin", - "category": "action", - "title": "GetOutLimitCoin()", - "description": "获得玩家游戏踢出限制\ngINKey 保存到黑板key", - "properties": { - "gINKey": "key" - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "CheckPlayerGameNum", - "category": "condition", - "title": "CheckPlayerGameNum(,)", - "description": "检查用户游戏次数\ngIPGameNum支持@ 用户需要游戏次数\ncmp 比较\t\n 0 //小于\n 1 //小于等于\n 2 //等于\n 3 //大于\n 4 //大于等于", - "properties": { - "gIPGameNum": "key", - "cmp": 0 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "CheckPlayerLastWinOrLost", - "category": "condition", - "title": "CheckPlayerLastWinOrLost(,)", - "description": "检查玩家上次输赢情况\ngIPLResult 比较值 支持@\ncmp 比较", - "properties": { - "gIPLResult": "key", - "cmp": 0 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "SetIntAction", - "category": "action", - "title": "SetIntAction(,)", - "description": "设置int参数值\ngINKey 黑版key值\ngIPValue 设置的值,支持@", - "properties": { - "gINKey": "key", - "gIPValue": 0 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "RVBBetCoin", - "category": "action", - "title": "RVBBetCoin(,)", - "description": "红黑押注\ngIPBetCoin 押注金额 支持@\ngIPArea 押注区域支持@", - "properties": { - "gIPBetCoin": "key", - "gIPArea": 0 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "RVBCheckBetCoin", - "category": "action", - "title": "RVBCheckBetCoin(,)", - "description": "修正押注金额,保存到黑板key\ngIPSrcCoin 押注金额支持@\ngINSaveCoin 保存后key", - "properties": { - "gIPSrcCoin": "key", - "gINSaveCoin": 0 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "SetIntMulti", - "category": "action", - "title": "SetIntMulti(,,)", - "description": "设置乘法,保存数值\ngINKey 保存黑版key\ngIPValue1 v1 支持@\ngIPValue2 v2 支持@", - "properties": { - "gINKey": "key", - "gIPValue1": 0, - "gIPValue2": 0 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "GetPlayerCoin", - "category": "action", - "title": "GetPlayerCoin()", - "description": "得到玩家金币\ngINKey 保存key", - "properties": { - "gINKey": "key" - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "SetIntDiv", - "category": "action", - "title": "SetIntDiv(,,)", - "description": "设定除法保存数据到黑板\ngINKey \ngIPValue1\ngIPValue2", - "properties": { - "gINKey": "key", - "gIPValue1": 0, - "gIPValue2": 0 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "RVBHistoryIsSame", - "category": "condition", - "title": "RVBHistoryIsSame()", - "description": "判定是上几局都是相同的结果", - "properties": { - "gIPNum": "key", - "num": 0 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "GetPlayerTakeCoin", - "category": "action", - "title": "GetPlayerTakeCoin()", - "description": "获得玩家入场携带金币\ngINKey 保存黑板key", - "properties": { - "gINKey": "key" - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "DVTHistoryIsSame", - "category": "condition", - "title": "DVTHistoryIsSame()", - "description": "判定是上几局都是相同的结果\ngIPNum 支持@", - "properties": { - "gIPNum": "key" - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "DVTLastWinArea", - "category": "action", - "title": "DVTLastWinArea()", - "description": "龙虎最后获胜的区域保存到黑板", - "properties": { - "gINKey": "key" - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "DVTBetCoin", - "category": "action", - "title": "DVTBetCoin(,)", - "description": "龙虎押注", - "properties": { - "gIPBetCoin": "key", - "gIPArea": 0 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "DVTCheckBetCoin", - "category": "action", - "title": "DVTCheckBetCoin(,)", - "description": "龙虎检查下注额度", - "properties": { - "gIPSrcCoin": 0, - "gINSaveCoin": 0 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "DVTSceneState", - "category": "condition", - "title": "DVTSceneState()", - "description": "龙虎状态检查\n0 准备押注\n1 押注\n2 准备开牌\n3 开牌\n4 结算", - "properties": { - "state": 0 - } - } - ] -} \ No newline at end of file diff --git a/data/botai/rvbfollowwin.json b/data/botai/rvbfollowwin.json deleted file mode 100644 index 8a415c4..0000000 --- a/data/botai/rvbfollowwin.json +++ /dev/null @@ -1,1174 +0,0 @@ -{ - "version": "0.3.0", - "scope": "tree", - "id": "3729efe7-b5eb-4656-8694-23a7f4d3b92d", - "title": "RVBFollowWinBot", - "description": "跟龙 倍投", - "root": "3868f9e0-f1f2-4927-9b75-f4049a3f5fa6", - "properties": {}, - "nodes": { - "32f44dae-b2da-4b7f-8e9b-a0594d9b9c7c": { - "id": "32f44dae-b2da-4b7f-8e9b-a0594d9b9c7c", - "name": "RVBSceneState", - "category": "condition", - "title": "RVBSceneState()", - "description": "红黑场景状态判定\n0 准备押注\n1 押注\n2 准备开牌\n3 开牌\n4 结算", - "properties": { - "state": 1 - }, - "display": { - "x": 696, - "y": -288 - } - }, - "8ee2e525-0e10-4339-9fc1-091059a33a3b": { - "id": "8ee2e525-0e10-4339-9fc1-091059a33a3b", - "name": "Sequence", - "category": "composite", - "title": "Sequence", - "description": "", - "properties": {}, - "display": { - "x": 276, - "y": -156 - }, - "children": [ - "32f44dae-b2da-4b7f-8e9b-a0594d9b9c7c", - "8289c2a3-9316-4a88-a2cd-b1f36d22d315", - "254e71dd-e4b5-45fd-9a43-812dfcf99f4e", - "3fe9e989-b8c9-4a07-b4af-45966df9aad7", - "87f04e22-3804-4713-8030-3367f2a3dc48", - "79dcac3e-9c14-4963-958f-82410069335b" - ] - }, - "fe47e8e1-19ef-448e-8c20-c9839229f1cf": { - "id": "fe47e8e1-19ef-448e-8c20-c9839229f1cf", - "name": "RandIntAction", - "category": "action", - "title": "RandIntAction(,,)", - "description": "随机获得一个[min,max)的整数,保存到黑板的index key中", - "properties": { - "index": "betSrcCoin", - "min": 2, - "max": 6 - }, - "display": { - "x": 276, - "y": -528 - } - }, - "f60a1323-ca6a-43cc-bd26-ef5a3c5c750c": { - "id": "f60a1323-ca6a-43cc-bd26-ef5a3c5c750c", - "name": "RVBSceneState", - "category": "condition", - "title": "RVBSceneState()", - "description": "红黑场景状态判定\n0 准备押注\n1 押注\n2 准备开牌\n3 开牌\n4 结算", - "properties": { - "state": 1 - }, - "display": { - "x": 972, - "y": 48 - } - }, - "bec1e9bc-4be0-47ff-8a69-f2211bd68011": { - "id": "bec1e9bc-4be0-47ff-8a69-f2211bd68011", - "name": "RandWait", - "category": "action", - "title": "RandWait(,)", - "description": "节点暂停[minTime,maxTime)毫秒", - "properties": { - "minTime": 600, - "maxTime": 1200 - }, - "display": { - "x": 996, - "y": 156 - } - }, - "254e71dd-e4b5-45fd-9a43-812dfcf99f4e": { - "id": "254e71dd-e4b5-45fd-9a43-812dfcf99f4e", - "name": "RVBHistoryIsSame", - "category": "condition", - "title": "RVBHistoryIsSame()", - "description": "判定是上几局都是相同的结果", - "properties": { - "gIPNum": "sameNum", - "num": 2 - }, - "display": { - "x": 720, - "y": -180 - } - }, - "3fe9e989-b8c9-4a07-b4af-45966df9aad7": { - "id": "3fe9e989-b8c9-4a07-b4af-45966df9aad7", - "name": "RVBLastWinArea", - "category": "action", - "title": "RVBLastWinArea()", - "description": "获得最后的下注结果保存到key,没有返回失败", - "properties": { - "gINKey": "betArea" - }, - "display": { - "x": 696, - "y": -132 - } - }, - "e683afae-4710-4113-9c6a-ffde88d780a1": { - "id": "e683afae-4710-4113-9c6a-ffde88d780a1", - "name": "Sequence", - "category": "composite", - "title": "Sequence", - "description": "", - "properties": {}, - "display": { - "x": -24, - "y": 996 - }, - "children": [ - "9bfd94ac-09b8-41b7-9898-62fa25e6e1ff", - "1bf7fa77-6cc7-4120-8862-61668a6768bc", - "e785463c-b082-403e-8b33-e2123551313d", - "383031e5-3af8-4b56-826a-76fff677d1c2" - ] - }, - "9bfd94ac-09b8-41b7-9898-62fa25e6e1ff": { - "id": "9bfd94ac-09b8-41b7-9898-62fa25e6e1ff", - "name": "RVBSceneState", - "category": "condition", - "title": "RVBSceneState()", - "description": "红黑场景状态判定\n0 准备押注\n1 押注\n2 准备开牌\n3 开牌\n4 结算", - "properties": { - "state": 4 - }, - "display": { - "x": 216, - "y": 876 - } - }, - "b9d620f1-7c32-423b-bab4-dc50183a602d": { - "id": "b9d620f1-7c32-423b-bab4-dc50183a602d", - "name": "CheckPlayerCoin", - "category": "condition", - "title": "CheckPlayerCoin(,)", - "description": "检查用户金币\ngIPCoin 支持@ 用户需要比较的金币\ncmp 比较\t\n 0 //小于\n 1 //小于等于\n 2 //等于\n 3 //大于\n 4 //大于等于", - "properties": { - "gIPCoin": "saveLimit", - "cmp": 0 - }, - "display": { - "x": 864, - "y": 900 - } - }, - "17c1ea6f-6b58-45d3-9457-4ac747100654": { - "id": "17c1ea6f-6b58-45d3-9457-4ac747100654", - "name": "GetOutLimitCoin", - "category": "action", - "title": "GetOutLimitCoin()", - "description": "获得玩家游戏踢出限制\ngINKey 保存到黑板key", - "properties": { - "gINKey": "saveLimit" - }, - "display": { - "x": 852, - "y": 828 - } - }, - "e785463c-b082-403e-8b33-e2123551313d": { - "id": "e785463c-b082-403e-8b33-e2123551313d", - "name": "RandWait", - "category": "action", - "title": "RandWait(,)", - "description": "节点暂停[minTime,maxTime)毫秒", - "properties": { - "minTime": 500, - "maxTime": 3500 - }, - "display": { - "x": 204, - "y": 1152 - } - }, - "383031e5-3af8-4b56-826a-76fff677d1c2": { - "id": "383031e5-3af8-4b56-826a-76fff677d1c2", - "name": "LeaveGame", - "category": "action", - "title": "LeaveGame", - "description": "离开游戏", - "properties": {}, - "display": { - "x": 168, - "y": 1296 - } - }, - "9501a1ea-d5d4-4437-b008-5901df5a3155": { - "id": "9501a1ea-d5d4-4437-b008-5901df5a3155", - "name": "CheckPlayerGameNum", - "category": "condition", - "title": "CheckPlayerGameNum(,)", - "description": "检查用户游戏次数\ngIPGameNum支持@ 用户需要游戏次数\ncmp 比较\t\n 0 //小于\n 1 //小于等于\n 2 //等于\n 3 //大于\n 4 //大于等于", - "properties": { - "gIPGameNum": "maxGameNum", - "cmp": 4 - }, - "display": { - "x": 912, - "y": 1080 - } - }, - "1a77bfb7-6ec1-4414-bcdf-7f5c8ea05e0a": { - "id": "1a77bfb7-6ec1-4414-bcdf-7f5c8ea05e0a", - "name": "RandIntAction", - "category": "action", - "title": "RandIntAction(,,)", - "description": "随机获得一个[min,max)的整数,保存到黑板的index key中", - "properties": { - "index": "maxGameNum", - "min": 10, - "max": 40 - }, - "display": { - "x": 888, - "y": 996 - } - }, - "a0833ec6-4c79-491d-8983-58ccae4d0329": { - "id": "a0833ec6-4c79-491d-8983-58ccae4d0329", - "name": "Sequence", - "category": "composite", - "title": "Sequence", - "description": "生成初始押注额度", - "properties": {}, - "display": { - "x": 36, - "y": -468 - }, - "children": [ - "5731b7b0-8447-43cf-8754-303d98a3634a", - "822d814e-a660-4d75-83ee-b06873791200", - "1df794f8-957a-4fdd-8057-b010928bf805", - "fe47e8e1-19ef-448e-8c20-c9839229f1cf", - "5caa26b4-ff66-4b35-8713-8de52405da42", - "86f7dc9c-ca22-4f66-9f5f-d75e3f0a8c02", - "45246284-428b-44b8-b976-169186544c9e", - "f37176cd-a3ec-4223-aebb-4a301c86b92a" - ] - }, - "822d814e-a660-4d75-83ee-b06873791200": { - "id": "822d814e-a660-4d75-83ee-b06873791200", - "name": "CheckInt", - "category": "condition", - "title": "CheckInt(,,)", - "description": "检查黑板的一个值和待比较值\n 0 //小于\n 1 //小于等于\n 2 //等于\n 3 //大于\n 4 //大于等于", - "properties": { - "keyName": "needStartBet", - "value": 0, - "cmp": 2 - }, - "display": { - "x": 252, - "y": -624 - } - }, - "1df794f8-957a-4fdd-8057-b010928bf805": { - "id": "1df794f8-957a-4fdd-8057-b010928bf805", - "name": "SetIntAction", - "category": "action", - "title": "SetIntAction(,)", - "description": "设置int参数值\ngINKey 黑版key值\ngIPValue 设置的值,支持@", - "properties": { - "gINKey": "needStartBet", - "gIPValue": "@1" - }, - "display": { - "x": 276, - "y": -576 - } - }, - "8ad87cb8-b5cc-456f-bf95-ba0d0b0b9cf4": { - "id": "8ad87cb8-b5cc-456f-bf95-ba0d0b0b9cf4", - "name": "RVBBetCoin", - "category": "action", - "title": "RVBBetCoin(,)", - "description": "红黑押注\ngIPBetCoin 押注金额 支持@\ngIPArea 押注区域支持@", - "properties": { - "gIPBetCoin": "betCoin", - "gIPArea": "betArea" - }, - "display": { - "x": 1020, - "y": 228 - } - }, - "f37176cd-a3ec-4223-aebb-4a301c86b92a": { - "id": "f37176cd-a3ec-4223-aebb-4a301c86b92a", - "name": "RVBCheckBetCoin", - "category": "action", - "title": "RVBCheckBetCoin(,)", - "description": "修正押注金额,保存到黑板key\ngIPSrcCoin 押注金额支持@\ngINSaveCoin 保存后key", - "properties": { - "gIPSrcCoin": "betSrcCoin", - "gINSaveCoin": "betSrcCoin" - }, - "display": { - "x": 324, - "y": -324 - } - }, - "87f04e22-3804-4713-8030-3367f2a3dc48": { - "id": "87f04e22-3804-4713-8030-3367f2a3dc48", - "name": "SetIntMulti", - "category": "action", - "title": "SetIntMulti(,,)", - "description": "设置乘法,保存数值\ngINKey 保存黑版key\ngIPValue1 v1 支持@\ngIPValue2 v2 支持@", - "properties": { - "gINKey": "betCoin", - "gIPValue1": "betSrcCoin", - "gIPValue2": "needStartBet" - }, - "display": { - "x": 768, - "y": -84 - } - }, - "79dcac3e-9c14-4963-958f-82410069335b": { - "id": "79dcac3e-9c14-4963-958f-82410069335b", - "name": "SetIntMulti", - "category": "action", - "title": "SetIntMulti(,,)", - "description": "设置乘法,保存数值\ngINKey 保存黑版key\ngIPValue1 v1 支持@\ngIPValue2 v2 支持@", - "properties": { - "gINKey": "needStartBet", - "gIPValue1": "needStartBet", - "gIPValue2": "@2" - }, - "display": { - "x": 756, - "y": -36 - } - }, - "19403a37-6769-4911-a71c-cb49f92a47b4": { - "id": "19403a37-6769-4911-a71c-cb49f92a47b4", - "name": "Sequence", - "category": "composite", - "title": "Sequence", - "description": "", - "properties": {}, - "display": { - "x": 144, - "y": 636 - }, - "children": [ - "69225c33-f1ab-4347-8071-620d2134cf31", - "858e1bb5-4a33-4dc5-8a84-2330d0669bf0", - "4e3753b8-309a-4976-984c-7ec00665ccf2" - ] - }, - "69225c33-f1ab-4347-8071-620d2134cf31": { - "id": "69225c33-f1ab-4347-8071-620d2134cf31", - "name": "RVBSceneState", - "category": "condition", - "title": "RVBSceneState()", - "description": "红黑场景状态判定\n0 准备押注\n1 押注\n2 准备开牌\n3 开牌\n4 结算", - "properties": { - "state": 4 - }, - "display": { - "x": 360, - "y": 564 - } - }, - "858e1bb5-4a33-4dc5-8a84-2330d0669bf0": { - "id": "858e1bb5-4a33-4dc5-8a84-2330d0669bf0", - "name": "CheckPlayerLastWinOrLost", - "category": "condition", - "title": "CheckPlayerLastWinOrLost(,)", - "description": "检查玩家上次输赢情况\ngIPLResult 比较值 支持@\ncmp 比较", - "properties": { - "gIPLResult": "@1", - "cmp": 2 - }, - "display": { - "x": 432, - "y": 636 - } - }, - "4e3753b8-309a-4976-984c-7ec00665ccf2": { - "id": "4e3753b8-309a-4976-984c-7ec00665ccf2", - "name": "SetIntAction", - "category": "action", - "title": "SetIntAction(,)", - "description": "设置int参数值\ngINKey 黑版key值\ngIPValue 设置的值,支持@", - "properties": { - "gINKey": "needStartBet", - "gIPValue": "@0" - }, - "display": { - "x": 420, - "y": 708 - } - }, - "5caa26b4-ff66-4b35-8713-8de52405da42": { - "id": "5caa26b4-ff66-4b35-8713-8de52405da42", - "name": "GetPlayerCoin", - "category": "action", - "title": "GetPlayerCoin()", - "description": "得到玩家金币\ngINKey 保存key", - "properties": { - "gINKey": "playerCoin" - }, - "display": { - "x": 264, - "y": -480 - } - }, - "86f7dc9c-ca22-4f66-9f5f-d75e3f0a8c02": { - "id": "86f7dc9c-ca22-4f66-9f5f-d75e3f0a8c02", - "name": "SetIntMulti", - "category": "action", - "title": "SetIntMulti(,,)", - "description": "设置乘法,保存数值\ngINKey 保存黑版key\ngIPValue1 v1 支持@\ngIPValue2 v2 支持@", - "properties": { - "gINKey": "betSrcCoin", - "gIPValue1": "betSrcCoin", - "gIPValue2": "playerCoin" - }, - "display": { - "x": 336, - "y": -432 - } - }, - "45246284-428b-44b8-b976-169186544c9e": { - "id": "45246284-428b-44b8-b976-169186544c9e", - "name": "SetIntDiv", - "category": "action", - "title": "SetIntDiv(,,)", - "description": "设定除法保存数据到黑板\ngINKey \ngIPValue1\ngIPValue2", - "properties": { - "gINKey": "betSrcCoin", - "gIPValue1": "betSrcCoin", - "gIPValue2": "@100" - }, - "display": { - "x": 312, - "y": -384 - } - }, - "1bf7fa77-6cc7-4120-8862-61668a6768bc": { - "id": "1bf7fa77-6cc7-4120-8862-61668a6768bc", - "name": "Priority", - "category": "composite", - "title": "Priority", - "description": "", - "properties": {}, - "display": { - "x": 288, - "y": 1008 - }, - "children": [ - "418a21fb-0971-4d1e-bbad-984453cde8bf", - "7024613f-625c-4dc8-8ebf-9f6b885d4142", - "3562d05e-c36f-422c-b9c0-44dd803c64c7", - "b2ecc51c-39f6-48c9-9176-586e2ac5f2ef" - ] - }, - "418a21fb-0971-4d1e-bbad-984453cde8bf": { - "id": "418a21fb-0971-4d1e-bbad-984453cde8bf", - "name": "Sequence", - "category": "composite", - "title": "Sequence", - "description": "", - "properties": {}, - "display": { - "x": 528, - "y": 924 - }, - "children": [ - "17c1ea6f-6b58-45d3-9457-4ac747100654", - "b9d620f1-7c32-423b-bab4-dc50183a602d" - ] - }, - "7024613f-625c-4dc8-8ebf-9f6b885d4142": { - "id": "7024613f-625c-4dc8-8ebf-9f6b885d4142", - "name": "Sequence", - "category": "composite", - "title": "Sequence", - "description": "", - "properties": {}, - "display": { - "x": 528, - "y": 1080 - }, - "children": [ - "1a77bfb7-6ec1-4414-bcdf-7f5c8ea05e0a", - "9501a1ea-d5d4-4437-b008-5901df5a3155" - ] - }, - "8289c2a3-9316-4a88-a2cd-b1f36d22d315": { - "id": "8289c2a3-9316-4a88-a2cd-b1f36d22d315", - "name": "RandIntAction", - "category": "action", - "title": "RandIntAction(,,)", - "description": "随机获得一个[min,max)的整数,保存到黑板的index key中", - "properties": { - "index": "sameNum", - "min": 2, - "max": 4 - }, - "display": { - "x": 720, - "y": -228 - } - }, - "65cd19af-85ed-4007-b276-cd4784c9e2eb": { - "id": "65cd19af-85ed-4007-b276-cd4784c9e2eb", - "name": "Sequence", - "category": "composite", - "title": "Sequence", - "description": "", - "properties": {}, - "display": { - "x": 720, - "y": 96 - }, - "children": [ - "f60a1323-ca6a-43cc-bd26-ef5a3c5c750c", - "5c2c3259-96a7-4d01-85dd-9b89bbf95d9e", - "bec1e9bc-4be0-47ff-8a69-f2211bd68011", - "886ee374-f912-4bd0-8095-b3961096e536" - ] - }, - "886ee374-f912-4bd0-8095-b3961096e536": { - "id": "886ee374-f912-4bd0-8095-b3961096e536", - "name": "Priority", - "category": "composite", - "title": "Priority", - "description": "", - "properties": {}, - "display": { - "x": 804, - "y": 240 - }, - "children": [ - "8ad87cb8-b5cc-456f-bf95-ba0d0b0b9cf4", - "a8daa59d-2bba-4fc5-b0d8-9e8dbb6a3329" - ] - }, - "a8daa59d-2bba-4fc5-b0d8-9e8dbb6a3329": { - "id": "a8daa59d-2bba-4fc5-b0d8-9e8dbb6a3329", - "name": "SetIntAction", - "category": "action", - "title": "SetIntAction(,)", - "description": "设置int参数值\ngINKey 黑版key值\ngIPValue 设置的值,支持@", - "properties": { - "gINKey": "betIsOk", - "gIPValue": "@1" - }, - "display": { - "x": 1008, - "y": 300 - } - }, - "5c2c3259-96a7-4d01-85dd-9b89bbf95d9e": { - "id": "5c2c3259-96a7-4d01-85dd-9b89bbf95d9e", - "name": "CheckInt", - "category": "condition", - "title": "CheckInt(,,)", - "description": "检查黑板的一个值和待比较值\n 0 //小于\n 1 //小于等于\n 2 //等于\n 3 //大于\n 4 //大于等于", - "properties": { - "keyName": "betIsOk", - "value": 0, - "cmp": 2 - }, - "display": { - "x": 984, - "y": 96 - } - }, - "630af409-8ad9-44c6-8686-29a39b94d392": { - "id": "630af409-8ad9-44c6-8686-29a39b94d392", - "name": "SetIntAction", - "category": "action", - "title": "SetIntAction(,)", - "description": "设置int参数值\ngINKey 黑版key值\ngIPValue 设置的值,支持@", - "properties": { - "gINKey": "betIsOk", - "gIPValue": "@0" - }, - "display": { - "x": 324, - "y": 312 - } - }, - "b2ecc51c-39f6-48c9-9176-586e2ac5f2ef": { - "id": "b2ecc51c-39f6-48c9-9176-586e2ac5f2ef", - "name": "CheckPlayerCoin", - "category": "condition", - "title": "CheckPlayerCoin(,)", - "description": "检查用户金币\ngIPCoin 支持@ 用户需要比较的金币\ncmp 比较\t\n 0 //小于\n 1 //小于等于\n 2 //等于\n 3 //大于\n 4 //大于等于", - "properties": { - "gIPCoin": "betCoin", - "cmp": 0 - }, - "display": { - "x": 600, - "y": 1488 - } - }, - "4cf9a0a2-32b6-4aff-826a-f7d6e69726c7": { - "id": "4cf9a0a2-32b6-4aff-826a-f7d6e69726c7", - "name": "Sequence", - "category": "composite", - "title": "Sequence", - "description": "", - "properties": {}, - "display": { - "x": 84, - "y": 348 - }, - "children": [ - "630af409-8ad9-44c6-8686-29a39b94d392", - "8992bffc-13af-4cb0-ab3b-fb37424be47e", - "9dc23b33-85ab-4010-85cc-bb61b1cb1b89" - ] - }, - "8992bffc-13af-4cb0-ab3b-fb37424be47e": { - "id": "8992bffc-13af-4cb0-ab3b-fb37424be47e", - "name": "RVBSceneState", - "category": "condition", - "title": "RVBSceneState()", - "description": "红黑场景状态判定\n0 准备押注\n1 押注\n2 准备开牌\n3 开牌\n4 结算", - "properties": { - "state": 1 - }, - "display": { - "x": 300, - "y": 384 - } - }, - "9dc23b33-85ab-4010-85cc-bb61b1cb1b89": { - "id": "9dc23b33-85ab-4010-85cc-bb61b1cb1b89", - "name": "Runner", - "category": "action", - "title": "Runner", - "description": "", - "properties": {}, - "display": { - "x": 300, - "y": 456 - } - }, - "de240ce6-74f8-4c15-8f6f-f0486d98cf93": { - "id": "de240ce6-74f8-4c15-8f6f-f0486d98cf93", - "name": "Runner", - "category": "action", - "title": "Runner", - "description": "", - "properties": {}, - "display": { - "x": 948, - "y": 372 - } - }, - "3868f9e0-f1f2-4927-9b75-f4049a3f5fa6": { - "id": "3868f9e0-f1f2-4927-9b75-f4049a3f5fa6", - "name": "Priority", - "category": "composite", - "title": "Priority", - "description": "", - "properties": {}, - "display": { - "x": -360, - "y": 144 - }, - "children": [ - "a0833ec6-4c79-491d-8983-58ccae4d0329", - "3fb1e974-7d51-4a6f-9701-fe001c3bd3a3", - "19403a37-6769-4911-a71c-cb49f92a47b4", - "e683afae-4710-4113-9c6a-ffde88d780a1" - ] - }, - "3fb1e974-7d51-4a6f-9701-fe001c3bd3a3": { - "id": "3fb1e974-7d51-4a6f-9701-fe001c3bd3a3", - "name": "MemSequence", - "category": "composite", - "title": "MemSequence", - "description": "", - "properties": {}, - "display": { - "x": -48, - "y": 60 - }, - "children": [ - "8ee2e525-0e10-4339-9fc1-091059a33a3b", - "96caa228-3af2-4e17-846d-41975eff29eb", - "4cf9a0a2-32b6-4aff-826a-f7d6e69726c7" - ] - }, - "96caa228-3af2-4e17-846d-41975eff29eb": { - "id": "96caa228-3af2-4e17-846d-41975eff29eb", - "name": "Priority", - "category": "composite", - "title": "Priority", - "description": "", - "properties": {}, - "display": { - "x": 468, - "y": 192 - }, - "children": [ - "e85533fb-029e-4366-8c59-d98768b9d994", - "de240ce6-74f8-4c15-8f6f-f0486d98cf93" - ] - }, - "e85533fb-029e-4366-8c59-d98768b9d994": { - "id": "e85533fb-029e-4366-8c59-d98768b9d994", - "name": "Inverter", - "category": "decorator", - "title": "Inverter", - "description": "", - "properties": {}, - "display": { - "x": 588, - "y": 72 - }, - "child": "65cd19af-85ed-4007-b276-cd4784c9e2eb" - }, - "5731b7b0-8447-43cf-8754-303d98a3634a": { - "id": "5731b7b0-8447-43cf-8754-303d98a3634a", - "name": "RVBSceneState", - "category": "condition", - "title": "RVBSceneState()", - "description": "红黑场景状态判定\n0 准备押注\n1 押注\n2 准备开牌\n3 开牌\n4 结算", - "properties": { - "state": 1 - }, - "display": { - "x": 216, - "y": -672 - } - }, - "9c95a923-029b-49d7-bf78-48c9842dc0dc": { - "id": "9c95a923-029b-49d7-bf78-48c9842dc0dc", - "name": "RandIntAction", - "category": "action", - "title": "RandIntAction(,,)", - "description": "随机获得一个[min,max)的整数,保存到黑板的index key中", - "properties": { - "index": "takeCoinDiv", - "min": 10, - "max": 30 - }, - "display": { - "x": 936, - "y": 1188 - } - }, - "3562d05e-c36f-422c-b9c0-44dd803c64c7": { - "id": "3562d05e-c36f-422c-b9c0-44dd803c64c7", - "name": "Sequence", - "category": "composite", - "title": "Sequence", - "description": "", - "properties": {}, - "display": { - "x": 528, - "y": 1224 - }, - "children": [ - "8b13cab6-11cb-496e-81db-3fb2c38113e1", - "9c95a923-029b-49d7-bf78-48c9842dc0dc", - "86c9f692-be00-4d13-88a2-289f80251c60", - "6fecd80b-3aa1-465e-a723-174c44c46213", - "2bd2caca-136a-4e2c-9822-722df79a15be" - ] - }, - "86c9f692-be00-4d13-88a2-289f80251c60": { - "id": "86c9f692-be00-4d13-88a2-289f80251c60", - "name": "GetPlayerTakeCoin", - "category": "action", - "title": "GetPlayerTakeCoin()", - "description": "获得玩家入场携带金币\ngINKey 保存黑板key", - "properties": { - "gINKey": "takeCoin" - }, - "display": { - "x": 924, - "y": 1236 - } - }, - "2bd2caca-136a-4e2c-9822-722df79a15be": { - "id": "2bd2caca-136a-4e2c-9822-722df79a15be", - "name": "CheckPlayerCoin", - "category": "condition", - "title": "CheckPlayerCoin(,)", - "description": "检查用户金币\ngIPCoin 支持@ 用户需要比较的金币\ncmp 比较\t\n 0 //小于\n 1 //小于等于\n 2 //等于\n 3 //大于\n 4 //大于等于", - "properties": { - "gIPCoin": "takeCoin", - "cmp": 0 - }, - "display": { - "x": 912, - "y": 1428 - } - }, - "8b13cab6-11cb-496e-81db-3fb2c38113e1": { - "id": "8b13cab6-11cb-496e-81db-3fb2c38113e1", - "name": "SetIntMulti", - "category": "action", - "title": "SetIntMulti(,,)", - "description": "设置乘法,保存数值\ngINKey 保存黑版key\ngIPValue1 v1 支持@\ngIPValue2 v2 支持@", - "properties": { - "gINKey": "takeCoin", - "gIPValue1": "takeCoin", - "gIPValue2": "takeCoinDiv" - }, - "display": { - "x": 972, - "y": 1140 - } - }, - "6fecd80b-3aa1-465e-a723-174c44c46213": { - "id": "6fecd80b-3aa1-465e-a723-174c44c46213", - "name": "SetIntDiv", - "category": "action", - "title": "SetIntDiv(,,)", - "description": "设定除法保存数据到黑板\ngINKey \ngIPValue1\ngIPValue2", - "properties": { - "gINKey": "takeCoin", - "gIPValue1": "takeCoin", - "gIPValue2": "@100" - }, - "display": { - "x": 936, - "y": 1344 - } - } - }, - "display": { - "camera_x": 582.9299999917857, - "camera_y": -88.36499998209183, - "camera_z": 0.75, - "x": -480, - "y": 252 - }, - "custom_nodes": [ - { - "version": "0.3.0", - "scope": "node", - "name": "RVBSceneState", - "category": "condition", - "title": "RVBSceneState()", - "description": "红黑场景状态判定\n0 准备押注\n1 押注\n2 准备开牌\n3 开牌\n4 结算", - "properties": { - "state": 0 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "RandIntAction", - "category": "action", - "title": "RandIntAction(,,)", - "description": "随机获得一个[min,max)的整数,保存到黑板的index key中", - "properties": { - "index": "key", - "min": 0, - "max": 1 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "RandWait", - "category": "action", - "title": "RandWait(,)", - "description": "节点暂停[minTime,maxTime)毫秒", - "properties": { - "minTime": 0, - "maxTime": 1 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "RandomWeightComposite", - "category": "composite", - "title": "RandomWeightComposite()", - "description": "根据权重随机,选择一个子节点。\n权重使用|分割。\n需要注意子节点的顺序,个数需要和权重对应", - "properties": { - "weight": "\"\"" - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "CheckBool", - "category": "condition", - "title": "CheckBool()", - "description": "检查一个黑板的key值", - "properties": { - "keyName": "key" - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "CheckInt", - "category": "condition", - "title": "CheckInt(,,)", - "description": "检查黑板的一个值和待比较值\n 0 //小于\n 1 //小于等于\n 2 //等于\n 3 //大于\n 4 //大于等于", - "properties": { - "keyName": "key", - "value": 0, - "cmp": 0 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "LogAction", - "category": "action", - "title": "LogAction(,)", - "description": "输出日志", - "properties": { - "info": "info", - "level": 0 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "RVBBetPct", - "category": "action", - "title": "RVBBetPct(,)", - "description": "红黑下注\ngIPpct 下注百分比,黑板key 支持@\ngIPArea 下注区域,黑板key 支持@", - "properties": { - "gIPpct": "key", - "gIPArea": 1 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "RVBLastWinArea", - "category": "action", - "title": "RVBLastWinArea()", - "description": "获得最后的下注结果保存到key,没有返回失败", - "properties": { - "gINKey": "key" - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "LeaveGame", - "category": "action", - "title": "LeaveGame", - "description": "离开游戏", - "properties": {} - }, - { - "version": "0.3.0", - "scope": "node", - "name": "CheckPlayerCoin", - "category": "condition", - "title": "CheckPlayerCoin(,)", - "description": "检查用户金币\ngIPCoin 支持@ 用户需要比较的金币\ncmp 比较\t\n 0 //小于\n 1 //小于等于\n 2 //等于\n 3 //大于\n 4 //大于等于", - "properties": { - "gIPCoin": "key", - "cmp": 0 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "GetOutLimitCoin", - "category": "action", - "title": "GetOutLimitCoin()", - "description": "获得玩家游戏踢出限制\ngINKey 保存到黑板key", - "properties": { - "gINKey": "key" - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "CheckPlayerGameNum", - "category": "condition", - "title": "CheckPlayerGameNum(,)", - "description": "检查用户游戏次数\ngIPGameNum支持@ 用户需要游戏次数\ncmp 比较\t\n 0 //小于\n 1 //小于等于\n 2 //等于\n 3 //大于\n 4 //大于等于", - "properties": { - "gIPGameNum": "key", - "cmp": 0 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "CheckPlayerLastWinOrLost", - "category": "condition", - "title": "CheckPlayerLastWinOrLost(,)", - "description": "检查玩家上次输赢情况\ngIPLResult 比较值 支持@\ncmp 比较", - "properties": { - "gIPLResult": "key", - "cmp": 0 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "SetIntAction", - "category": "action", - "title": "SetIntAction(,)", - "description": "设置int参数值\ngINKey 黑版key值\ngIPValue 设置的值,支持@", - "properties": { - "gINKey": "key", - "gIPValue": 0 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "RVBBetCoin", - "category": "action", - "title": "RVBBetCoin(,)", - "description": "红黑押注\ngIPBetCoin 押注金额 支持@\ngIPArea 押注区域支持@", - "properties": { - "gIPBetCoin": "key", - "gIPArea": 0 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "RVBCheckBetCoin", - "category": "action", - "title": "RVBCheckBetCoin(,)", - "description": "修正押注金额,保存到黑板key\ngIPSrcCoin 押注金额支持@\ngINSaveCoin 保存后key", - "properties": { - "gIPSrcCoin": "key", - "gINSaveCoin": 0 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "SetIntMulti", - "category": "action", - "title": "SetIntMulti(,,)", - "description": "设置乘法,保存数值\ngINKey 保存黑版key\ngIPValue1 v1 支持@\ngIPValue2 v2 支持@", - "properties": { - "gINKey": "key", - "gIPValue1": 0, - "gIPValue2": 0 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "GetPlayerCoin", - "category": "action", - "title": "GetPlayerCoin()", - "description": "得到玩家金币\ngINKey 保存key", - "properties": { - "gINKey": "key" - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "SetIntDiv", - "category": "action", - "title": "SetIntDiv(,,)", - "description": "设定除法保存数据到黑板\ngINKey \ngIPValue1\ngIPValue2", - "properties": { - "gINKey": "key", - "gIPValue1": 0, - "gIPValue2": 0 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "RVBHistoryIsSame", - "category": "condition", - "title": "RVBHistoryIsSame()", - "description": "判定是上几局都是相同的结果", - "properties": { - "gIPNum": "key", - "num": 0 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "GetPlayerTakeCoin", - "category": "action", - "title": "GetPlayerTakeCoin()", - "description": "获得玩家入场携带金币\ngINKey 保存黑板key", - "properties": { - "gINKey": "key" - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "DVTHistoryIsSame", - "category": "condition", - "title": "DVTHistoryIsSame()", - "description": "判定是上几局都是相同的结果\ngIPNum 支持@", - "properties": { - "gIPNum": "key" - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "DVTLastWinArea", - "category": "action", - "title": "DVTLastWinArea()", - "description": "龙虎最后获胜的区域保存到黑板", - "properties": { - "gINKey": "key" - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "DVTBetCoin", - "category": "action", - "title": "DVTBetCoin(,)", - "description": "龙虎押注", - "properties": { - "gIPBetCoin": "key", - "gIPArea": 0 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "DVTCheckBetCoin", - "category": "action", - "title": "DVTCheckBetCoin(,)", - "description": "龙虎检查下注额度", - "properties": { - "gIPSrcCoin": 0, - "gINSaveCoin": 0 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "DVTSceneState", - "category": "condition", - "title": "DVTSceneState()", - "description": "龙虎状态检查\n0 准备押注\n1 押注\n2 准备开牌\n3 开牌\n4 结算", - "properties": { - "state": 0 - } - } - ] -} \ No newline at end of file diff --git a/data/botai/rvbinvertwin.json b/data/botai/rvbinvertwin.json deleted file mode 100644 index 6c35203..0000000 --- a/data/botai/rvbinvertwin.json +++ /dev/null @@ -1,1285 +0,0 @@ -{ - "version": "0.3.0", - "scope": "tree", - "id": "bcbcd98d-0a18-4edc-80a0-f1ac01fbb289", - "title": "RVBInvertWinBot", - "description": "反龙 倍投", - "root": "5e8ef189-1c68-4e2d-96a2-093a9260e4c5", - "properties": {}, - "nodes": { - "04a7e3aa-fbc7-4eee-855b-0be19910dbc2": { - "id": "04a7e3aa-fbc7-4eee-855b-0be19910dbc2", - "name": "RVBSceneState", - "category": "condition", - "title": "RVBSceneState()", - "description": "红黑场景状态判定\n0 准备押注\n1 押注\n2 准备开牌\n3 开牌\n4 结算", - "properties": { - "state": 1 - }, - "display": { - "x": 744, - "y": -240 - } - }, - "d82746db-e3c3-4c20-a798-f4929bb7bc58": { - "id": "d82746db-e3c3-4c20-a798-f4929bb7bc58", - "name": "Sequence", - "category": "composite", - "title": "Sequence", - "description": "", - "properties": {}, - "display": { - "x": 360, - "y": -84 - }, - "children": [ - "04a7e3aa-fbc7-4eee-855b-0be19910dbc2", - "7ee1ee6e-7a67-431d-b74a-86dcf4d7c736", - "9a735735-d5e2-4ad9-a25c-1aa3102a097c", - "22f65664-750a-4786-86f7-0b1a55caf32f", - "7eab985d-b081-4b8d-9e47-0f936888da5e", - "c10981f9-a77c-4d35-80f7-83108bd43a15", - "132af4ee-8feb-4c71-8702-0d34384b5a7c" - ] - }, - "22169c28-d742-4508-8753-3568224e6965": { - "id": "22169c28-d742-4508-8753-3568224e6965", - "name": "RandIntAction", - "category": "action", - "title": "RandIntAction(,,)", - "description": "随机获得一个[min,max)的整数,保存到黑板的index key中", - "properties": { - "index": "betSrcCoin", - "min": 2, - "max": 6 - }, - "display": { - "x": 324, - "y": -480 - } - }, - "e78284a9-88a0-4db9-9cc7-4c481b5085df": { - "id": "e78284a9-88a0-4db9-9cc7-4c481b5085df", - "name": "RVBSceneState", - "category": "condition", - "title": "RVBSceneState()", - "description": "红黑场景状态判定\n0 准备押注\n1 押注\n2 准备开牌\n3 开牌\n4 结算", - "properties": { - "state": 1 - }, - "display": { - "x": 1056, - "y": 192 - } - }, - "509f2c7a-9091-429e-a713-750250e50aa8": { - "id": "509f2c7a-9091-429e-a713-750250e50aa8", - "name": "RandWait", - "category": "action", - "title": "RandWait(,)", - "description": "节点暂停[minTime,maxTime)毫秒", - "properties": { - "minTime": 600, - "maxTime": 1200 - }, - "display": { - "x": 1092, - "y": 336 - } - }, - "9a735735-d5e2-4ad9-a25c-1aa3102a097c": { - "id": "9a735735-d5e2-4ad9-a25c-1aa3102a097c", - "name": "RVBHistoryIsSame", - "category": "condition", - "title": "RVBHistoryIsSame()", - "description": "判定是上几局都是相同的结果", - "properties": { - "gIPNum": "sameNum", - "num": 3 - }, - "display": { - "x": 768, - "y": -132 - } - }, - "22f65664-750a-4786-86f7-0b1a55caf32f": { - "id": "22f65664-750a-4786-86f7-0b1a55caf32f", - "name": "RVBLastWinArea", - "category": "action", - "title": "RVBLastWinArea()", - "description": "获得最后的下注结果保存到key,没有返回失败", - "properties": { - "gINKey": "betArea" - }, - "display": { - "x": 744, - "y": -84 - } - }, - "bfd009ae-3e5c-4f60-8939-17d4216e65d7": { - "id": "bfd009ae-3e5c-4f60-8939-17d4216e65d7", - "name": "Sequence", - "category": "composite", - "title": "Sequence", - "description": "", - "properties": {}, - "display": { - "x": 24, - "y": 1044 - }, - "children": [ - "2099f74a-10b9-47fa-8fb6-7f09c56892c2", - "c9bfe3cf-4d62-48b5-8ee0-364b25ff174e", - "5f63726c-7922-4fcf-b393-05cf6e0c6bf7", - "cd38883a-38c9-4e1e-bc09-3dea72740355" - ] - }, - "2099f74a-10b9-47fa-8fb6-7f09c56892c2": { - "id": "2099f74a-10b9-47fa-8fb6-7f09c56892c2", - "name": "RVBSceneState", - "category": "condition", - "title": "RVBSceneState()", - "description": "红黑场景状态判定\n0 准备押注\n1 押注\n2 准备开牌\n3 开牌\n4 结算", - "properties": { - "state": 4 - }, - "display": { - "x": 264, - "y": 924 - } - }, - "13e3c21b-919b-4608-8c4f-156c275b8f01": { - "id": "13e3c21b-919b-4608-8c4f-156c275b8f01", - "name": "CheckPlayerCoin", - "category": "condition", - "title": "CheckPlayerCoin(,)", - "description": "检查用户金币\ngIPCoin 支持@ 用户需要比较的金币\ncmp 比较\t\n 0 //小于\n 1 //小于等于\n 2 //等于\n 3 //大于\n 4 //大于等于", - "properties": { - "gIPCoin": "saveLimit", - "cmp": 0 - }, - "display": { - "x": 912, - "y": 948 - } - }, - "243c4715-ef1d-46c4-aa1a-7a1cea7640d8": { - "id": "243c4715-ef1d-46c4-aa1a-7a1cea7640d8", - "name": "GetOutLimitCoin", - "category": "action", - "title": "GetOutLimitCoin()", - "description": "获得玩家游戏踢出限制\ngINKey 保存到黑板key", - "properties": { - "gINKey": "saveLimit" - }, - "display": { - "x": 900, - "y": 876 - } - }, - "5f63726c-7922-4fcf-b393-05cf6e0c6bf7": { - "id": "5f63726c-7922-4fcf-b393-05cf6e0c6bf7", - "name": "RandWait", - "category": "action", - "title": "RandWait(,)", - "description": "节点暂停[minTime,maxTime)毫秒", - "properties": { - "minTime": 500, - "maxTime": 3500 - }, - "display": { - "x": 252, - "y": 1200 - } - }, - "cd38883a-38c9-4e1e-bc09-3dea72740355": { - "id": "cd38883a-38c9-4e1e-bc09-3dea72740355", - "name": "LeaveGame", - "category": "action", - "title": "LeaveGame", - "description": "离开游戏", - "properties": {}, - "display": { - "x": 216, - "y": 1344 - } - }, - "1b9c36d2-95ac-401f-8da9-1cad33396832": { - "id": "1b9c36d2-95ac-401f-8da9-1cad33396832", - "name": "CheckPlayerGameNum", - "category": "condition", - "title": "CheckPlayerGameNum(,)", - "description": "检查用户游戏次数\ngIPGameNum支持@ 用户需要游戏次数\ncmp 比较\t\n 0 //小于\n 1 //小于等于\n 2 //等于\n 3 //大于\n 4 //大于等于", - "properties": { - "gIPGameNum": "maxGameNum", - "cmp": 4 - }, - "display": { - "x": 960, - "y": 1128 - } - }, - "ca9584e7-ec24-447c-811e-d986401ce76d": { - "id": "ca9584e7-ec24-447c-811e-d986401ce76d", - "name": "RandIntAction", - "category": "action", - "title": "RandIntAction(,,)", - "description": "随机获得一个[min,max)的整数,保存到黑板的index key中", - "properties": { - "index": "maxGameNum", - "min": 40, - "max": 80 - }, - "display": { - "x": 936, - "y": 1044 - } - }, - "2be54f8d-7266-4246-86e8-8174fb4bf191": { - "id": "2be54f8d-7266-4246-86e8-8174fb4bf191", - "name": "Sequence", - "category": "composite", - "title": "Sequence", - "description": "生成初始押注额度", - "properties": {}, - "display": { - "x": 84, - "y": -420 - }, - "children": [ - "191cc1aa-c2fd-41d6-aa56-1b9a440de6ba", - "34adecfc-97b9-4d6c-a62f-0397acffb5dd", - "1c3b2110-eb51-4aa5-bef8-cfa3960f5e80", - "22169c28-d742-4508-8753-3568224e6965", - "7045671b-03f0-4490-8f3f-1b5e5f4eca86", - "f519275f-63b3-4491-a588-72f36f9dbf17", - "c236ac94-5ed8-4c3e-8504-30d6d632aa6c", - "3c3872e0-36fc-496a-89a6-7dae8248f7f7" - ] - }, - "34adecfc-97b9-4d6c-a62f-0397acffb5dd": { - "id": "34adecfc-97b9-4d6c-a62f-0397acffb5dd", - "name": "CheckInt", - "category": "condition", - "title": "CheckInt(,,)", - "description": "检查黑板的一个值和待比较值\n 0 //小于\n 1 //小于等于\n 2 //等于\n 3 //大于\n 4 //大于等于", - "properties": { - "keyName": "needStartBet", - "value": 0, - "cmp": 2 - }, - "display": { - "x": 300, - "y": -576 - } - }, - "1c3b2110-eb51-4aa5-bef8-cfa3960f5e80": { - "id": "1c3b2110-eb51-4aa5-bef8-cfa3960f5e80", - "name": "SetIntAction", - "category": "action", - "title": "SetIntAction(,)", - "description": "设置int参数值\ngINKey 黑版key值\ngIPValue 设置的值,支持@", - "properties": { - "gINKey": "needStartBet", - "gIPValue": "@1" - }, - "display": { - "x": 324, - "y": -528 - } - }, - "2a1e554f-1b42-410d-874b-d3fc859f76fe": { - "id": "2a1e554f-1b42-410d-874b-d3fc859f76fe", - "name": "RVBBetCoin", - "category": "action", - "title": "RVBBetCoin(,)", - "description": "红黑押注\ngIPBetCoin 押注金额 支持@\ngIPArea 押注区域支持@", - "properties": { - "gIPBetCoin": "betCoin", - "gIPArea": "betArea" - }, - "display": { - "x": 1116, - "y": 408 - } - }, - "3c3872e0-36fc-496a-89a6-7dae8248f7f7": { - "id": "3c3872e0-36fc-496a-89a6-7dae8248f7f7", - "name": "RVBCheckBetCoin", - "category": "action", - "title": "RVBCheckBetCoin(,)", - "description": "修正押注金额,保存到黑板key\ngIPSrcCoin 押注金额支持@\ngINSaveCoin 保存后key", - "properties": { - "gIPSrcCoin": "betSrcCoin", - "gINSaveCoin": "betSrcCoin" - }, - "display": { - "x": 372, - "y": -276 - } - }, - "7eab985d-b081-4b8d-9e47-0f936888da5e": { - "id": "7eab985d-b081-4b8d-9e47-0f936888da5e", - "name": "SetIntMulti", - "category": "action", - "title": "SetIntMulti(,,)", - "description": "设置乘法,保存数值\ngINKey 保存黑版key\ngIPValue1 v1 支持@\ngIPValue2 v2 支持@", - "properties": { - "gINKey": "betCoin", - "gIPValue1": "betSrcCoin", - "gIPValue2": "needStartBet" - }, - "display": { - "x": 816, - "y": -24 - } - }, - "c10981f9-a77c-4d35-80f7-83108bd43a15": { - "id": "c10981f9-a77c-4d35-80f7-83108bd43a15", - "name": "SetIntMulti", - "category": "action", - "title": "SetIntMulti(,,)", - "description": "设置乘法,保存数值\ngINKey 保存黑版key\ngIPValue1 v1 支持@\ngIPValue2 v2 支持@", - "properties": { - "gINKey": "needStartBet", - "gIPValue1": "needStartBet", - "gIPValue2": "@2" - }, - "display": { - "x": 804, - "y": 24 - } - }, - "2e099a8f-9b75-4f55-a62c-80dbe1ea0c66": { - "id": "2e099a8f-9b75-4f55-a62c-80dbe1ea0c66", - "name": "Sequence", - "category": "composite", - "title": "Sequence", - "description": "", - "properties": {}, - "display": { - "x": 192, - "y": 684 - }, - "children": [ - "8590d78b-fa12-4811-87f2-8e60b63aa1c8", - "9be91e8d-2024-457f-9c4e-e9d6ba1eb89a", - "3de2a4dd-b7f7-476f-9f40-58f1588cddeb" - ] - }, - "8590d78b-fa12-4811-87f2-8e60b63aa1c8": { - "id": "8590d78b-fa12-4811-87f2-8e60b63aa1c8", - "name": "RVBSceneState", - "category": "condition", - "title": "RVBSceneState()", - "description": "红黑场景状态判定\n0 准备押注\n1 押注\n2 准备开牌\n3 开牌\n4 结算", - "properties": { - "state": 4 - }, - "display": { - "x": 408, - "y": 612 - } - }, - "9be91e8d-2024-457f-9c4e-e9d6ba1eb89a": { - "id": "9be91e8d-2024-457f-9c4e-e9d6ba1eb89a", - "name": "CheckPlayerLastWinOrLost", - "category": "condition", - "title": "CheckPlayerLastWinOrLost(,)", - "description": "检查玩家上次输赢情况\ngIPLResult 比较值 支持@\ncmp 比较", - "properties": { - "gIPLResult": "@1", - "cmp": 2 - }, - "display": { - "x": 480, - "y": 684 - } - }, - "3de2a4dd-b7f7-476f-9f40-58f1588cddeb": { - "id": "3de2a4dd-b7f7-476f-9f40-58f1588cddeb", - "name": "SetIntAction", - "category": "action", - "title": "SetIntAction(,)", - "description": "设置int参数值\ngINKey 黑版key值\ngIPValue 设置的值,支持@", - "properties": { - "gINKey": "needStartBet", - "gIPValue": "@0" - }, - "display": { - "x": 468, - "y": 756 - } - }, - "7045671b-03f0-4490-8f3f-1b5e5f4eca86": { - "id": "7045671b-03f0-4490-8f3f-1b5e5f4eca86", - "name": "GetPlayerCoin", - "category": "action", - "title": "GetPlayerCoin()", - "description": "得到玩家金币\ngINKey 保存key", - "properties": { - "gINKey": "playerCoin" - }, - "display": { - "x": 312, - "y": -432 - } - }, - "f519275f-63b3-4491-a588-72f36f9dbf17": { - "id": "f519275f-63b3-4491-a588-72f36f9dbf17", - "name": "SetIntMulti", - "category": "action", - "title": "SetIntMulti(,,)", - "description": "设置乘法,保存数值\ngINKey 保存黑版key\ngIPValue1 v1 支持@\ngIPValue2 v2 支持@", - "properties": { - "gINKey": "betSrcCoin", - "gIPValue1": "betSrcCoin", - "gIPValue2": "playerCoin" - }, - "display": { - "x": 384, - "y": -384 - } - }, - "c236ac94-5ed8-4c3e-8504-30d6d632aa6c": { - "id": "c236ac94-5ed8-4c3e-8504-30d6d632aa6c", - "name": "SetIntDiv", - "category": "action", - "title": "SetIntDiv(,,)", - "description": "设定除法保存数据到黑板\ngINKey \ngIPValue1\ngIPValue2", - "properties": { - "gINKey": "betSrcCoin", - "gIPValue1": "betSrcCoin", - "gIPValue2": "@100" - }, - "display": { - "x": 360, - "y": -336 - } - }, - "c9bfe3cf-4d62-48b5-8ee0-364b25ff174e": { - "id": "c9bfe3cf-4d62-48b5-8ee0-364b25ff174e", - "name": "Priority", - "category": "composite", - "title": "Priority", - "description": "", - "properties": {}, - "display": { - "x": 336, - "y": 1056 - }, - "children": [ - "e31db30e-34af-4e2e-b65b-6be86e089141", - "9a2d8fb2-f8fa-4782-8c62-81da19d633a3", - "41e3bada-b468-4a60-9115-090e440bd49a", - "455c4049-1886-4ab0-8609-c9d3fd0d8263" - ] - }, - "e31db30e-34af-4e2e-b65b-6be86e089141": { - "id": "e31db30e-34af-4e2e-b65b-6be86e089141", - "name": "Sequence", - "category": "composite", - "title": "Sequence", - "description": "", - "properties": {}, - "display": { - "x": 576, - "y": 972 - }, - "children": [ - "243c4715-ef1d-46c4-aa1a-7a1cea7640d8", - "13e3c21b-919b-4608-8c4f-156c275b8f01" - ] - }, - "9a2d8fb2-f8fa-4782-8c62-81da19d633a3": { - "id": "9a2d8fb2-f8fa-4782-8c62-81da19d633a3", - "name": "Sequence", - "category": "composite", - "title": "Sequence", - "description": "", - "properties": {}, - "display": { - "x": 576, - "y": 1128 - }, - "children": [ - "ca9584e7-ec24-447c-811e-d986401ce76d", - "1b9c36d2-95ac-401f-8da9-1cad33396832" - ] - }, - "7ee1ee6e-7a67-431d-b74a-86dcf4d7c736": { - "id": "7ee1ee6e-7a67-431d-b74a-86dcf4d7c736", - "name": "RandIntAction", - "category": "action", - "title": "RandIntAction(,,)", - "description": "随机获得一个[min,max)的整数,保存到黑板的index key中", - "properties": { - "index": "sameNum", - "min": 3, - "max": 5 - }, - "display": { - "x": 768, - "y": -180 - } - }, - "2c51e0ee-4d4f-43c2-8419-0d66ada2fdb1": { - "id": "2c51e0ee-4d4f-43c2-8419-0d66ada2fdb1", - "name": "Sequence", - "category": "composite", - "title": "Sequence", - "description": "", - "properties": {}, - "display": { - "x": 816, - "y": 276 - }, - "children": [ - "e78284a9-88a0-4db9-9cc7-4c481b5085df", - "3ef80a4a-aa41-4d47-b06f-847af6ee0e93", - "509f2c7a-9091-429e-a713-750250e50aa8", - "464528f0-4195-4946-8279-fb3bbc0b37e3" - ] - }, - "464528f0-4195-4946-8279-fb3bbc0b37e3": { - "id": "464528f0-4195-4946-8279-fb3bbc0b37e3", - "name": "Priority", - "category": "composite", - "title": "Priority", - "description": "", - "properties": {}, - "display": { - "x": 900, - "y": 420 - }, - "children": [ - "2a1e554f-1b42-410d-874b-d3fc859f76fe", - "af0c68f9-fc34-4a05-86bc-3f7d2d17830b" - ] - }, - "af0c68f9-fc34-4a05-86bc-3f7d2d17830b": { - "id": "af0c68f9-fc34-4a05-86bc-3f7d2d17830b", - "name": "SetIntAction", - "category": "action", - "title": "SetIntAction(,)", - "description": "设置int参数值\ngINKey 黑版key值\ngIPValue 设置的值,支持@", - "properties": { - "gINKey": "betIsOk", - "gIPValue": "@1" - }, - "display": { - "x": 1104, - "y": 480 - } - }, - "3ef80a4a-aa41-4d47-b06f-847af6ee0e93": { - "id": "3ef80a4a-aa41-4d47-b06f-847af6ee0e93", - "name": "CheckInt", - "category": "condition", - "title": "CheckInt(,,)", - "description": "检查黑板的一个值和待比较值\n 0 //小于\n 1 //小于等于\n 2 //等于\n 3 //大于\n 4 //大于等于", - "properties": { - "keyName": "betIsOk", - "value": 0, - "cmp": 2 - }, - "display": { - "x": 1080, - "y": 276 - } - }, - "b9901516-891a-496f-9d09-4905203f905d": { - "id": "b9901516-891a-496f-9d09-4905203f905d", - "name": "SetIntAction", - "category": "action", - "title": "SetIntAction(,)", - "description": "设置int参数值\ngINKey 黑版key值\ngIPValue 设置的值,支持@", - "properties": { - "gINKey": "betIsOk", - "gIPValue": "@0" - }, - "display": { - "x": 372, - "y": 360 - } - }, - "455c4049-1886-4ab0-8609-c9d3fd0d8263": { - "id": "455c4049-1886-4ab0-8609-c9d3fd0d8263", - "name": "CheckPlayerCoin", - "category": "condition", - "title": "CheckPlayerCoin(,)", - "description": "检查用户金币\ngIPCoin 支持@ 用户需要比较的金币\ncmp 比较\t\n 0 //小于\n 1 //小于等于\n 2 //等于\n 3 //大于\n 4 //大于等于", - "properties": { - "gIPCoin": "betCoin", - "cmp": 0 - }, - "display": { - "x": 660, - "y": 1524 - } - }, - "99088e7a-2b9f-4a9f-8df3-b1bb39366142": { - "id": "99088e7a-2b9f-4a9f-8df3-b1bb39366142", - "name": "Sequence", - "category": "composite", - "title": "Sequence", - "description": "", - "properties": {}, - "display": { - "x": 132, - "y": 396 - }, - "children": [ - "b9901516-891a-496f-9d09-4905203f905d", - "9eefd3d3-d61e-46af-808e-cd298da3bef7", - "9575b0af-999d-413f-8b99-713dd3fa59d8" - ] - }, - "9eefd3d3-d61e-46af-808e-cd298da3bef7": { - "id": "9eefd3d3-d61e-46af-808e-cd298da3bef7", - "name": "RVBSceneState", - "category": "condition", - "title": "RVBSceneState()", - "description": "红黑场景状态判定\n0 准备押注\n1 押注\n2 准备开牌\n3 开牌\n4 结算", - "properties": { - "state": 1 - }, - "display": { - "x": 348, - "y": 432 - } - }, - "9575b0af-999d-413f-8b99-713dd3fa59d8": { - "id": "9575b0af-999d-413f-8b99-713dd3fa59d8", - "name": "Runner", - "category": "action", - "title": "Runner", - "description": "", - "properties": {}, - "display": { - "x": 348, - "y": 504 - } - }, - "a7da2d4a-9556-4049-8855-b24190414a8b": { - "id": "a7da2d4a-9556-4049-8855-b24190414a8b", - "name": "Runner", - "category": "action", - "title": "Runner", - "description": "", - "properties": {}, - "display": { - "x": 1044, - "y": 552 - } - }, - "5e8ef189-1c68-4e2d-96a2-093a9260e4c5": { - "id": "5e8ef189-1c68-4e2d-96a2-093a9260e4c5", - "name": "Priority", - "category": "composite", - "title": "Priority", - "description": "", - "properties": {}, - "display": { - "x": -312, - "y": 192 - }, - "children": [ - "2be54f8d-7266-4246-86e8-8174fb4bf191", - "c3e8cb6f-4d62-47d3-af65-f876e4afcf44", - "2e099a8f-9b75-4f55-a62c-80dbe1ea0c66", - "bfd009ae-3e5c-4f60-8939-17d4216e65d7" - ] - }, - "c3e8cb6f-4d62-47d3-af65-f876e4afcf44": { - "id": "c3e8cb6f-4d62-47d3-af65-f876e4afcf44", - "name": "MemSequence", - "category": "composite", - "title": "MemSequence", - "description": "", - "properties": {}, - "display": { - "x": 0, - "y": 108 - }, - "children": [ - "d82746db-e3c3-4c20-a798-f4929bb7bc58", - "c7deb35f-1a13-4025-95eb-7a284ecd3385", - "99088e7a-2b9f-4a9f-8df3-b1bb39366142" - ] - }, - "c7deb35f-1a13-4025-95eb-7a284ecd3385": { - "id": "c7deb35f-1a13-4025-95eb-7a284ecd3385", - "name": "Priority", - "category": "composite", - "title": "Priority", - "description": "", - "properties": {}, - "display": { - "x": 564, - "y": 312 - }, - "children": [ - "4afdfe17-63c5-49f8-a97a-62a64b7f2dc6", - "a7da2d4a-9556-4049-8855-b24190414a8b" - ] - }, - "4afdfe17-63c5-49f8-a97a-62a64b7f2dc6": { - "id": "4afdfe17-63c5-49f8-a97a-62a64b7f2dc6", - "name": "Inverter", - "category": "decorator", - "title": "Inverter", - "description": "", - "properties": {}, - "display": { - "x": 684, - "y": 252 - }, - "child": "2c51e0ee-4d4f-43c2-8419-0d66ada2fdb1" - }, - "191cc1aa-c2fd-41d6-aa56-1b9a440de6ba": { - "id": "191cc1aa-c2fd-41d6-aa56-1b9a440de6ba", - "name": "RVBSceneState", - "category": "condition", - "title": "RVBSceneState()", - "description": "红黑场景状态判定\n0 准备押注\n1 押注\n2 准备开牌\n3 开牌\n4 结算", - "properties": { - "state": 1 - }, - "display": { - "x": 264, - "y": -624 - } - }, - "132af4ee-8feb-4c71-8702-0d34384b5a7c": { - "id": "132af4ee-8feb-4c71-8702-0d34384b5a7c", - "name": "Priority", - "category": "composite", - "title": "Priority", - "description": "", - "properties": {}, - "display": { - "x": 660, - "y": 96 - }, - "children": [ - "73a509d2-7eb1-4666-8a29-53c9a0fc0f4e", - "72e53829-3919-43fe-afc9-e3e02ede7ffe" - ] - }, - "73a509d2-7eb1-4666-8a29-53c9a0fc0f4e": { - "id": "73a509d2-7eb1-4666-8a29-53c9a0fc0f4e", - "name": "Sequence", - "category": "composite", - "title": "Sequence", - "description": "", - "properties": {}, - "display": { - "x": 996, - "y": 72 - }, - "children": [ - "b436f8d6-18cc-4f03-8b91-90d43c2969b8", - "941cfa1c-5228-41d3-b37e-eb1b35890235" - ] - }, - "b436f8d6-18cc-4f03-8b91-90d43c2969b8": { - "id": "b436f8d6-18cc-4f03-8b91-90d43c2969b8", - "name": "CheckInt", - "category": "condition", - "title": "CheckInt(,,)", - "description": "检查黑板的一个值和待比较值\n 0 //小于\n 1 //小于等于\n 2 //等于\n 3 //大于\n 4 //大于等于", - "properties": { - "keyName": "betArea", - "value": 0, - "cmp": 2 - }, - "display": { - "x": 1260, - "y": -48 - } - }, - "941cfa1c-5228-41d3-b37e-eb1b35890235": { - "id": "941cfa1c-5228-41d3-b37e-eb1b35890235", - "name": "SetIntAction", - "category": "action", - "title": "SetIntAction(,)", - "description": "设置int参数值\ngINKey 黑版key值\ngIPValue 设置的值,支持@", - "properties": { - "gINKey": "betArea", - "gIPValue": "@1" - }, - "display": { - "x": 1284, - "y": 12 - } - }, - "72e53829-3919-43fe-afc9-e3e02ede7ffe": { - "id": "72e53829-3919-43fe-afc9-e3e02ede7ffe", - "name": "Sequence", - "category": "composite", - "title": "Sequence", - "description": "", - "properties": {}, - "display": { - "x": 996, - "y": 120 - }, - "children": [ - "4f1b9b1c-ba0e-4647-8506-15158a24707e", - "0b7f9248-bd04-444f-85b1-cfd06be650ee" - ] - }, - "4f1b9b1c-ba0e-4647-8506-15158a24707e": { - "id": "4f1b9b1c-ba0e-4647-8506-15158a24707e", - "name": "CheckInt", - "category": "condition", - "title": "CheckInt(,,)", - "description": "检查黑板的一个值和待比较值\n 0 //小于\n 1 //小于等于\n 2 //等于\n 3 //大于\n 4 //大于等于", - "properties": { - "keyName": "betArea", - "value": 1, - "cmp": 2 - }, - "display": { - "x": 1284, - "y": 60 - } - }, - "0b7f9248-bd04-444f-85b1-cfd06be650ee": { - "id": "0b7f9248-bd04-444f-85b1-cfd06be650ee", - "name": "SetIntAction", - "category": "action", - "title": "SetIntAction(,)", - "description": "设置int参数值\ngINKey 黑版key值\ngIPValue 设置的值,支持@", - "properties": { - "gINKey": "betArea", - "gIPValue": "@0" - }, - "display": { - "x": 1308, - "y": 120 - } - }, - "0da9990b-5d53-4bbe-8e9f-4d6b9066746d": { - "id": "0da9990b-5d53-4bbe-8e9f-4d6b9066746d", - "name": "RandIntAction", - "category": "action", - "title": "RandIntAction(,,)", - "description": "随机获得一个[min,max)的整数,保存到黑板的index key中", - "properties": { - "index": "takeCoinDiv", - "min": 10, - "max": 30 - }, - "display": { - "x": 924, - "y": 1188 - } - }, - "41e3bada-b468-4a60-9115-090e440bd49a": { - "id": "41e3bada-b468-4a60-9115-090e440bd49a", - "name": "Sequence", - "category": "composite", - "title": "Sequence", - "description": "", - "properties": {}, - "display": { - "x": 576, - "y": 1236 - }, - "children": [ - "0da9990b-5d53-4bbe-8e9f-4d6b9066746d", - "20475fe6-09d0-4813-8cdc-1736deba8418", - "7ce22449-b59a-40be-8f1b-5bcf2ce0754e", - "d08a6179-81dd-4431-84ff-f623c888d4a8", - "7046f547-8d2e-43d3-a8b6-822386ae6e0e" - ] - }, - "20475fe6-09d0-4813-8cdc-1736deba8418": { - "id": "20475fe6-09d0-4813-8cdc-1736deba8418", - "name": "GetPlayerTakeCoin", - "category": "action", - "title": "GetPlayerTakeCoin()", - "description": "获得玩家入场携带金币\ngINKey 保存黑板key", - "properties": { - "gINKey": "takeCoin" - }, - "display": { - "x": 912, - "y": 1236 - } - }, - "7046f547-8d2e-43d3-a8b6-822386ae6e0e": { - "id": "7046f547-8d2e-43d3-a8b6-822386ae6e0e", - "name": "CheckPlayerCoin", - "category": "condition", - "title": "CheckPlayerCoin(,)", - "description": "检查用户金币\ngIPCoin 支持@ 用户需要比较的金币\ncmp 比较\t\n 0 //小于\n 1 //小于等于\n 2 //等于\n 3 //大于\n 4 //大于等于", - "properties": { - "gIPCoin": "takeCoin", - "cmp": 0 - }, - "display": { - "x": 900, - "y": 1428 - } - }, - "7ce22449-b59a-40be-8f1b-5bcf2ce0754e": { - "id": "7ce22449-b59a-40be-8f1b-5bcf2ce0754e", - "name": "SetIntMulti", - "category": "action", - "title": "SetIntMulti(,,)", - "description": "设置乘法,保存数值\ngINKey 保存黑版key\ngIPValue1 v1 支持@\ngIPValue2 v2 支持@", - "properties": { - "gINKey": "takeCoin", - "gIPValue1": "takeCoin", - "gIPValue2": "takeCoinDiv" - }, - "display": { - "x": 960, - "y": 1296 - } - }, - "d08a6179-81dd-4431-84ff-f623c888d4a8": { - "id": "d08a6179-81dd-4431-84ff-f623c888d4a8", - "name": "SetIntDiv", - "category": "action", - "title": "SetIntDiv(,,)", - "description": "设定除法保存数据到黑板\ngINKey \ngIPValue1\ngIPValue2", - "properties": { - "gINKey": "takeCoin", - "gIPValue1": "takeCoin", - "gIPValue2": "@100" - }, - "display": { - "x": 924, - "y": 1356 - } - } - }, - "display": { - "camera_x": 616.7549999991315, - "camera_y": -272.9800000007963, - "camera_z": 0.75, - "x": -540, - "y": 180 - }, - "custom_nodes": [ - { - "version": "0.3.0", - "scope": "node", - "name": "RVBSceneState", - "category": "condition", - "title": "RVBSceneState()", - "description": "红黑场景状态判定\n0 准备押注\n1 押注\n2 准备开牌\n3 开牌\n4 结算", - "properties": { - "state": 0 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "RandIntAction", - "category": "action", - "title": "RandIntAction(,,)", - "description": "随机获得一个[min,max)的整数,保存到黑板的index key中", - "properties": { - "index": "key", - "min": 0, - "max": 1 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "RandWait", - "category": "action", - "title": "RandWait(,)", - "description": "节点暂停[minTime,maxTime)毫秒", - "properties": { - "minTime": 0, - "maxTime": 1 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "RandomWeightComposite", - "category": "composite", - "title": "RandomWeightComposite()", - "description": "根据权重随机,选择一个子节点。\n权重使用|分割。\n需要注意子节点的顺序,个数需要和权重对应", - "properties": { - "weight": "\"\"" - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "CheckBool", - "category": "condition", - "title": "CheckBool()", - "description": "检查一个黑板的key值", - "properties": { - "keyName": "key" - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "CheckInt", - "category": "condition", - "title": "CheckInt(,,)", - "description": "检查黑板的一个值和待比较值\n 0 //小于\n 1 //小于等于\n 2 //等于\n 3 //大于\n 4 //大于等于", - "properties": { - "keyName": "key", - "value": 0, - "cmp": 0 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "LogAction", - "category": "action", - "title": "LogAction(,)", - "description": "输出日志", - "properties": { - "info": "info", - "level": 0 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "RVBBetPct", - "category": "action", - "title": "RVBBetPct(,)", - "description": "红黑下注\ngIPpct 下注百分比,黑板key 支持@\ngIPArea 下注区域,黑板key 支持@", - "properties": { - "gIPpct": "key", - "gIPArea": 1 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "RVBLastWinArea", - "category": "action", - "title": "RVBLastWinArea()", - "description": "获得最后的下注结果保存到key,没有返回失败", - "properties": { - "gINKey": "key" - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "LeaveGame", - "category": "action", - "title": "LeaveGame", - "description": "离开游戏", - "properties": {} - }, - { - "version": "0.3.0", - "scope": "node", - "name": "CheckPlayerCoin", - "category": "condition", - "title": "CheckPlayerCoin(,)", - "description": "检查用户金币\ngIPCoin 支持@ 用户需要比较的金币\ncmp 比较\t\n 0 //小于\n 1 //小于等于\n 2 //等于\n 3 //大于\n 4 //大于等于", - "properties": { - "gIPCoin": "key", - "cmp": 0 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "GetOutLimitCoin", - "category": "action", - "title": "GetOutLimitCoin()", - "description": "获得玩家游戏踢出限制\ngINKey 保存到黑板key", - "properties": { - "gINKey": "key" - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "CheckPlayerGameNum", - "category": "condition", - "title": "CheckPlayerGameNum(,)", - "description": "检查用户游戏次数\ngIPGameNum支持@ 用户需要游戏次数\ncmp 比较\t\n 0 //小于\n 1 //小于等于\n 2 //等于\n 3 //大于\n 4 //大于等于", - "properties": { - "gIPGameNum": "key", - "cmp": 0 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "CheckPlayerLastWinOrLost", - "category": "condition", - "title": "CheckPlayerLastWinOrLost(,)", - "description": "检查玩家上次输赢情况\ngIPLResult 比较值 支持@\ncmp 比较", - "properties": { - "gIPLResult": "key", - "cmp": 0 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "SetIntAction", - "category": "action", - "title": "SetIntAction(,)", - "description": "设置int参数值\ngINKey 黑版key值\ngIPValue 设置的值,支持@", - "properties": { - "gINKey": "key", - "gIPValue": 0 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "RVBBetCoin", - "category": "action", - "title": "RVBBetCoin(,)", - "description": "红黑押注\ngIPBetCoin 押注金额 支持@\ngIPArea 押注区域支持@", - "properties": { - "gIPBetCoin": "key", - "gIPArea": 0 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "RVBCheckBetCoin", - "category": "action", - "title": "RVBCheckBetCoin(,)", - "description": "修正押注金额,保存到黑板key\ngIPSrcCoin 押注金额支持@\ngINSaveCoin 保存后key", - "properties": { - "gIPSrcCoin": "key", - "gINSaveCoin": 0 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "SetIntMulti", - "category": "action", - "title": "SetIntMulti(,,)", - "description": "设置乘法,保存数值\ngINKey 保存黑版key\ngIPValue1 v1 支持@\ngIPValue2 v2 支持@", - "properties": { - "gINKey": "key", - "gIPValue1": 0, - "gIPValue2": 0 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "GetPlayerCoin", - "category": "action", - "title": "GetPlayerCoin()", - "description": "得到玩家金币\ngINKey 保存key", - "properties": { - "gINKey": "key" - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "SetIntDiv", - "category": "action", - "title": "SetIntDiv(,,)", - "description": "设定除法保存数据到黑板\ngINKey \ngIPValue1\ngIPValue2", - "properties": { - "gINKey": "key", - "gIPValue1": 0, - "gIPValue2": 0 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "RVBHistoryIsSame", - "category": "condition", - "title": "RVBHistoryIsSame()", - "description": "判定是上几局都是相同的结果", - "properties": { - "gIPNum": "key", - "num": 0 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "GetPlayerTakeCoin", - "category": "action", - "title": "GetPlayerTakeCoin()", - "description": "获得玩家入场携带金币\ngINKey 保存黑板key", - "properties": { - "gINKey": "key" - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "DVTHistoryIsSame", - "category": "condition", - "title": "DVTHistoryIsSame()", - "description": "判定是上几局都是相同的结果\ngIPNum 支持@", - "properties": { - "gIPNum": "key" - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "DVTLastWinArea", - "category": "action", - "title": "DVTLastWinArea()", - "description": "龙虎最后获胜的区域保存到黑板", - "properties": { - "gINKey": "key" - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "DVTBetCoin", - "category": "action", - "title": "DVTBetCoin(,)", - "description": "龙虎押注", - "properties": { - "gIPBetCoin": "key", - "gIPArea": 0 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "DVTCheckBetCoin", - "category": "action", - "title": "DVTCheckBetCoin(,)", - "description": "龙虎检查下注额度", - "properties": { - "gIPSrcCoin": 0, - "gINSaveCoin": 0 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "DVTSceneState", - "category": "condition", - "title": "DVTSceneState()", - "description": "龙虎状态检查\n0 准备押注\n1 押注\n2 准备开牌\n3 开牌\n4 结算", - "properties": { - "state": 0 - } - } - ] -} \ No newline at end of file diff --git a/data/botai/rvbrandom.json b/data/botai/rvbrandom.json deleted file mode 100644 index 54fe92c..0000000 --- a/data/botai/rvbrandom.json +++ /dev/null @@ -1,1026 +0,0 @@ -{ - "version": "0.3.0", - "scope": "tree", - "id": "7dc34556-b453-4e90-8fa4-468cb40c1a94", - "title": "RVBRandomBot", - "description": "随机下注", - "root": "61acd76e-6aed-4df1-8e46-a86644fd41d3", - "properties": {}, - "nodes": { - "7a63cc18-b09a-489b-98c9-e3aec5ebb761": { - "id": "7a63cc18-b09a-489b-98c9-e3aec5ebb761", - "name": "MemSequence", - "category": "composite", - "title": "MemSequence", - "description": "", - "properties": {}, - "display": { - "x": 312, - "y": -348 - }, - "children": [ - "636e84b3-e817-452f-874c-7f4146eef5ba", - "0db31a0d-b752-4850-8402-a2c8f95a3651", - "b716de05-b53b-4cb4-be2a-49a2961a38d5", - "82ef36d0-175c-4045-9aed-f900e51f649c" - ] - }, - "0db31a0d-b752-4850-8402-a2c8f95a3651": { - "id": "0db31a0d-b752-4850-8402-a2c8f95a3651", - "name": "RandWait", - "category": "action", - "title": "RandWait(,)", - "description": "节点暂停[minTime,maxTime)毫秒", - "properties": { - "minTime": 100, - "maxTime": 4000 - }, - "display": { - "x": 696, - "y": -420 - } - }, - "b716de05-b53b-4cb4-be2a-49a2961a38d5": { - "id": "b716de05-b53b-4cb4-be2a-49a2961a38d5", - "name": "RandomWeightComposite", - "category": "composite", - "title": "RandomWeightComposite()", - "description": "根据权重随机,选择一个子节点。\n权重使用|分割。\n需要注意子节点的顺序,个数需要和权重对应", - "properties": { - "weight": "10|100" - }, - "display": { - "x": 684, - "y": -264 - }, - "children": [ - "44b72066-4117-42fc-8c11-12e641ac7963", - "61296429-2d2f-4ea2-88f7-e0bbd6f881d3" - ] - }, - "61acd76e-6aed-4df1-8e46-a86644fd41d3": { - "id": "61acd76e-6aed-4df1-8e46-a86644fd41d3", - "name": "Priority", - "category": "composite", - "title": "Priority", - "description": "", - "properties": {}, - "display": { - "x": 108, - "y": 324 - }, - "children": [ - "7a63cc18-b09a-489b-98c9-e3aec5ebb761", - "a95b1a70-8eb6-41e3-b938-8d88cfb807de" - ] - }, - "a95b1a70-8eb6-41e3-b938-8d88cfb807de": { - "id": "a95b1a70-8eb6-41e3-b938-8d88cfb807de", - "name": "Sequence", - "category": "composite", - "title": "Sequence", - "description": "", - "properties": {}, - "display": { - "x": 360, - "y": 564 - }, - "children": [ - "397dc2cf-c281-4992-a858-069be6a1b791", - "db5bac79-6fb0-43c8-a119-09925c126e28", - "67ac5481-3e6f-4612-a33a-a431d09163ef", - "4176b141-6c22-47f0-b03f-de940e092514" - ] - }, - "397dc2cf-c281-4992-a858-069be6a1b791": { - "id": "397dc2cf-c281-4992-a858-069be6a1b791", - "name": "RVBSceneState", - "category": "condition", - "title": "RVBSceneState()", - "description": "红黑场景状态判定\n0 准备押注\n1 押注\n2 准备开牌\n3 开牌\n4 结算", - "properties": { - "state": 4 - }, - "display": { - "x": 600, - "y": 444 - } - }, - "f3b1d188-97d4-4a39-9623-5f21eda87ca1": { - "id": "f3b1d188-97d4-4a39-9623-5f21eda87ca1", - "name": "CheckPlayerCoin", - "category": "condition", - "title": "CheckPlayerCoin(,)", - "description": "检查用户金币\ngIPCoin 支持@ 用户需要比较的金币\ncmp 比较\t\n 0 //小于\n 1 //小于等于\n 2 //等于\n 3 //大于\n 4 //大于等于", - "properties": { - "gIPCoin": "saveLimit", - "cmp": 0 - }, - "display": { - "x": 1248, - "y": 468 - } - }, - "1d3e262c-ec24-45af-8138-9a12d624edcc": { - "id": "1d3e262c-ec24-45af-8138-9a12d624edcc", - "name": "GetOutLimitCoin", - "category": "action", - "title": "GetOutLimitCoin()", - "description": "获得玩家游戏踢出限制\ngINKey 保存到黑板key", - "properties": { - "gINKey": "saveLimit" - }, - "display": { - "x": 1236, - "y": 396 - } - }, - "67ac5481-3e6f-4612-a33a-a431d09163ef": { - "id": "67ac5481-3e6f-4612-a33a-a431d09163ef", - "name": "RandWait", - "category": "action", - "title": "RandWait(,)", - "description": "节点暂停[minTime,maxTime)毫秒", - "properties": { - "minTime": 500, - "maxTime": 3000 - }, - "display": { - "x": 588, - "y": 720 - } - }, - "4176b141-6c22-47f0-b03f-de940e092514": { - "id": "4176b141-6c22-47f0-b03f-de940e092514", - "name": "LeaveGame", - "category": "action", - "title": "LeaveGame", - "description": "离开游戏", - "properties": {}, - "display": { - "x": 564, - "y": 912 - } - }, - "451ea4cd-408b-48fe-852d-a38711db5357": { - "id": "451ea4cd-408b-48fe-852d-a38711db5357", - "name": "CheckPlayerGameNum", - "category": "condition", - "title": "CheckPlayerGameNum(,)", - "description": "检查用户游戏次数\ngIPGameNum支持@ 用户需要游戏次数\ncmp 比较\t\n 0 //小于\n 1 //小于等于\n 2 //等于\n 3 //大于\n 4 //大于等于", - "properties": { - "gIPGameNum": "maxGameNum", - "cmp": 4 - }, - "display": { - "x": 1296, - "y": 648 - } - }, - "32d3b272-ee17-45ef-8681-c8593701d96a": { - "id": "32d3b272-ee17-45ef-8681-c8593701d96a", - "name": "RandIntAction", - "category": "action", - "title": "RandIntAction(,,)", - "description": "随机获得一个[min,max)的整数,保存到黑板的index key中", - "properties": { - "index": "maxGameNum", - "min": 50, - "max": 80 - }, - "display": { - "x": 1272, - "y": 564 - } - }, - "db5bac79-6fb0-43c8-a119-09925c126e28": { - "id": "db5bac79-6fb0-43c8-a119-09925c126e28", - "name": "Priority", - "category": "composite", - "title": "Priority", - "description": "", - "properties": {}, - "display": { - "x": 672, - "y": 576 - }, - "children": [ - "1efd066c-8ed8-4b1c-8ebd-257c45afafc5", - "62c3db0e-241c-4497-8b06-fecdf5e8d10e", - "e053f60d-7c4b-4810-925f-364a5a6f7f97", - "a9836e66-89c0-4805-bc00-d001854fb972" - ] - }, - "1efd066c-8ed8-4b1c-8ebd-257c45afafc5": { - "id": "1efd066c-8ed8-4b1c-8ebd-257c45afafc5", - "name": "Sequence", - "category": "composite", - "title": "Sequence", - "description": "", - "properties": {}, - "display": { - "x": 912, - "y": 492 - }, - "children": [ - "1d3e262c-ec24-45af-8138-9a12d624edcc", - "f3b1d188-97d4-4a39-9623-5f21eda87ca1" - ] - }, - "62c3db0e-241c-4497-8b06-fecdf5e8d10e": { - "id": "62c3db0e-241c-4497-8b06-fecdf5e8d10e", - "name": "Sequence", - "category": "composite", - "title": "Sequence", - "description": "", - "properties": {}, - "display": { - "x": 912, - "y": 648 - }, - "children": [ - "32d3b272-ee17-45ef-8681-c8593701d96a", - "451ea4cd-408b-48fe-852d-a38711db5357" - ] - }, - "a9836e66-89c0-4805-bc00-d001854fb972": { - "id": "a9836e66-89c0-4805-bc00-d001854fb972", - "name": "CheckPlayerCoin", - "category": "condition", - "title": "CheckPlayerCoin(,)", - "description": "检查用户金币\ngIPCoin 支持@ 用户需要比较的金币\ncmp 比较\t\n 0 //小于\n 1 //小于等于\n 2 //等于\n 3 //大于\n 4 //大于等于", - "properties": { - "gIPCoin": "betCoin", - "cmp": 0 - }, - "display": { - "x": 1008, - "y": 1104 - } - }, - "e6e7396f-2b1a-4d80-858a-51e5b7781d28": { - "id": "e6e7396f-2b1a-4d80-858a-51e5b7781d28", - "name": "RandIntAction", - "category": "action", - "title": "RandIntAction(,,)", - "description": "随机获得一个[min,max)的整数,保存到黑板的index key中", - "properties": { - "index": "betSrcCoin", - "min": 15, - "max": 35 - }, - "display": { - "x": 720, - "y": -792 - } - }, - "636e84b3-e817-452f-874c-7f4146eef5ba": { - "id": "636e84b3-e817-452f-874c-7f4146eef5ba", - "name": "Sequence", - "category": "composite", - "title": "Sequence", - "description": "生成初始押注额度", - "properties": {}, - "display": { - "x": 468, - "y": -672 - }, - "children": [ - "6354ee40-1eb7-4117-96c0-ca164c722f97", - "e6e7396f-2b1a-4d80-858a-51e5b7781d28", - "06b2fa81-958e-492d-844c-63ec253a45c6", - "1bcebd0c-d082-4dde-9f5d-f54162699ee7", - "982002cc-2646-41c3-84b6-8c610e1c087f", - "cc63113d-9572-43e7-8f23-f6ca0678b796", - "871ccb22-30c2-4d0a-9d52-534ad305de4b" - ] - }, - "cc63113d-9572-43e7-8f23-f6ca0678b796": { - "id": "cc63113d-9572-43e7-8f23-f6ca0678b796", - "name": "RVBCheckBetCoin", - "category": "action", - "title": "RVBCheckBetCoin(,)", - "description": "修正押注金额,保存到黑板key\ngIPSrcCoin 押注金额支持@\ngINSaveCoin 保存后key", - "properties": { - "gIPSrcCoin": "betSrcCoin", - "gINSaveCoin": "betCoin" - }, - "display": { - "x": 756, - "y": -552 - } - }, - "06b2fa81-958e-492d-844c-63ec253a45c6": { - "id": "06b2fa81-958e-492d-844c-63ec253a45c6", - "name": "GetPlayerCoin", - "category": "action", - "title": "GetPlayerCoin()", - "description": "得到玩家金币\ngINKey 保存key", - "properties": { - "gINKey": "playerCoin" - }, - "display": { - "x": 708, - "y": -732 - } - }, - "982002cc-2646-41c3-84b6-8c610e1c087f": { - "id": "982002cc-2646-41c3-84b6-8c610e1c087f", - "name": "SetIntDiv", - "category": "action", - "title": "SetIntDiv(,,)", - "description": "设定除法保存数据到黑板\ngINKey \ngIPValue1\ngIPValue2", - "properties": { - "gINKey": "betSrcCoin", - "gIPValue1": "betSrcCoin", - "gIPValue2": "@100" - }, - "display": { - "x": 756, - "y": -612 - } - }, - "6354ee40-1eb7-4117-96c0-ca164c722f97": { - "id": "6354ee40-1eb7-4117-96c0-ca164c722f97", - "name": "RVBSceneState", - "category": "condition", - "title": "RVBSceneState()", - "description": "红黑场景状态判定\n0 准备押注\n1 押注\n2 准备开牌\n3 开牌\n4 结算", - "properties": { - "state": 1 - }, - "display": { - "x": 648, - "y": -876 - } - }, - "871ccb22-30c2-4d0a-9d52-534ad305de4b": { - "id": "871ccb22-30c2-4d0a-9d52-534ad305de4b", - "name": "RandIntAction", - "category": "action", - "title": "RandIntAction(,,)", - "description": "随机获得一个[min,max)的整数,保存到黑板的index key中", - "properties": { - "index": "betArea", - "min": 0, - "max": 2 - }, - "display": { - "x": 708, - "y": -492 - } - }, - "82ef36d0-175c-4045-9aed-f900e51f649c": { - "id": "82ef36d0-175c-4045-9aed-f900e51f649c", - "name": "Sequence", - "category": "composite", - "title": "Sequence", - "description": "", - "properties": {}, - "display": { - "x": 444, - "y": -72 - }, - "children": [ - "ef706ab5-b108-4475-97a3-c8336c48b451", - "01308bf4-dcb1-437f-810e-31d0487a4c9e" - ] - }, - "ef706ab5-b108-4475-97a3-c8336c48b451": { - "id": "ef706ab5-b108-4475-97a3-c8336c48b451", - "name": "RVBSceneState", - "category": "condition", - "title": "RVBSceneState()", - "description": "红黑场景状态判定\n0 准备押注\n1 押注\n2 准备开牌\n3 开牌\n4 结算", - "properties": { - "state": 1 - }, - "display": { - "x": 636, - "y": -96 - } - }, - "01308bf4-dcb1-437f-810e-31d0487a4c9e": { - "id": "01308bf4-dcb1-437f-810e-31d0487a4c9e", - "name": "Runner", - "category": "action", - "title": "Runner", - "description": "", - "properties": {}, - "display": { - "x": 624, - "y": -12 - } - }, - "c0da4159-f259-4881-9c52-1e41cc8aa75e": { - "id": "c0da4159-f259-4881-9c52-1e41cc8aa75e", - "name": "RandWait", - "category": "action", - "title": "RandWait(,)", - "description": "节点暂停[minTime,maxTime)毫秒", - "properties": { - "minTime": 300, - "maxTime": 900 - }, - "display": { - "x": 1464, - "y": -444 - } - }, - "25c0e6a3-b5b8-4be2-a168-83bde0188ba9": { - "id": "25c0e6a3-b5b8-4be2-a168-83bde0188ba9", - "name": "RVBBetCoin", - "category": "action", - "title": "RVBBetCoin(,)", - "description": "红黑押注\ngIPBetCoin 押注金额 支持@\ngIPArea 押注区域支持@", - "properties": { - "gIPBetCoin": "betCoin", - "gIPArea": "@2" - }, - "display": { - "x": 1500, - "y": -360 - } - }, - "e18e1e73-ff91-4a13-892c-78719aab101d": { - "id": "e18e1e73-ff91-4a13-892c-78719aab101d", - "name": "Sequence", - "category": "composite", - "title": "Sequence", - "description": "", - "properties": {}, - "display": { - "x": 1272, - "y": -408 - }, - "children": [ - "c0da4159-f259-4881-9c52-1e41cc8aa75e", - "25c0e6a3-b5b8-4be2-a168-83bde0188ba9" - ] - }, - "615b29db-284f-4b90-818c-2151ec030aac": { - "id": "615b29db-284f-4b90-818c-2151ec030aac", - "name": "Runner", - "category": "action", - "title": "Runner", - "description": "", - "properties": {}, - "display": { - "x": 1440, - "y": -276 - } - }, - "44b72066-4117-42fc-8c11-12e641ac7963": { - "id": "44b72066-4117-42fc-8c11-12e641ac7963", - "name": "Priority", - "category": "composite", - "title": "Priority", - "description": "", - "properties": {}, - "display": { - "x": 1008, - "y": -288 - }, - "children": [ - "78a7aff1-616d-4372-9b03-1345ee67aed9", - "615b29db-284f-4b90-818c-2151ec030aac" - ] - }, - "78a7aff1-616d-4372-9b03-1345ee67aed9": { - "id": "78a7aff1-616d-4372-9b03-1345ee67aed9", - "name": "Inverter", - "category": "decorator", - "title": "Inverter", - "description": "", - "properties": {}, - "display": { - "x": 1140, - "y": -372 - }, - "child": "e18e1e73-ff91-4a13-892c-78719aab101d" - }, - "05965a4d-b80a-40f0-899e-da9291c589aa": { - "id": "05965a4d-b80a-40f0-899e-da9291c589aa", - "name": "RandWait", - "category": "action", - "title": "RandWait(,)", - "description": "节点暂停[minTime,maxTime)毫秒", - "properties": { - "minTime": 200, - "maxTime": 600 - }, - "display": { - "x": 1476, - "y": -180 - } - }, - "7f387e61-6dfb-4e92-8123-4f8a46dcfce6": { - "id": "7f387e61-6dfb-4e92-8123-4f8a46dcfce6", - "name": "RVBBetCoin", - "category": "action", - "title": "RVBBetCoin(,)", - "description": "红黑押注\ngIPBetCoin 押注金额 支持@\ngIPArea 押注区域支持@", - "properties": { - "gIPBetCoin": "betCoin", - "gIPArea": "betArea" - }, - "display": { - "x": 1512, - "y": -96 - } - }, - "6fc1821d-dba7-408a-8297-bdcff52b2750": { - "id": "6fc1821d-dba7-408a-8297-bdcff52b2750", - "name": "Sequence", - "category": "composite", - "title": "Sequence", - "description": "", - "properties": {}, - "display": { - "x": 1284, - "y": -144 - }, - "children": [ - "05965a4d-b80a-40f0-899e-da9291c589aa", - "7f387e61-6dfb-4e92-8123-4f8a46dcfce6" - ] - }, - "fb22c1ec-6b73-4e0c-8332-069407b31bb6": { - "id": "fb22c1ec-6b73-4e0c-8332-069407b31bb6", - "name": "Runner", - "category": "action", - "title": "Runner", - "description": "", - "properties": {}, - "display": { - "x": 1428, - "y": 12 - } - }, - "61296429-2d2f-4ea2-88f7-e0bbd6f881d3": { - "id": "61296429-2d2f-4ea2-88f7-e0bbd6f881d3", - "name": "Priority", - "category": "composite", - "title": "Priority", - "description": "", - "properties": {}, - "display": { - "x": 1020, - "y": -24 - }, - "children": [ - "555526d7-e9c7-46fd-892f-2dafa22ddc78", - "fb22c1ec-6b73-4e0c-8332-069407b31bb6" - ] - }, - "555526d7-e9c7-46fd-892f-2dafa22ddc78": { - "id": "555526d7-e9c7-46fd-892f-2dafa22ddc78", - "name": "Inverter", - "category": "decorator", - "title": "Inverter", - "description": "", - "properties": {}, - "display": { - "x": 1152, - "y": -108 - }, - "child": "6fc1821d-dba7-408a-8297-bdcff52b2750" - }, - "1bcebd0c-d082-4dde-9f5d-f54162699ee7": { - "id": "1bcebd0c-d082-4dde-9f5d-f54162699ee7", - "name": "SetIntMulti", - "category": "action", - "title": "SetIntMulti(,,)", - "description": "设置乘法,保存数值\ngINKey 保存黑版key\ngIPValue1 v1 支持@\ngIPValue2 v2 支持@", - "properties": { - "gINKey": "betSrcCoin", - "gIPValue1": "betSrcCoin", - "gIPValue2": "playerCoin" - }, - "display": { - "x": 780, - "y": -672 - } - }, - "a445b081-8aeb-4a8d-859e-337c2c599763": { - "id": "a445b081-8aeb-4a8d-859e-337c2c599763", - "name": "RandIntAction", - "category": "action", - "title": "RandIntAction(,,)", - "description": "随机获得一个[min,max)的整数,保存到黑板的index key中", - "properties": { - "index": "takeCoinDiv", - "min": 5, - "max": 40 - }, - "display": { - "x": 1284, - "y": 720 - } - }, - "e053f60d-7c4b-4810-925f-364a5a6f7f97": { - "id": "e053f60d-7c4b-4810-925f-364a5a6f7f97", - "name": "Sequence", - "category": "composite", - "title": "Sequence", - "description": "", - "properties": {}, - "display": { - "x": 912, - "y": 768 - }, - "children": [ - "a445b081-8aeb-4a8d-859e-337c2c599763", - "04848730-ff32-4fde-b3a4-1fb1a39af240", - "be0f13cd-8aa5-4c15-8333-c69d4cd339ef", - "6cd3023a-d433-45a9-8bbe-a99a828d3be6", - "e47faeae-783f-4cca-8c91-91b7ac112009" - ] - }, - "04848730-ff32-4fde-b3a4-1fb1a39af240": { - "id": "04848730-ff32-4fde-b3a4-1fb1a39af240", - "name": "GetPlayerTakeCoin", - "category": "action", - "title": "GetPlayerTakeCoin()", - "description": "获得玩家入场携带金币\ngINKey 保存黑板key", - "properties": { - "gINKey": "takeCoin" - }, - "display": { - "x": 1272, - "y": 768 - } - }, - "e47faeae-783f-4cca-8c91-91b7ac112009": { - "id": "e47faeae-783f-4cca-8c91-91b7ac112009", - "name": "CheckPlayerCoin", - "category": "condition", - "title": "CheckPlayerCoin(,)", - "description": "检查用户金币\ngIPCoin 支持@ 用户需要比较的金币\ncmp 比较\t\n 0 //小于\n 1 //小于等于\n 2 //等于\n 3 //大于\n 4 //大于等于", - "properties": { - "gIPCoin": "takeCoin", - "cmp": 0 - }, - "display": { - "x": 1260, - "y": 960 - } - }, - "be0f13cd-8aa5-4c15-8333-c69d4cd339ef": { - "id": "be0f13cd-8aa5-4c15-8333-c69d4cd339ef", - "name": "SetIntMulti", - "category": "action", - "title": "SetIntMulti(,,)", - "description": "设置乘法,保存数值\ngINKey 保存黑版key\ngIPValue1 v1 支持@\ngIPValue2 v2 支持@", - "properties": { - "gINKey": "takeCoin", - "gIPValue1": "takeCoin", - "gIPValue2": "takeCoinDiv" - }, - "display": { - "x": 1320, - "y": 828 - } - }, - "6cd3023a-d433-45a9-8bbe-a99a828d3be6": { - "id": "6cd3023a-d433-45a9-8bbe-a99a828d3be6", - "name": "SetIntDiv", - "category": "action", - "title": "SetIntDiv(,,)", - "description": "设定除法保存数据到黑板\ngINKey \ngIPValue1\ngIPValue2", - "properties": { - "gINKey": "takeCoin", - "gIPValue1": "takeCoin", - "gIPValue2": "@100" - }, - "display": { - "x": 1284, - "y": 888 - } - } - }, - "display": { - "camera_x": 285.7500000118962, - "camera_y": 135.66499998217478, - "camera_z": 0.75, - "x": -96, - "y": 324 - }, - "custom_nodes": [ - { - "version": "0.3.0", - "scope": "node", - "name": "RVBSceneState", - "category": "condition", - "title": "RVBSceneState()", - "description": "红黑场景状态判定\n0 准备押注\n1 押注\n2 准备开牌\n3 开牌\n4 结算", - "properties": { - "state": 0 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "RandIntAction", - "category": "action", - "title": "RandIntAction(,,)", - "description": "随机获得一个[min,max)的整数,保存到黑板的index key中", - "properties": { - "index": "key", - "min": 0, - "max": 1 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "RandWait", - "category": "action", - "title": "RandWait(,)", - "description": "节点暂停[minTime,maxTime)毫秒", - "properties": { - "minTime": 0, - "maxTime": 1 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "RandomWeightComposite", - "category": "composite", - "title": "RandomWeightComposite()", - "description": "根据权重随机,选择一个子节点。\n权重使用|分割。\n需要注意子节点的顺序,个数需要和权重对应", - "properties": { - "weight": "\"\"" - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "CheckBool", - "category": "condition", - "title": "CheckBool()", - "description": "检查一个黑板的key值", - "properties": { - "keyName": "key" - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "CheckInt", - "category": "condition", - "title": "CheckInt(,,)", - "description": "检查黑板的一个值和待比较值\n 0 //小于\n 1 //小于等于\n 2 //等于\n 3 //大于\n 4 //大于等于", - "properties": { - "keyName": "key", - "value": 0, - "cmp": 0 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "LogAction", - "category": "action", - "title": "LogAction(,)", - "description": "输出日志", - "properties": { - "info": "info", - "level": 0 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "RVBBetPct", - "category": "action", - "title": "RVBBetPct(,)", - "description": "红黑下注\ngIPpct 下注百分比,黑板key 支持@\ngIPArea 下注区域,黑板key 支持@", - "properties": { - "gIPpct": "key", - "gIPArea": 1 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "RVBLastWinArea", - "category": "action", - "title": "RVBLastWinArea()", - "description": "获得最后的下注结果保存到key,没有返回失败", - "properties": { - "gINKey": "key" - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "LeaveGame", - "category": "action", - "title": "LeaveGame", - "description": "离开游戏", - "properties": {} - }, - { - "version": "0.3.0", - "scope": "node", - "name": "CheckPlayerCoin", - "category": "condition", - "title": "CheckPlayerCoin(,)", - "description": "检查用户金币\ngIPCoin 支持@ 用户需要比较的金币\ncmp 比较\t\n 0 //小于\n 1 //小于等于\n 2 //等于\n 3 //大于\n 4 //大于等于", - "properties": { - "gIPCoin": "key", - "cmp": 0 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "GetOutLimitCoin", - "category": "action", - "title": "GetOutLimitCoin()", - "description": "获得玩家游戏踢出限制\ngINKey 保存到黑板key", - "properties": { - "gINKey": "key" - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "CheckPlayerGameNum", - "category": "condition", - "title": "CheckPlayerGameNum(,)", - "description": "检查用户游戏次数\ngIPGameNum支持@ 用户需要游戏次数\ncmp 比较\t\n 0 //小于\n 1 //小于等于\n 2 //等于\n 3 //大于\n 4 //大于等于", - "properties": { - "gIPGameNum": "key", - "cmp": 0 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "CheckPlayerLastWinOrLost", - "category": "condition", - "title": "CheckPlayerLastWinOrLost(,)", - "description": "检查玩家上次输赢情况\ngIPLResult 比较值 支持@\ncmp 比较", - "properties": { - "gIPLResult": "key", - "cmp": 0 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "SetIntAction", - "category": "action", - "title": "SetIntAction(,)", - "description": "设置int参数值\ngINKey 黑版key值\ngIPValue 设置的值,支持@", - "properties": { - "gINKey": "key", - "gIPValue": 0 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "RVBBetCoin", - "category": "action", - "title": "RVBBetCoin(,)", - "description": "红黑押注\ngIPBetCoin 押注金额 支持@\ngIPArea 押注区域支持@", - "properties": { - "gIPBetCoin": "key", - "gIPArea": 0 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "RVBCheckBetCoin", - "category": "action", - "title": "RVBCheckBetCoin(,)", - "description": "修正押注金额,保存到黑板key\ngIPSrcCoin 押注金额支持@\ngINSaveCoin 保存后key", - "properties": { - "gIPSrcCoin": "key", - "gINSaveCoin": 0 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "SetIntMulti", - "category": "action", - "title": "SetIntMulti(,,)", - "description": "设置乘法,保存数值\ngINKey 保存黑版key\ngIPValue1 v1 支持@\ngIPValue2 v2 支持@", - "properties": { - "gINKey": "key", - "gIPValue1": 0, - "gIPValue2": 0 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "GetPlayerCoin", - "category": "action", - "title": "GetPlayerCoin()", - "description": "得到玩家金币\ngINKey 保存key", - "properties": { - "gINKey": "key" - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "SetIntDiv", - "category": "action", - "title": "SetIntDiv(,,)", - "description": "设定除法保存数据到黑板\ngINKey \ngIPValue1\ngIPValue2", - "properties": { - "gINKey": "key", - "gIPValue1": 0, - "gIPValue2": 0 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "RVBHistoryIsSame", - "category": "condition", - "title": "RVBHistoryIsSame()", - "description": "判定是上几局都是相同的结果", - "properties": { - "gIPNum": "key", - "num": 0 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "GetPlayerTakeCoin", - "category": "action", - "title": "GetPlayerTakeCoin()", - "description": "获得玩家入场携带金币\ngINKey 保存黑板key", - "properties": { - "gINKey": "key" - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "DVTHistoryIsSame", - "category": "condition", - "title": "DVTHistoryIsSame()", - "description": "判定是上几局都是相同的结果\ngIPNum 支持@", - "properties": { - "gIPNum": "key" - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "DVTLastWinArea", - "category": "action", - "title": "DVTLastWinArea()", - "description": "龙虎最后获胜的区域保存到黑板", - "properties": { - "gINKey": "key" - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "DVTBetCoin", - "category": "action", - "title": "DVTBetCoin(,)", - "description": "龙虎押注", - "properties": { - "gIPBetCoin": "key", - "gIPArea": 0 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "DVTCheckBetCoin", - "category": "action", - "title": "DVTCheckBetCoin(,)", - "description": "龙虎检查下注额度", - "properties": { - "gIPSrcCoin": 0, - "gINSaveCoin": 0 - } - }, - { - "version": "0.3.0", - "scope": "node", - "name": "DVTSceneState", - "category": "condition", - "title": "DVTSceneState()", - "description": "龙虎状态检查\n0 准备押注\n1 押注\n2 准备开牌\n3 开牌\n4 结算", - "properties": { - "state": 0 - } - } - ] -} \ No newline at end of file diff --git a/data/fishpath/path.json b/data/fishpath/path.json deleted file mode 100644 index f630728..0000000 --- a/data/fishpath/path.json +++ /dev/null @@ -1 +0,0 @@ -{"count":3,"pools":[{"id":-1,"type":2,"scatter":0,"s_obj":{"helix":0,"h_obj":{"offset":0},"custom":0,"c_obj":{"start":0,"offset":0}},"move":0,"m_obj":{"sx":0,"sy":0,"ex":0,"ey":0,"sp":0},"points":[{"x":-464,"y":-77,"stay":0},{"x":354,"y":1175,"stay":100},{"x":1352,"y":1038,"stay":50},{"x":897,"y":-374,"stay":50}],"stay":200,"length":3986}],"maxId":3,"lastEdit":1} \ No newline at end of file diff --git a/tools/upload/config.json b/tools/upload/config.json index b3c35ad..62d98ff 100644 --- a/tools/upload/config.json +++ b/tools/upload/config.json @@ -3,5 +3,6 @@ "Passwd": "123456", "Addr": "127.0.0.1", "RemoteDir": "/root/win88", - "LocalDir": "D:\\trunk\\src\\mongo.games.com\\game" + "LocalDir": "D:\\trunk\\src\\mongo.games.com\\game", + "PPK": "C:\\Users\\dell\\Downloads\\beta.ppk" } \ No newline at end of file From 0143ebbe1214071b031392e6e91073a017986e51 Mon Sep 17 00:00:00 2001 From: sk <123456@qq.com> Date: Thu, 5 Dec 2024 09:41:29 +0800 Subject: [PATCH 36/41] =?UTF-8?q?=E4=BF=AE=E5=A4=8Ddbgamefree=E5=8D=8F?= =?UTF-8?q?=E8=AE=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- data/DB_GameFree.dat | Bin 23953 -> 24371 bytes data/DB_GameFree.json | 137 +++++++++++++++++++++++++++++++++++ data/DB_GameItem.dat | Bin 20409 -> 20409 bytes data/DB_GameItem.json | 8 +- data/DB_PropExchange.dat | Bin 384 -> 384 bytes data/DB_Task.dat | Bin 5519 -> 5519 bytes protocol/server/pbdata.pb.go | 38 +++++----- protocol/server/pbdata.proto | 8 +- xlsx/DB_GameFree.xlsx | Bin 66837 -> 66196 bytes xlsx/DB_GameItem.xlsx | Bin 37444 -> 37420 bytes 10 files changed, 164 insertions(+), 27 deletions(-) diff --git a/data/DB_GameFree.dat b/data/DB_GameFree.dat index 28559c2cd217a73fd8bd958ff461ac0ce54bb150..4b9a383b3c0829d72ba0ef81300e8ce6a332276f 100644 GIT binary patch delta 3093 zcmY*beNa?Y6rZzu*B(!B0e1mGU=ef$QSg&hSVKr#L_Su8U4j0ore+!)QPC(e6>uan zndOvCWiphOX()&_CZnKf=GX_N<HIP!ONAq~d<7iW^4gL_u97HSw-_ zL*N0t!J!U@&#_mb*l-d!gn^LBK?L@PG>bk^8gO1%3_hqvYRG}SF&I$S@=~K*>I4-h zk5mSUTE$^dnrLYZUKtr-@d$P*+#ZYJp*3&>H-^#%7S4Gi?0C^W0?&l5f@3&0jPfHm zzcDo)Tf%DLUAz-EYfwxKmW)~@PJ?nBw_1~MU6P77N71hGI0JdHxIZZbAO5&q^3~&ZQXr^92oioP9n=%TC-mX6O^z@#pll;tVLCNhF(e8(atb z3?{|lOR=k{O-IGihMG|UIF1+MriXZ-6#UXmYAyOq?PDotqMXWt^}eE=U&Tvt2}pev z@f*0Bk1)NN%B)=05#I_YaB2cU1?6m<)0&H|*d?LcLsfJnDj^;Vl_YS9q1X5TugS6t ziIE|m5mYjbOZ2w;05>~whKXe-RlMPNSbPe~H`wBEQu`6qpq<-q4KH7j%O&Gzc~G<7 zh2D{C;3NEV9I+d;a|^B&1E5@$&|i`XYS8UKXUcMM4wP&7_qd7JpAuozOkH>@rB=`k z>&AX(0!<)78+;BnBzby3F1yWY#P8txQF>~SKL)uusjMehMq??_N&Xp*z_uT84!6Ap zPT|Ihlr!k%J6*>fzfDw$_(*HDMz*u~0+c^wNneT@F~~I3I8y@f5RT56qFue+88axZ8y2s?3mNnR$g9cgE3h!r z7`Nd&nW@_Px0w$?I~GpWXCKF3;`OPMg6loe)6xMh;yu$T!PBp2<@BilKj5n~D8VD8 zXJAG)z)cLDMG2lMJ+o)!0qnvjveI-7S#_`*lUx+b0b1m$7jN=ovOdcm{q3R7?+(At zwml_WP0yS8{_zdD?OHFoKzWvn@R`~A6z!PZDE5Q$oJ_mtP&zm<=QO}}JU1s@+j2*C z6vkxx=x8 z#y>HyLG0y5hq+PMH<#W*?P=HqZ=m;XDwA8(=QoNypd92f>kP+Px(z#JWAF(RbDKmb zC~rxQBe}$(4gV;-n7a}Vpm!ee$hlTOe~Z`+$}!xR7lmWuda2dM_60zDte>?Ih z#36cl;B^%^&|WZlhzk0!vp|1i>+>Z=$ouBZ0W+u#fXfy-HHzmJ`d|zGv~au@+X^3q zb@*6eiWavQmcx3y&9Rgjx5!8F>O~Ywc`q#TnKl6a$_eRHbdet#v8G773;1$Tx!6P+ z+e)G^w3u2?(m0BJoV`NX=%E>~&*b{+2IQK9)Vqp(uo?d?)~*Pql`Q40no4x-oh9Wa zI*hrL5|TB&)W?Y?PDpi~r9Kj4@lMplWqAEe(d^YJy1kO(uEjb<=3+)PFD8U!II!3+ z8bJwQplo#XwQXJ3o_dco@#iZTpXt-_ zl|IHFCF5v;|HL|B;NG;{X5v delta 2737 zcmZWqdr;KZ6`r$uSuZQBJYLEe&}G&U`p_4dCyW+XB5p>u&{4EFIbcKo-AQ=W`7j3x$8ta>`cN9P zkPhQ>2`Jv)jpC@)^a>6{aUcR2?quAEYNKOljpl#@m)$8i5xrWSAl;7}t_)e!`8j!q zj)m52ac!mn{MU6yXrKpyaStmN@^w@Egd?ojj%%4|_-9!xQnHq-KaoCZYMS!GY7_=z zw$Mo|iRFf}P6BRt9N0f80*7Lo6)QbpNEO*(B-t_%9obHF#s4@yW6I(eLoy0+r!-JJcYgoUF5|Fbe!|Q30 zW4>qFcEmby!J|i|SgX#Eejk^Ta^cU8bdHP+NpLoKo#G3y8?h;=d;{Vf0jj0t5hKnR zfGg$uj)0AWPRkwgv3_j`{;^Kir)y2V>H4Z`6bI4yq<`(Aw5=S(_Rr z{SkMX%<{%M0@kMDE+g#$^yj3)lM}XSBE($-IF|E&(z3%u+FnEWZ7vfmNke91Ne`Nw zKf&qxjJ*FcvX4s3#uI7#OijscVbX3DSr3``X?GacTDD6K@*{}Sys2VKT${pjSUxbe zRPU1h)Z|6hugLrDcVsnAmAcPNoyfXtYM87c;|{@>S2ikb$h`d0ePKvq-im2V3Riip zdY|-{oX-;jj}Et%PXwEoet=W?)8z7glRtw&e!&Q6!qWxj!In%D^z;$14eO@gCY*VN zKcZc574i!b0)NKKh2LY)d#P|L(FH`$U}Wp{&6rN~5mw#K$lm+>?L|cY#^3H>q!tYh~R(7L3pYE}SgPjSFj;`S*o}>0Bht z6^jgW>mn(;x`@l{h`Udgdhk95gzXGEab187sWtVy$GRF*)>G5KW%k9UtYC31J%+~x z*l=iZ9dlxWrpy-<&UOI`Zv=&tS!*~|wZhpez=ro~g_B=rI1P2eIV?coN?ijzgtGcH zS?B(Ge^#>|K68}fqUWq?TfL_F{@HCSR<3IH(Dd{^oA=;#Dz$UnU+VqTjGQIuLRzrI zPY+ diff --git a/data/DB_GameItem.json b/data/DB_GameItem.json index d9b867f..133fcf4 100644 --- a/data/DB_GameItem.json +++ b/data/DB_GameItem.json @@ -6723,7 +6723,7 @@ "Describe": "可联系客服兑换实物奖励", "Entity": 1, "Compound": { - "300008": 10 + "30008": 10 } }, { @@ -6762,7 +6762,7 @@ "Describe": "可联系客服兑换实物奖励", "Entity": 1, "Compound": { - "300009": 10 + "30009": 10 } }, { @@ -6801,7 +6801,7 @@ "Describe": "可联系客服兑换实物奖励", "Entity": 1, "Compound": { - "300010": 10 + "30010": 10 } }, { @@ -6840,7 +6840,7 @@ "Describe": "可联系客服兑换实物奖励", "Entity": 2, "Compound": { - "300011": 10 + "30011": 10 } }, { diff --git a/data/DB_PropExchange.dat b/data/DB_PropExchange.dat index 8f64d81123b961d917ed8dfba79fe2eea84d844e..7ad9b2f2d9089134370dce2a322fe7927c338c0f 100644 GIT binary patch literal 384 zcmd-w<6snElw#w!*2WB`uS4m}Q2Gj#z6zq1I5-yevI!h$vE|a^U;?YZ0hPZArEfv$ z+i2>;IUwevn+vlK-5jufpu52KBDoK2z7i+c9Sv(Av2ew5uz(!`GnkNpC>}yL7|6c^ Sb~ro7BA`dVFmo}`76Jfc!aOwq literal 384 zcmd-w<6snElw#w!-o^~3FGJ}oQ2HvAz6PR|I5-yevI!h$vE|a^U;?YZ0hPZArEfv$ z+i2>;IUweP%|WscrXSrttmXmrf!(LX33f-r+D9y0u^cR5hoCqVs1V%%n8#oqg;@-C ZC{X;k lO-|#~#Uj0glZQzVqL$SQV(5ZHa+?ow?`FXw+$+Gu3IOQXBKZIS delta 130 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�rXh1vmtY`w|{c*ENx6?dHNtGdQA>Z~tIZ0QoE>gU1rUBLZHhYR9wLw5tj%tIqS`nKDwv1tWYN#eEN-GxV8= z8+}z&$sV(0rM^1lQkm`7!_bz#zz(CK*`4td?GYz?`|!yaUFf^gi^z`rqdEs0b7ra5 z@Ut(yQIYeO$JTC^{ET96(@)fUJ4-0HJ+t4$2QwbHbnX+X5E=_S>ZH{Xkv1im+qFx0 zE@+jd(fuoXXo-&+t$TH$sLh4>eatx7){l0qkbF#;ujv_8yW$jP9lVJzVCW)E8!q|F z?{1!rZ*{~-y|IND#eVOH+RP1;N3k%)pusOq8_5GS zA!jgCE5)S~pt%|)ChPl16vi2W!m06jv~r-ic}@M-(xiU=e3I9-{Akg#84KFvv%M-p zPxYj!3|4Yn`F8Tdt{4?-!$iEMB9)g8C%Ufs1z)WaZSy-O)~#Mvu$PU#qk`~cZ+ugK z?m?DrFzanuPw9Y?Owv~RE3$Z{_!=kSnni8)a^HWgErnrmq_9zWqi^NWEvLK=b;n$E;l6x2 zM;~6F91OwhIh@)lDNMP^)LO@W=_fi3;~|!6?-C!i&Kd77iBsBWe%4d%gD4#f2dS(_ z@643GxM+Ll^S+lhv}Njq69b|rqNGROf~t0GZrIZ z_wCuwUhG~^YhV~vfV$4vK;ySE+-8iOV0O^*)RVpLiXr_cubK=36Ro%riX8O>Gdn0_ zU__GnySv?Myy&alpUs)(TusXpJ(W|+*mG}iudv2d<3H~$lo!qqA-9PPND%upK=d(6 zuatp*JbkSAskpDGf-7T1URnOVO(CX=Jf)>~Vf2g@7;Bk33kNKvH4@0YpZzVP?K=em zwSMZnx4)@{UDnckK)J8*<|nI4IsLpkw5tDcC`Q+8%~IJ~O@yT)Z?(fd7?o~UeUxy8 z)jDq^fA{K(9DJR7N3Fzi^XUub!8imu_nVi2XBI4s+gDpk2(K?Ew75=R)o%VY=WX{+ zE`L5Vv6{{gQB}L88`lUlPBZ$B2sC#6j}08x&H2aabPfaf_F$7Z6pn?DMy7T6A@M|> zRR)O_iaE1HR-P9x>YCRmV>x!SzmU7f?_KzZMZn%OYS~PW#+ua?^p*1lpb~WEyFY1@ z7#~X|OGWG&Kq>|X_{Wo>&T2h(0<`*d5+4Z&4yby|b3>HEze&tfUP zVzjxBSRqjl_AICO1bXUjPnYIpFrUA|*XJ?syDKGKGA|xAlk59b?d4OOuhbZA@5#(2gqAV7v)H#G$%caj$V&ZabPH)cZbSXp}@i&y*68_Zr9*a4Q5 z4=5_AAUCV6)M1<`V-i+sEEwTG!fmj z>?)d-ziV^H5Gp@FyQ@q4ri_6xhFE>fQJU-M8;PjA;$&Ei0q1`B%s$Ttyo%9C#%;~6)7vP zkJtDeb6u@ldOl`rJ9tU3_iT&d$@Z7vWM;}8OiSm1O4Izvl$NeI*?Ni~oXns&*8(PLTSHRF&iwoDbJqu~^nkzf>dkp=kGwB~Y zy79#eG}%^xOmu)8);Fwh(PZoYV_f&Y?yB)ayY@p1{l9gCIp}{D0Yh9QcucUvmaERv zrnp1Ez3&>`)1YPk6sVVOagu<$Mir=1J>bG!m;`lRLN=Zfg=Z;?jwvkr zUG1y~S&OfS780fjRJP-l92*%wg&jTiPMZQaR?nTIl*RKQqvK!crw^

u=Kncz?RD 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 F{{sROIH3Rl delta 55518 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ΞGx%ALDxhgfbZreWS$m3jVxp!NnK-M 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 diff --git a/xlsx/DB_GameItem.xlsx b/xlsx/DB_GameItem.xlsx index c069f7c00460e14f5352df5b4ab9c01a349a65a8..5d613b4079a35acbbbdb0c634788e7d4ebea2733 100644 GIT binary patch delta 20749 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 TDTL9C3c?dhfFAf9zTy7?BP4^2 delta 20520 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 LhMF1yU+Dh>D6JeH From 53f6aae1c6d444e00590377d831ecc40f52066cd Mon Sep 17 00:00:00 2001 From: tomas Date: Thu, 5 Dec 2024 13:42:21 +0800 Subject: [PATCH 37/41] add totalbet rec --- gamesrv/fortuneox/scenepolicy_fortuneox.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gamesrv/fortuneox/scenepolicy_fortuneox.go b/gamesrv/fortuneox/scenepolicy_fortuneox.go index 2868476..d6a4b33 100644 --- a/gamesrv/fortuneox/scenepolicy_fortuneox.go +++ b/gamesrv/fortuneox/scenepolicy_fortuneox.go @@ -518,7 +518,7 @@ func FortuneOxAndSaveLog(sceneEx *FortuneOxSceneData, playerEx *FortuneOxPlayerD json.Unmarshal(sp, &spinLock) respinStatus = spinLock.ReSpinStatus } - if respinStatus == 0 || respinStatus == 1 { + if respinStatus != 0 && respinStatus != 1 { data.TotalBet = 0 } From 6923ed95f175f9f204cfa766d651bff2f85b8336 Mon Sep 17 00:00:00 2001 From: sk <123456@qq.com> Date: Fri, 6 Dec 2024 09:59:10 +0800 Subject: [PATCH 38/41] =?UTF-8?q?=E7=B3=BB=E7=BB=9F=E8=B5=A0=E9=80=81?= =?UTF-8?q?=E8=AE=B0=E5=BD=95=E7=A0=B4=E4=BA=A7=E8=A1=A5=E5=8A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- worldsrv/welfmgr.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/worldsrv/welfmgr.go b/worldsrv/welfmgr.go index c14348e..772d847 100644 --- a/worldsrv/welfmgr.go +++ b/worldsrv/welfmgr.go @@ -113,6 +113,10 @@ func (this *WelfareMgr) GetReliefFund(p *Player, isVideo bool) { mq.Write(log) logger.Logger.Tracef("NewReliefFundLogEx WriteLog snid: %v Coin:%v", p.SnId, pack.Coin) } + if !p.IsRob { + mq.Write(model.GenerateSystemFreeGive(p.SnId, p.Name, p.Platform, p.Channel, + model.SystemFreeGive_GiveType_ReliefFund, model.SystemFreeGive_CoinType_Coin, coin)) + } } } logger.Logger.Tracef("GetReliefFund snid: %v pack: %v", p.SnId, pack) @@ -1114,7 +1118,7 @@ func (this *WelfareMgr) BlindBoxInfo(p *Player, bid int32) { if cyc == 1 || blindBox.Cycle == model.WelfareOpen { p.WelfData.BlindBoxId = 0 } - } // == 1代表当日循环 + } // == 1代表当日循环 if p.WelfData.BlindBoxId == 0 { // 未领取过发随机Date idx := bid From 4fc201977057516c16603eb674a0082c97b136a8 Mon Sep 17 00:00:00 2001 From: sk <123456@qq.com> Date: Fri, 6 Dec 2024 10:15:17 +0800 Subject: [PATCH 39/41] update statistics --- statistics/main.go | 6 +++--- statistics/task/main.go | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/statistics/main.go b/statistics/main.go index 23e6b9f..c738b31 100644 --- a/statistics/main.go +++ b/statistics/main.go @@ -68,9 +68,9 @@ func DoTickPlatform(ctx context.Context, wg *sync.WaitGroup, duration time.Durat } func main() { - VP = viperx.GetViper("config", "yaml") + VP = viperx.GetViper("config.yaml") // mongo - vp := viperx.GetViper("mongo", "yaml") + vp := viperx.GetViper("mongo.yaml") // mongo初始化 conf := &mongox.Config{} err := vp.Unmarshal(conf) @@ -81,7 +81,7 @@ func main() { defer mongox.Close() // mysql - vp = viperx.GetViper("mysql", "yaml") + vp = viperx.GetViper("mysql.yaml") myConf := &mysqlx.Config{} err = vp.Unmarshal(myConf) if err != nil { diff --git a/statistics/task/main.go b/statistics/task/main.go index a582273..bb555b8 100644 --- a/statistics/task/main.go +++ b/statistics/task/main.go @@ -35,9 +35,9 @@ func main() { logger.Logger.Flush() logger.Logger.Close() }() - VP = viperx.GetViper("config", "yaml") + VP = viperx.GetViper("config.yaml") // mongo - vp := viperx.GetViper("mongo", "yaml") + vp := viperx.GetViper("mongo.yaml") // mongo初始化 conf := &mongox.Config{} err := vp.Unmarshal(conf) @@ -48,7 +48,7 @@ func main() { defer mongox.Close() // mysql - vp = viperx.GetViper("mysql", "yaml") + vp = viperx.GetViper("mysql.yaml") myConf := &mysqlx.Config{} err = vp.Unmarshal(myConf) if err != nil { From 52b4994de3864fb96691bc23a08232065bf7adfb Mon Sep 17 00:00:00 2001 From: sk <123456@qq.com> Date: Sat, 7 Dec 2024 10:20:06 +0800 Subject: [PATCH 40/41] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E5=8D=81=E4=B8=89?= =?UTF-8?q?=E5=BC=A0=E5=85=A8=E5=9E=92=E6=89=93=E5=88=86=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gamesrv/thirteen/scene.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/gamesrv/thirteen/scene.go b/gamesrv/thirteen/scene.go index bd04c0f..2659e20 100644 --- a/gamesrv/thirteen/scene.go +++ b/gamesrv/thirteen/scene.go @@ -1100,10 +1100,10 @@ func (this *SceneEx) CountScore() { playerEx.winAllPlayers[k] += v // 全垒打分数 if playerEx.Pos == this.isCanAllHitPos { - this.seats[k].score[5] -= v - this.seats[k].winAllPlayers[playerEx.Pos] -= v - playerEx.score[5] += v - playerEx.winAllPlayers[k] += v + this.seats[k].score[5] -= v * 2 + this.seats[k].winAllPlayers[playerEx.Pos] -= v * 2 + playerEx.score[5] += v * 2 + playerEx.winAllPlayers[k] += v * 2 } } } From 690a5f1a08b4a88dafd74eb0e0f07a4f40eff95a Mon Sep 17 00:00:00 2001 From: sk <123456@qq.com> Date: Sat, 7 Dec 2024 17:09:19 +0800 Subject: [PATCH 41/41] =?UTF-8?q?=E5=8D=81=E4=B8=89=E5=BC=A0=E6=AF=94?= =?UTF-8?q?=E7=89=8C=E5=8C=85=E5=90=AB=E8=8A=B1=E8=89=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gamerule/thirteen/logic.go | 206 ++++++++++++++++++------------------- 1 file changed, 102 insertions(+), 104 deletions(-) diff --git a/gamerule/thirteen/logic.go b/gamerule/thirteen/logic.go index d6f922f..e3933b9 100644 --- a/gamerule/thirteen/logic.go +++ b/gamerule/thirteen/logic.go @@ -245,36 +245,35 @@ func (l *Logic) SortMidAndEnd(cards *Group) *Group { // 不可能 } else if n == 0 { // 逻辑点数相同 // 比花色,比三条就行了 - //n, index1, index2 := IndexCompareColorByLogic(c1, c2) - n = 0 + n, index1, index2 := IndexCompareColorByLogic(c1, c2) if n == 1 { // 花色交换,结束 - //if index1 >= 0 && index2 >= 0 { - // for k, v := range cards.Head { - // if v == r1[index1] { - // cards.Head[k] = -1 - // break - // } - // } - // for k, v := range cards.Mid { - // if v == r2[index2] { - // cards.Mid[k] = -1 - // break - // } - // } - // for k, v := range cards.Head { - // if v == -1 && r2[index2] >= 0 { - // cards.Head[k] = r2[index2] - // break - // } - // } - // for k, v := range cards.Mid { - // if v == -1 && r1[index1] >= 0 { - // cards.Mid[k] = r1[index1] - // break - // } - // } - //} + if index1 >= 0 && index2 >= 0 { + for k, v := range cards.Head { + if v == r1[index1] { + cards.Head[k] = -1 + break + } + } + for k, v := range cards.Mid { + if v == r2[index2] { + cards.Mid[k] = -1 + break + } + } + for k, v := range cards.Head { + if v == -1 && r2[index2] >= 0 { + cards.Head[k] = r2[index2] + break + } + } + for k, v := range cards.Mid { + if v == -1 && r1[index1] >= 0 { + cards.Mid[k] = r1[index1] + break + } + } + } } else if n == 0 { // 比癞子数 if l.LaiZiCount(r1) < l.LaiZiCount(r2) { @@ -381,13 +380,12 @@ func (l *Logic) SortMidAndEnd(cards *Group) *Group { } } else if n == 0 { // 点数相同 // 比花色 - //n, index1, index2 := IndexCompareColorByLogic(nHead[:], nMid[:]) - n = 0 + n, index1, index2 := IndexCompareColorByLogic(nHead[:], nMid[:]) if n == 1 { // 交换花色,结束 - //if index1 >= 0 && index2 >= 0 { - // cards.Head[index1], cards.Mid[index2] = cards.Mid[index2], cards.Head[index1] - //} + if index1 >= 0 && index2 >= 0 { + cards.Head[index1], cards.Mid[index2] = cards.Mid[index2], cards.Head[index1] + } } else if n == 0 { // 比癞子多少 if l.LaiZiCount(r1) < l.LaiZiCount(r2) { @@ -426,13 +424,13 @@ func (l *Logic) SortMidAndEnd(cards *Group) *Group { } } else if n == 0 { // 点数相同比花色 - //n, index1, index2 := IndexCompareColorByLogic(cards.Head[:], cards.Mid[:]) - //if n == 1 { - // // 交换最大花色的牌 - // if index1 >= 0 && index2 >= 0 { - // cards.Head[index1], cards.Mid[index2] = cards.Mid[index2], cards.Head[index1] - // } - //} + n, index1, index2 := IndexCompareColorByLogic(cards.Head[:], cards.Mid[:]) + if n == 1 { + // 交换最大花色的牌 + if index1 >= 0 && index2 >= 0 { + cards.Head[index1], cards.Mid[index2] = cards.Mid[index2], cards.Head[index1] + } + } } } } @@ -834,10 +832,10 @@ func (l *Logic) CompareHead(c, cs [3]int) int { return n } // 比花色 - //n = CompareColorByLogic(c1, c2) - //if n != 0 { - // return n - //} + n = CompareColorByLogic(c1, c2) + if n != 0 { + return n + } // 比癞子数 z1, z2 := l.LaiZiCount(c[:]), l.LaiZiCount(cs[:]) if z1 < z2 { @@ -869,10 +867,10 @@ func (l *Logic) CompareFive(c, cs [5]int) int { return n } // 比花色 - //n = CompareColorByLogic(c1, c2) - //if n != 0 { - // return n - //} + n = CompareColorByLogic(c1, c2) + if n != 0 { + return n + } case PokersTypeStraightFlush: _, c1 := FindMaxSameColorFlush(c[:], l.LaiZi) @@ -888,20 +886,20 @@ func (l *Logic) CompareFive(c, cs [5]int) int { } if ch1 && ch2 { // 比花色 - //n := CompareColorByLogic(c1, c2) - //if n != 0 { - // return n - //} + n := CompareColorByLogic(c1, c2) + if n != 0 { + return n + } } else if !ch1 && !ch2 { n := CompareLogic(c1, c2) if n != 0 { return n } // 比花色 - //n = CompareColorByLogic(c1, c2) - //if n != 0 { - // return n - //} + n = CompareColorByLogic(c1, c2) + if n != 0 { + return n + } } else { if ch1 { return -1 @@ -928,10 +926,10 @@ func (l *Logic) CompareFive(c, cs [5]int) int { return n } // 比花色 - //n = CompareColorByLogic(c1, c2) - //if n != 0 { - // return n - //} + n = CompareColorByLogic(c1, c2) + if n != 0 { + return n + } case PokersTypeFullHouse: _, c1 := FindMaxGourdCards(c[:], l.LaiZi) @@ -946,10 +944,10 @@ func (l *Logic) CompareFive(c, cs [5]int) int { return n } // 比花色 - //n = CompareColorByLogic(c1, c2) - //if n != 0 { - // return n - //} + n = CompareColorByLogic(c1, c2) + if n != 0 { + return n + } case PokersTypeFlush: _, c1 := FindMaxSameColors(c[:], l.LaiZi) @@ -960,10 +958,10 @@ func (l *Logic) CompareFive(c, cs [5]int) int { return n } // 比花色 - //n = CompareColorByLogic(c1, c2) - //if n != 0 { - // return n - //} + n = CompareColorByLogic(c1, c2) + if n != 0 { + return n + } case PokersTypeStraight: _, c1 := FindMaxFlush(c[:], l.LaiZi) @@ -979,20 +977,20 @@ func (l *Logic) CompareFive(c, cs [5]int) int { } if ch1 && ch2 { // 比花色 - //n := CompareColorByLogic(c1, c2) - //if n != 0 { - // return n - //} + n := CompareColorByLogic(c1, c2) + if n != 0 { + return n + } } else if !ch1 && !ch2 { n := CompareLogic(c1, c2) if n != 0 { return n } // 比花色 - //n = CompareColorByLogic(c1, c2) - //if n != 0 { - // return n - //} + n = CompareColorByLogic(c1, c2) + if n != 0 { + return n + } } else { if ch1 { return -1 @@ -1019,10 +1017,10 @@ func (l *Logic) CompareFive(c, cs [5]int) int { return n } // 比花色 - //n = CompareColorByLogic(c1, c2) - //if n != 0 { - // return n - //} + n = CompareColorByLogic(c1, c2) + if n != 0 { + return n + } case PokersTypeTwoPairs: r1, c1 := FindMaxPairs(c[:], l.LaiZi) @@ -1053,10 +1051,10 @@ func (l *Logic) CompareFive(c, cs [5]int) int { return n } // 比花色 - //n = CompareColorByLogic(c1, c2) - //if n != 0 { - // return n - //} + n = CompareColorByLogic(c1, c2) + if n != 0 { + return n + } case PokersTypePair: r1, c1 := FindMaxPairs(c[:], l.LaiZi) @@ -1077,10 +1075,10 @@ func (l *Logic) CompareFive(c, cs [5]int) int { return n } // 比花色 - //n = CompareColorByLogic(c1, c2) - //if n != 0 { - // return n - //} + n = CompareColorByLogic(c1, c2) + if n != 0 { + return n + } case PokersTypeOne: // 乌龙不会有癞子 @@ -1090,10 +1088,10 @@ func (l *Logic) CompareFive(c, cs [5]int) int { return n } // 比花色 - //n = CompareColorByLogic(c[:], cs[:]) - //if n != 0 { - // return n - //} + n = CompareColorByLogic(c[:], cs[:]) + if n != 0 { + return n + } return 0 } @@ -1136,10 +1134,10 @@ func (l *Logic) IsDP(head [3]int, mid, end [5]int) bool { return n == 1 } // 比花色 - //n = CompareColorByLogic(c1, changeMid) - //if n != 0 { - // return n == 1 - //} + n = CompareColorByLogic(c1, changeMid) + if n != 0 { + return n == 1 + } // 比癞子数 z1, z2 := l.LaiZiCount(r1), l.LaiZiCount(r2) if z1 < z2 { @@ -1164,10 +1162,10 @@ func (l *Logic) IsDP(head [3]int, mid, end [5]int) bool { return n == 1 } // 比花色 - //n = CompareColorByLogic(c1, changeMid) - //if n != 0 { - // return n == 1 - //} + n = CompareColorByLogic(c1, changeMid) + if n != 0 { + return n == 1 + } // 比癞子数 z1, z2 := l.LaiZiCount(r1), l.LaiZiCount(r2) if z1 < z2 { @@ -1184,10 +1182,10 @@ func (l *Logic) IsDP(head [3]int, mid, end [5]int) bool { return n == 1 } // 比花色 - //n = CompareColorByLogic(head[:], mid[:]) - //if n != 0 { - // return n == 1 - //} + n = CompareColorByLogic(head[:], mid[:]) + if n != 0 { + return n == 1 + } } }