123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411 |
- package player
- import (
- "context"
- "encoding/json"
- "fmt"
- "github.com/aws/aws-sdk-go/aws"
- "github.com/aws/aws-sdk-go/aws/credentials"
- "github.com/aws/aws-sdk-go/aws/session"
- "github.com/aws/aws-sdk-go/service/s3/s3manager"
- jsoniter "github.com/json-iterator/go"
- mhayaString "github.com/mhaya/extend/string"
- mhayaTime "github.com/mhaya/extend/time"
- "github.com/mhaya/game/game_cluster/internal/code"
- "github.com/mhaya/game/game_cluster/internal/constant"
- "github.com/mhaya/game/game_cluster/internal/data"
- "github.com/mhaya/game/game_cluster/internal/event"
- "github.com/mhaya/game/game_cluster/internal/mdb"
- "github.com/mhaya/game/game_cluster/internal/mdb/models"
- "github.com/mhaya/game/game_cluster/internal/param"
- "github.com/mhaya/game/game_cluster/internal/token"
- "github.com/mhaya/game/game_cluster/nodes/game/module/online"
- clog "github.com/mhaya/logger"
- "github.com/mhaya/net/parser/pomelo"
- "go.mongodb.org/mongo-driver/bson"
- "io"
- "net/http"
- "net/url"
- "time"
- )
- type (
- // actorPlayer 每位登录的玩家对应一个子actor
- actorPlayer struct {
- pomelo.ActorBase
- isOnline bool // 玩家是否在线
- playerId string
- uid int64
- index int
- dirty bool
- exitTime time.Duration
- Player *models.Player
- Account *models.Account
- }
- )
- func (p *actorPlayer) OnInit() {
- p.exitTime = time.Minute * 30
- clog.Debugf("[actorPlayer] path = %s init!", p.PathString())
- // 注册 session关闭的remote函数(网关触发连接断开后,会调用RPC发送该消息)
- p.Remote().Register("sessionClose", p.sessionClose)
- p.Remote().Register("login", p.login) // 注册 查看角色
- p.Remote().Register("start", p.start) // 主页
- p.Remote().Register("guide", p.guide) // 主页关闭信息
- p.Remote().Register("roll", p.roll) // roll
- p.Remote().Register("lottery", p.lottery) // 转盘
- p.Remote().Register("signIn", p.signIn) // 签到
- p.Remote().Register("rank", p.rank) // 排行榜
- p.Remote().Register("invite", p.invite) // 邀请
- p.Remote().Register("inviteRecord", p.inviteRecord) // 邀请累计信息
- p.Remote().Register("share", p.share) // 分享
- p.Remote().Register("claim", p.claim) // 领取奖励
- p.Remote().Register("cashOut", p.cashOut) //提现
- p.Remote().Register("jump", p.jump) // 成就1相关的跳转服务
- p.Remote().Register("savex", p.savex) // 更新推特
- p.Remote().Register("savetonwall", p.savetonwall) // 更新钱包
- p.Timer().Add(10*time.Second, p.refreshRoll)
- p.Timer().Add(1*time.Second, p.SetRewardToDB)
- p.Timer().Add(1*time.Minute, p.setRedis)
- p.Timer().Add(1*time.Second, p.setDb)
- p.Timer().Add(30*time.Second, p.setInviteReward)
- p.Timer().Add(1*time.Second, p.addRoll)
- p.Timer().Add(10*time.Second, p.sessionClose)
- //p.Timer().Add(30*time.Second, p.getAndUpdateAvatar) //排行榜头像
- }
- func (p *actorPlayer) addRoll() {
- if p.isOnline {
- if p.Player.Item[models.ItemRoll].Num < 10 {
- p.Player.Item[models.ItemRoll].Num += 100
- }
- if p.Player.Item[models.ItemDrawsNumber].Num < 10 {
- p.Player.Item[models.ItemDrawsNumber].Num += 100
- }
- p.dirty = true
- }
- }
- func (p *actorPlayer) OnStop() {
- clog.Debugf("[actorPlayer] path = %s exit!", p.PathString())
- }
- func (p *actorPlayer) setInviteReward() {
- if p.isOnline {
- p.Player.SetInviteReward()
- }
- }
- func (p *actorPlayer) setRedis() {
- if p.isOnline {
- var playerBase = param.PlayerBase{
- UserName: p.Player.UserName,
- NickName: p.Player.NickName,
- UserNameMaybe: p.Player.UserNameMaybe,
- IsLeader: p.Player.IsLeader,
- Avatar: p.Player.Avatar,
- OpenId: p.Player.OpenId,
- }
- d, _ := jsoniter.Marshal(&playerBase)
- mdb.RDB.Set(context.Background(), models.GetPlayBaseKey(p.Player.UserName), d, 30*24*time.Hour)
- }
- }
- func (p *actorPlayer) SetRewardToDB() {
- if p.Player != nil {
- for k, r := range p.Player.PlayerReward {
- _, err := mdb.MDB.Collection(constant.CNamePlayerReward).InsertOne(context.Background(), r)
- if err != nil {
- clog.Errorf("[actorPlayer] set invite to db error: %v", err)
- }
- delete(p.Player.PlayerReward, k)
- }
- }
- }
- func (p *actorPlayer) setDb() {
- if p.isOnline && p.dirty {
- ret, err := mdb.MDB.Collection(constant.CNamePlayer).UpdateOne(context.Background(), bson.M{"userName": p.Player.UserName}, bson.M{"$set": p.Player})
- if err != nil {
- clog.Debugf("[actorPlayer] setDb ret=%v, err = %s exit!", ret, err)
- }
- p.dirty = false
- }
- }
- // 获取和更新头像
- func (p *actorPlayer) getAndUpdateAvatar() {
- if p.isOnline {
- openid, _ := mhayaString.ToInt64(p.Player.OpenId)
- proxyURL, err := url.Parse("http://127.0.0.1:22307")
- if err != nil {
- clog.Debugf("Failed to parse proxy URL: %v", err.Error())
- return
- }
- // 创建代理配置
- proxy := http.ProxyURL(proxyURL)
- // 创建自定义的 Transport
- tr := &http.Transport{
- Proxy: proxy,
- TLSHandshakeTimeout: 5 * time.Second,
- }
- // 使用自定义 Transport 创建 HTTP 客户端
- client := &http.Client{
- Transport: tr,
- Timeout: 10 * time.Second, // 设置超时时间
- }
- sdkConfig := data.SdkConfig.Get(3).Params
- url := fmt.Sprintf("https://api.telegram.org/bot%s/getUserProfilePhotos?user_id=%d", sdkConfig.BotToken, openid)
- // 发起 HTTP 请求
- req, err := http.NewRequestWithContext(context.Background(), "GET", url, nil)
- if err != nil {
- clog.Error("Failed to create request: %v", err)
- return
- }
- resp, err := client.Do(req)
- if err != nil {
- clog.Error("Failed to send request: %v", err)
- return
- }
- defer resp.Body.Close()
- body, err := io.ReadAll(resp.Body)
- if err != nil {
- clog.Error("Error reading body: %v", err)
- return
- }
- var result struct {
- Ok bool `json:"ok"`
- Result struct {
- Photos [][]struct {
- FileID string `json:"file_id"`
- } `json:"photos"`
- } `json:"result"`
- }
- err = json.Unmarshal(body, &result)
- if err != nil {
- clog.Error("Error unmarshalling JSON: %v", err)
- return
- }
- if !result.Ok {
- clog.Error("Error: %s", string(body))
- return
- }
- if len(result.Result.Photos) == 0 {
- clog.Error("No photos found for user %d", openid)
- return
- }
- if len(result.Result.Photos) > 0 {
- // 获取第一张照片的最大尺寸
- photo := result.Result.Photos[0][len(result.Result.Photos[0])-1]
- //根据数据库记录判断是否需要更新图片库
- if photo.FileID != p.Player.Avatar {
- if p.uploadPhotoToS3(client, sdkConfig.BotToken, photo.FileID, openid) == true {
- p.Player.Avatar = photo.FileID
- }
- }
- }
- }
- }
- func (p *actorPlayer) uploadPhotoToS3(client *http.Client, botToken, fileId string, openid int64) bool {
- s3 := data.SdkConfig.Get(3).S3
- url := fmt.Sprintf("https://api.telegram.org/bot%s/getFile?file_id=%s", botToken, fileId)
- // 发起 HTTP 请求
- req, err := http.NewRequestWithContext(context.Background(), "GET", url, nil)
- if err != nil {
- clog.Error("Failed to create request: %v", err)
- return false
- }
- resp, err := client.Do(req)
- if err != nil {
- clog.Error("Failed to send request: %v", err)
- return false
- }
- defer resp.Body.Close()
- body, err := io.ReadAll(resp.Body)
- if err != nil {
- clog.Error("Error reading body: %v", err)
- return false
- }
- var fileInfo struct {
- Ok bool `json:"ok"`
- Result struct {
- FilePath string `json:"file_path"`
- } `json:"result"`
- }
- err = json.Unmarshal(body, &fileInfo)
- if err != nil {
- clog.Error("Error unmarshalling JSON: %v", err)
- return false
- }
- if !fileInfo.Ok {
- clog.Error("Error: %s", string(body))
- return false
- }
- downloadUrl := fmt.Sprintf("https://api.telegram.org/file/bot%s/%s", botToken, fileInfo.Result.FilePath)
- resp, err = client.Get(downloadUrl)
- if err != nil {
- clog.Error("Error: %v", err)
- return false
- }
- defer resp.Body.Close()
- // 配置 AWS 凭证
- sess, err := session.NewSession(&aws.Config{
- Credentials: credentials.NewStaticCredentials(
- s3.AccessKey,
- s3.SecretKey,
- "",
- ),
- Region: aws.String(s3.Region), // 替换为你的 S3 区域
- })
- uploader := s3manager.NewUploader(sess)
- // 上传文件到 S3
- _, err = uploader.Upload(&s3manager.UploadInput{
- Bucket: aws.String(s3.BucketName), // S3 存储桶名称
- Key: aws.String(fmt.Sprintf("%d.jpg", openid)), //当前目录存储文件
- Body: resp.Body,
- ACL: aws.String("private"), // 可以根据需要设置 ACL
- })
- if err != nil {
- clog.Error("Error uploading file: %v", err)
- return false
- }
- return true
- }
- func (p *actorPlayer) refreshRoll() {
- if p.isOnline {
- if p.Player.RefreshRoll() {
- p.dirty = true
- }
- }
- }
- // sessionClose 接收角色session关闭处理
- func (p *actorPlayer) sessionClose() {
- deadline := time.Now().Add(-p.exitTime).Unix()
- if p.LastAt() < deadline {
- online.UnBindPlayer(p.uid)
- p.isOnline = false
- p.Exit()
- logoutEvent := event.NewPlayerLogout(p.ActorID(), p.playerId)
- p.PostEvent(&logoutEvent)
- }
- }
- func (p *actorPlayer) Init(req *token.Token) {
- clog.Debugf("[actorPlayer] init token = %s", req)
- var account models.Account
- mdb.MDB.Collection(constant.CNameAccount).FindOne(context.Background(), bson.M{"userName": req.PlayerID}).Decode(&account)
- p.Account = &account
- var player models.Player
- mdb.MDB.Collection(constant.CNamePlayer).FindOne(context.Background(), bson.M{"userName": req.PlayerID}).Decode(&player)
- if player.OpenId != "" {
- p.Player = &player
- } else {
- user := models.NewPlayer(req)
- mdb.MDB.Collection(constant.CNamePlayer).InsertOne(context.Background(), user)
- p.Player = user
- }
- if len(p.Player.PlayerReward) == 0 {
- p.Player.PlayerReward = make(map[int]*models.PlayerRewardBase)
- }
- }
- func (p *actorPlayer) InitBase(uid string) int32 {
- clog.Debugf("[actorPlayer] InitBase uid = %s", uid)
- var player models.Player
- mdb.MDB.Collection(constant.CNamePlayer).FindOne(context.Background(), bson.M{"userName": uid}).Decode(&player)
- if player.OpenId != "" {
- p.Player = &player
- if len(p.Player.PlayerReward) == 0 {
- p.Player.PlayerReward = make(map[int]*models.PlayerRewardBase)
- }
- return code.OK
- } else {
- return code.Error
- }
- }
- func (p *actorPlayer) login(req *token.Token) (*models.Player, int32) {
- if !p.isOnline {
- p.Init(req)
- }
- p.isOnline = true
- p.dirty = true
- p.playerId = req.PlayerID
- uid, _ := mhayaString.ToInt64(req.OpenID)
- p.uid = uid
- p.Player.Init()
- p.Player.NickName = req.Nickname
- if !mhayaTime.CreateFromTimestamp(p.Player.LoginTime).IsToday() {
- p.Player.Successions += 1
- if mhayaTime.CreateFromTimestamp(p.Player.LoginTime).DiffInDays(mhayaTime.Now()) > 1 {
- p.Player.MaxSuccessions = 1
- } else {
- p.Player.MaxSuccessions += 1
- }
- }
- p.Player.LoginTime = mhayaTime.Now().Unix()
- //刷新roll
- p.Player.RefreshRoll()
- p.Player.InitDaily()
- p.Player.InitWeekly()
- p.Player.InitAchieveTask()
- // 保存进入游戏的玩家对应的agentPath
- online.BindPlayer(p.Player.UserName, p.uid, req.TargetPath)
- // 角色登录事件
- loginEvent := event.NewPlayerLogin(p.ActorID(), req)
- p.PostEvent(&loginEvent)
- return p.Player, code.OK
- }
|