凌晨事故多发点

每日商店

在大世界中与流浪商人对话,点击对应的按钮即可进入商城购买道具或进入交易界面出售道具。购买的道具要求每天凌晨刷新,每个玩家有五次手动刷新。

需求分析

从需求描述可以分析出,需要三个接口:

  1. 获取商城:需要返回的结构体,主要有商城的道具,倒计时,刷新次数。
  2. 刷新商城:需要返回的结构体,主要有商城的道具,倒计时,刷新次数。
  3. 购买商城:需要返回的结构体,主要有购买的道具是否成功。
  4. 出售商城:需要返回的结构体,主要有出售的道具是否成功,获得得金币,已经放入的背包位置。

设计数据库

  1. 背包数据库:
type BagData struct {
	Id     int     `json:"id"` //背包主键
	Uid     int64   `json:"uuid" bson:"uuid"`     //用户ID
	ItemId   string  `json:"iname" bson:"iname"`   //物品名
	Num        int     `json:"num" bson:"num"`     //数量
	Options    string  `json:"options" bson:"options"`
	Durability float32 `json:"durability" bson:"durability"` //耐久度
	F32        float32 `json:"f32" bson:"f32"`               //float32传值用
	TimeStamp  int64   `json:"tm" bson:"tm"`                 //时间戳
	Param      int     `json:"param" bson:"param"`           //暂留字段
}
  1. 商城数据库:
type MallItemDetails struct {
	Id     int     `json:"id"` //背包主键
	Uid     int64   `json:"uuid" bson:"uuid"`     //用户ID
	ItemId   string  `json:"iname" bson:"iname"`   //物品名
	Num      int    `json:"num"`
	Oil      int    `json:"oil"`				//金币
	IsBuy    bool   `json:"isBuy" bson:"isBuy"` //是否购买
	RefreshName	int `json:"rn"`	//刷新次数
	RefreshTime		int64	`json:"rt"`	//刷新时间
}

功能逻辑分析

  1. 获取商城

    • 客户端请求获取商城的接口。
    • 查询数据库找到用户商城信息。
    • 如果没有则执行刷新物品信息存入数据库,同时返回给客户端。
    • 如果有则执行判断是否今天有刷新,如果有刷新则返回给客户端,如果没有刷新则执行刷新物品信息存入数据库,同时返回给客户端。
  2. 刷新商城

    • 客户端请求刷新商城的接口。
    • 查询数据库找到用户商城信息。
    • 判断今天手动刷新还是自动刷新。
    • 手动刷新去判断是否还有次数,自动刷新去判断当天是否刷新。

方法

1.获取商城

a. 计算当前时间到今天凌晨的时间.

 func (slf *RealmSer) GetCountdownSecond() (countdown int64) {
	now := time.Now() // 获取当前时间
	addDate := now.AddDate(0, 0, 1)
	today := time.Date(addDate.Year(), addDate.Month(), addDate.Day(), 0, 0, 0, 0, now.Location()) // 获取今天凌晨时间
	timestamp := today.Unix() - now.Unix()// 计算当前时间到今天凌晨的时间戳
	return timestamp
}

b. 获取公共的每日商店

func (slf *RealmSer) GetMallLimitedDetails() []MallLimitedDetails {
	limited := slf.Csvhandle.MallLimited
	var mallLimitedDetails []MallLimitedDetails
	//具体代码省略
	return mallLimitedDetails
}

c. 获取用户每日商店

 func () DoGetMallLimited(ctx context.Context, roleId int64) () {
  	//倒计时
	timeStamp = slf.GetCountdownSecond()
	 //用户用户数据库
	mallLimited, err := slf.getRoleMallLimited(ctx, roleId)
	if err != nil {
		log.Error(ctx, "getRoleMallLimited|%s", err)
		return nil, timeStamp, err
	}

	//如果商城没有,则给他加载
	if mallLimited == nil {
		limitedDetails := slf.GetMallLimitedDetails()
		limitedMall := LimitedMall{
			RoleId:             roleId,
			MallLimitedDetails: limitedDetails,
			TimeStamp:          time.Now().Unix(),
		}
		//写入数据库
		err := slf.createRoleLimitedMall(ctx, limitedMall)
		if err != nil {
			log.Error(ctx, "createRoleLimitedMall MongoDB is err=%s", err)
			return nil, timeStamp, err
		}
		return limitedDetails, timeStamp, nil
	}
	year, month, day := time.Now().Date()
	// 获得自动刷新的记录
	t := time.Unix(mallLimited.TimeStamp, 0)
	y, m, d := t.Date()
	//判断是否到了第二天还没有给他刷新
	if y != year || m != month || d != day {
		log.Debug(ctx, "y=%d,m=%d,d=%d", y, m, d)
		limitedDetails := slf.GetMallLimitedDetails()
		limitedMall := LimitedMall{
			RoleId:             roleId,
			MallLimitedDetails: limitedDetails,
			TimeStamp:          time.Now().Unix(),
		}
		//把新生成的商城道具修改到数据库
		err := slf.updateRoleLimitedMall(ctx, roleId, &limitedMall)
		if err != nil {
			log.Error(ctx, "updateRoleLimitedMall MongoDB is err=%s", err)
			return nil, timeStamp, err
		}
		return limitedDetails, timeStamp, nil
	}
	return mallLimited.MallLimitedDetails, timeStamp, err
}

2.刷新商城

func () refreshMallItemRandom(ctx context.Context, roleId int64, isAuto bool) () {
	//倒计时
	getCountdown := slf.GetCountdownSecond()
	
	//用户用户数据库
	mallLimited, err := slf.getRoleMallLimited(ctx, roleId)
	if err != nil {
		log.Error(ctx, "getRoleMallLimited|%s", err)
		return nil, timeStamp, err
	}
	//校验是否是自动刷新
	if isAuto {
		newUnix := time.Now().Unix()
		currentTime := time.Now()
		year, month, day := currentTime.Date()
		time00 := time.Date(year, month, day, 0, 0, 0, 0, currentTime.Location())
		noonTime00stampmin := time00.Unix() - 3
		noonTime00stampmax := time00.Unix() + 3

		if noonTime00stampmin <= newUnix && newUnix <= noonTime00stampmax {
			limitedDetails := slf.GetMallLimitedDetails()
			limitedMall := LimitedMall{
				RoleId:             roleId,
				MallLimitedDetails: limitedDetails,
				TimeStamp:          time.Now().Unix(),
			}
			//把新生成的商城道具修改到数据库
			err := slf.updateRoleLimitedMall(ctx, roleId, &limitedMall)
			if err != nil {
				log.Error(ctx, "updateRoleLimitedMall MongoDB is err=%s", err)
				return nil, timeStamp, err
			}
			return limitedDetails, timeStamp, nil
		}
		//返回错误
		return limitedDetails, timeStamp, myErr
	} else {
		refreshTimes := mallLimited.RefreshTimes
		if refreshTimes <= 0 {
			//刷新次数不够了
			return limitedDetails, timeStamp, myErr
		}
		mallLimited.RefreshTimes-=1
		limitedDetails := slf.GetMallLimitedDetails()
		limitedMall := LimitedMall{
			RoleId:             roleId,
			MallLimitedDetails: limitedDetails,
			TimeStamp:          time.Now().Unix(),
		}
		//把新生成的商城道具修改到数据库,同时刷新次数减一
		err := slf.updateRoleLimitedMall(ctx, roleId, &limitedMall)
		if err != nil {
			log.Error(ctx, "updateRoleLimitedMall MongoDB is err=%s", err)
			return nil, timeStamp, err
		}
		return limitedDetails, timeStamp, nil
	}
	return limitedDetails, timeStamp, err
}

存在问题

目前我感觉会存在几个问题,想听听大佬的见解,希望可以提升自己的业务能力。

  1. 这个获取商城信息,我用记录的时间戳去判断今天是否已经刷新,如果正好是凌晨我这个逻辑有问题吗?
    在这里插入图片描述
  2. 在购买的接口里面我要去验证上次刷新的时间戳是今天吗?
  3. 我在自动刷新的判断里面,给了6秒的延迟,因为我把倒计时给客户端,他那边再向我请求会存在延迟,他可能会利用这个bug返回请求自动刷新。有没有什么好的解决方案,或者给多少秒的缓冲比较好。
    在这里插入图片描述
  • 23
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值