service.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483
  1. package storage
  2. import (
  3. actorRemote "f1-game/internal/actor_remote"
  4. capp "f1-game/internal/cherry_app"
  5. "f1-game/internal/code"
  6. "f1-game/internal/data"
  7. "f1-game/internal/enum"
  8. "f1-game/internal/event"
  9. facade "f1-game/internal/facade"
  10. nameRoute "f1-game/internal/name/route"
  11. "f1-game/internal/pb"
  12. "f1-game/internal/sessions"
  13. "f1-game/internal/types"
  14. assetOrigin "f1-game/nodes/game/player/asset/origin"
  15. mapCall "f1-game/nodes/map/internal/call"
  16. "f1-game/nodes/map/internal/db"
  17. clog "github.com/cherry-game/cherry/logger"
  18. cproto "github.com/cherry-game/cherry/net/proto"
  19. )
  20. var (
  21. srv = newService()
  22. )
  23. func newService() *service {
  24. instance := &service{}
  25. instance.load()
  26. return instance
  27. }
  28. func Service() *service {
  29. return srv
  30. }
  31. type service struct {
  32. facade.PlayerServiceBase[*db.MapPlayerTable]
  33. }
  34. func (p *service) load() {
  35. }
  36. func (p *service) OnLogin(mapPlayerTable *db.MapPlayerTable, session *cproto.Session) {
  37. if session.Contains(sessions.IsNewPlayer) {
  38. clog.Infof("map storage init: playerID = %d", mapPlayerTable.PlayerID)
  39. // 初始化资源
  40. p.AssetAdds(mapPlayerTable.PlayerID, data.Const.PlayerInitCurrencies, assetOrigin.CreatePlayer, false)
  41. }
  42. }
  43. // func (p *service) OnLogined(mapPlayerTable *db.MapPlayerTable, session *cproto.Session) {
  44. // }
  45. // func (p *service) OnLogout(mapPlayerTable *db.MapPlayerTable) {
  46. // }
  47. // func (p *service) OnReset(mapPlayerTable *db.MapPlayerTable, time *ctime.CherryTime, byLogin bool) {
  48. // }
  49. func (p *service) Push(mapPlayerTable *db.MapPlayerTable, session *cproto.Session) {
  50. mapPlayerStorageTable := db.GetMapPlayerStorageTable(mapPlayerTable.PlayerID)
  51. proto := mapPlayerStorageTable.Storage.ToProto()
  52. sessions.PushWithSession(session, nameRoute.PushMapPlayer_StorageList, proto)
  53. }
  54. // ChangePush 仓库变更推送
  55. func (p *service) ChangePush(playerID int64, idList ...int32) {
  56. if len(idList) < 1 {
  57. return
  58. }
  59. var (
  60. mapPlayerStorageTable = db.GetMapPlayerStorageTable(playerID)
  61. rsp = &pb.ItemList{
  62. Currencies: map[int32]*pb.Currency{},
  63. }
  64. )
  65. for _, id := range idList {
  66. // 只推送地图里面的资源
  67. if enum.IsMapCurrency(id) {
  68. entity := mapPlayerStorageTable.Storage.CurrencyMap.GetEntity(id)
  69. proto := entity.ToProto()
  70. rsp.Currencies[entity.ID] = &proto
  71. }
  72. }
  73. if len(rsp.Currencies) < 1 {
  74. return
  75. }
  76. sessions.PushPlayer(playerID, nameRoute.PushMapPlayer_StoragChange, rsp)
  77. }
  78. func (p *service) Contain(playerID int64, id int32) int32 {
  79. mapPlayerStorageTable := db.GetMapPlayerStorageTable(playerID)
  80. if _, found := data.Item.GetByID(id); !found {
  81. return code.ConfigNotFound_Item
  82. }
  83. if mapPlayerStorageTable.Storage.CurrencyMap.Get(id) < 1 {
  84. return code.ItemNotEnough
  85. }
  86. return code.OK
  87. }
  88. func (p *service) isEnough(playerID int64, id int32, num int64) bool {
  89. mapPlayerStorageTable := db.GetMapPlayerStorageTable(playerID)
  90. availableNum := mapPlayerStorageTable.Storage.CurrencyMap.Get(id)
  91. if availableNum < 1 || availableNum < num {
  92. return false
  93. }
  94. return true
  95. }
  96. func (p *service) add(playerID int64, id int32, num int64, origin assetOrigin.Origin, save, push bool) (types.Asset, int32) {
  97. mapPlayerStorageTable := db.GetMapPlayerStorageTable(playerID)
  98. row, found := data.Item.GetByID(id)
  99. if !found {
  100. return types.NoneAsset, code.ConfigNotFound_Item
  101. }
  102. if row.ParseType != enum.AssetType_Currency {
  103. return types.NoneAsset, code.CurrencyTypeError
  104. }
  105. if !enum.IsMapCurrency(id) {
  106. return types.NoneAsset, code.CurrencyTypeError
  107. }
  108. if num < 1 {
  109. return types.NoneAsset, code.ItemNumError
  110. }
  111. _, ok := mapPlayerStorageTable.Storage.CurrencyMap.Increase(id, num)
  112. if !ok {
  113. return types.NoneAsset, code.ItemNotEnough
  114. }
  115. if save {
  116. mapPlayerStorageTable.Save2Queue()
  117. }
  118. if push {
  119. p.ChangePush(playerID, id)
  120. }
  121. returnAsset := types.Asset{
  122. ID: id,
  123. Num: num,
  124. }
  125. return returnAsset, code.OK
  126. }
  127. func (p *service) sub(playerID int64, id int32, num int64, origin assetOrigin.Origin, save, push bool) int32 {
  128. mapPlayerStorageTable := db.GetMapPlayerStorageTable(playerID)
  129. if num < 1 {
  130. return code.ItemNumError
  131. }
  132. _, found := data.Item.GetByID(id)
  133. if !found {
  134. return code.ConfigNotFound_Item
  135. }
  136. // 优先扣除绑定资源,再扣除非绑定资源
  137. changeAssets, ok := mapPlayerStorageTable.Storage.CurrencyMap.Decrease(id, num)
  138. if !ok {
  139. return code.ItemNotEnough
  140. }
  141. if save {
  142. mapPlayerStorageTable.Save2Queue()
  143. }
  144. var changeIDList []int32
  145. for _, asset := range changeAssets {
  146. changeIDList = append(changeIDList, asset.ID)
  147. }
  148. if push {
  149. p.ChangePush(playerID, changeIDList...)
  150. }
  151. return code.OK
  152. }
  153. // CheckAutoAdd 检查每几秒资源发放情况
  154. func (p *service) CheckAutoAdd(playerTable *db.MapPlayerTable, nowSecond int64, isOnline bool) {
  155. var (
  156. playerStorageTable = db.GetMapPlayerStorageTable(playerTable.PlayerID)
  157. itemAddSecond = data.Const.ItemAddSecond
  158. changePushIDList []int32
  159. save bool
  160. )
  161. for _, itemID := range enum.ItemMaxNumList {
  162. // 产出的量
  163. yield := p.GetMapCurrencyYield(playerTable, itemID)
  164. if yield < 1 {
  165. continue
  166. }
  167. // 只有能产出的时候才初始化 UpdateTime
  168. if playerStorageTable.Storage.CurrencyMap.CheckInitUpdateTime(itemID, nowSecond) {
  169. save = true
  170. }
  171. if !playerStorageTable.Storage.CurrencyMap.CheckAutoAdd(itemID, nowSecond, yield, itemAddSecond) {
  172. continue
  173. }
  174. save = true
  175. changePushIDList = append(changePushIDList, itemID)
  176. if playerStorageTable.Storage.CurrencyMap.IsFull(itemID) {
  177. actorRemote.GamePlayer.GamePlayerCallSystemMsg(playerTable.GameNodeID, playerTable.PlayerID, enum.ChatMsgType_resourceMax, nil, nil, itemID)
  178. }
  179. }
  180. if save {
  181. playerStorageTable.Save2Queue()
  182. }
  183. if len(changePushIDList) > 0 && isOnline {
  184. p.ChangePush(playerTable.PlayerID, changePushIDList...)
  185. }
  186. }
  187. // 获取资源总产量
  188. func (p *service) GetMapCurrencyYield(mapPlayerTable *db.MapPlayerTable, itemIDs ...int32) int64 {
  189. if len(itemIDs) <= 0 {
  190. return 0
  191. }
  192. var (
  193. mapResYields = mapPlayerTable.GetAllYield()
  194. totalYield = int64(0)
  195. )
  196. for _, itemID := range itemIDs {
  197. // 绑定资源
  198. if attrID, ok := enum.MapItemAttrs[itemID]; ok {
  199. totalYield += p.calcAssetOutputFinalAttr(mapPlayerTable, attrID)
  200. }
  201. // 非绑定资源
  202. if _, ok := enum.UnBindingResourceMap[itemID]; ok {
  203. totalYield += mapResYields.GetValue(itemID)
  204. }
  205. }
  206. return totalYield
  207. }
  208. func (p *service) IsEnough(playerID int64, id int32, num int64) bool {
  209. if !enum.IsMapCurrency(id) {
  210. return true
  211. }
  212. if !p.isEnough(playerID, id, num) {
  213. return false
  214. }
  215. return true
  216. }
  217. func (p *service) IsAllEnough(playerID int64, assets types.Assets) bool {
  218. for _, asset := range assets {
  219. if !enum.IsMapCurrency(asset.ID) {
  220. continue
  221. }
  222. if !p.isEnough(playerID, asset.ID, asset.Num) {
  223. return false
  224. }
  225. }
  226. return true
  227. }
  228. // AssetAdds 增加多个资源,地图和游戏节点分别增加
  229. func (p *service) AssetAdds(playerID int64, assets types.Assets, ao assetOrigin.Origin, isPush ...bool) (types.Assets, int32) {
  230. var (
  231. mapPlayerTable = db.GetMapPlayerTable(playerID)
  232. mapAssets = types.Assets{}
  233. mapLeagueAssets = types.Assets{}
  234. gameAssets = types.Assets{}
  235. retAssets = types.Assets{}
  236. )
  237. // 检查玩家表是否存在
  238. if mapPlayerTable == nil {
  239. return retAssets, code.PlayerNotFound
  240. }
  241. if len(assets) == 0 {
  242. return retAssets, code.IllegalArgument
  243. }
  244. // TODO 默认推送
  245. push := true
  246. if len(isPush) > 0 {
  247. push = isPush[0]
  248. }
  249. // 资源拆解分组,地图的资源和游戏的资源分开处理
  250. for _, asset := range assets {
  251. if enum.IsLeagueCurrency(asset.ID) {
  252. mapLeagueAssets.AddAsset(asset)
  253. } else if enum.IsMapCurrency(asset.ID) {
  254. mapAssets.AddAsset(asset)
  255. } else {
  256. gameAssets.AddAsset(asset)
  257. }
  258. }
  259. if mapAssets.Len() > 0 {
  260. for _, asset := range mapAssets {
  261. retAsset, errCode := p.add(playerID, asset.ID, asset.Num, ao, true, push)
  262. if code.IsFail(errCode) {
  263. return retAssets, errCode
  264. }
  265. retAssets.AddAsset(&retAsset)
  266. }
  267. // 发送获得奖励的系统消息
  268. actorRemote.GamePlayer.GamePlayerCallSystemMsg(mapPlayerTable.GameNodeID, playerID, enum.ChatMsgType_reward, mapAssets, nil)
  269. capp.PostEvent(event.NewItemAdd(playerID, mapAssets, ao))
  270. }
  271. if mapLeagueAssets.Len() > 0 {
  272. mapCall.League.MapLeagueAddAssets(playerID, mapPlayerTable.LeagueID, mapLeagueAssets)
  273. }
  274. if gameAssets.Len() > 0 {
  275. retAssetsProto, errCode := actorRemote.GamePlayer.AssetAdd(mapPlayerTable.GameNodeID, playerID, gameAssets, ao)
  276. if code.IsFail(errCode) {
  277. return retAssets, errCode
  278. }
  279. for _, asset := range retAssetsProto.List {
  280. retAsset := types.Asset{
  281. ID: asset.Id,
  282. Num: asset.Num,
  283. GUID: asset.Guid,
  284. }
  285. retAssets.AddAsset(&retAsset)
  286. }
  287. }
  288. return retAssets, code.OK
  289. }
  290. // AssetAddOne 单个资源增加,地图和游戏节点分别增加
  291. func (p *service) AssetAddOne(playerID int64, id int32, num int64, origin assetOrigin.Origin, isPush ...bool) (types.Assets, int32) {
  292. assets := types.Assets{
  293. {
  294. ID: id,
  295. Num: num,
  296. },
  297. }
  298. return p.AssetAdds(playerID, assets, origin, isPush...)
  299. }
  300. // AssetSubs 扣除多个资源,地图和游戏节点分别扣除
  301. func (p *service) AssetSubs(playerID int64, assets types.Assets, origin assetOrigin.Origin, isPush ...bool) (types.Assets, int32) {
  302. var (
  303. mapAssets = types.Assets{}
  304. gameAssets = types.Assets{}
  305. retAssets = types.Assets{}
  306. )
  307. if len(assets) == 0 {
  308. return nil, code.IllegalArgument
  309. }
  310. // TODO 默认推送
  311. push := true
  312. if len(isPush) > 0 {
  313. push = isPush[0]
  314. }
  315. for _, asset := range assets {
  316. // 不支持联盟货币消耗
  317. if enum.IsLeagueCurrency(asset.ID) {
  318. clog.Warnf("AssetSubs league currency not support, playerID: %d, asset: %+v", playerID, asset)
  319. return nil, code.LeagueCurrencyNotSupport
  320. }
  321. if enum.IsMapCurrency(asset.ID) {
  322. mapAssets.AddAsset(asset)
  323. } else {
  324. gameAssets.AddAsset(asset)
  325. }
  326. }
  327. // 先检查地图这边的资源是否足够
  328. if !p.IsAllEnough(playerID, mapAssets) {
  329. return nil, code.CurrencyNotEnough
  330. }
  331. if len(gameAssets) > 0 {
  332. mapPlayerTable := db.GetMapPlayerTable(playerID)
  333. // 检查玩家表是否存在
  334. if mapPlayerTable == nil {
  335. return retAssets, code.PlayerNotFound
  336. }
  337. // 发送到游戏节点扣除游戏资源
  338. retAssetsProto, errCode := actorRemote.GamePlayer.AssetSub(mapPlayerTable.GameNodeID, playerID, gameAssets, origin)
  339. if code.IsFail(errCode) {
  340. return nil, errCode
  341. }
  342. for _, asset := range retAssetsProto.List {
  343. retAsset := types.Asset{
  344. ID: asset.Id,
  345. Num: asset.Num,
  346. GUID: asset.Guid,
  347. }
  348. retAssets.AddAsset(&retAsset)
  349. }
  350. }
  351. for _, asset := range mapAssets {
  352. errCode := p.sub(playerID, asset.ID, asset.Num, origin, true, push)
  353. if code.IsFail(errCode) {
  354. return nil, errCode
  355. }
  356. retAssets.AddAsset(asset)
  357. }
  358. return retAssets, code.OK
  359. }
  360. // AssetSubOne 单个资源扣除,地图和游戏节点分别扣除
  361. func (p *service) AssetSubOne(playerID int64, id int32, num int64, origin assetOrigin.Origin, isPush ...bool) (types.Assets, int32) {
  362. assets := types.Assets{
  363. {
  364. ID: id,
  365. Num: num,
  366. },
  367. }
  368. return p.AssetSubs(playerID, assets, origin, isPush...)
  369. }
  370. // Get 获取资源数量
  371. func (p *service) Get(playerID int64, id int32) int64 {
  372. if !enum.IsMapCurrency(id) {
  373. return 0
  374. }
  375. mapPlayerStorageTable := db.GetMapPlayerStorageTable(playerID)
  376. return mapPlayerStorageTable.Storage.CurrencyMap.Get(id)
  377. }
  378. // 计算各个模块给资源产出的加成
  379. // 1,城建
  380. // 2,VIP
  381. func (p *service) calcAssetOutputFinalAttr(mapPlayerTable *db.MapPlayerTable, attrID int32) int64 {
  382. facilityValue := mapPlayerTable.Facilities.Attrs.GetI64(attrID)
  383. vipValue := int64(0)
  384. if !mapPlayerTable.Vip.IsExpired {
  385. vipValue = mapPlayerTable.Vip.Attrs.GetI64(attrID)
  386. }
  387. attrValue := facilityValue + vipValue
  388. return attrValue
  389. }