Przeglądaj źródła

1.优化受灾和测试类逻辑

slambb 4 lat temu
rodzic
commit
3ba51f590c

+ 2 - 0
src/main/java/com/td/boss/config/enums/ResultEnum.java

@@ -58,6 +58,8 @@ public enum ResultEnum {
     APPLY_SNB_TOO_MUCH(606,"snb申请过多,待审核完成后再申请!"),
     APPLY_SNB_HAS_APPLY(607,"已有一笔snb申请中,待审核完成后再申请!"),
     APPLY_SNB_STATE_ERROR(608,"状态信息错误!"),
+
+    WALLET_SNB_ABNORMAL(609,"SNB异常状态"),
     //土地数据
     LAND_DATA_ERROR(701,"土地数据不能初始化!"),
     LAND_NOT_LEASE(702,"土地未租赁!"),

+ 71 - 50
src/main/java/com/td/boss/game/complayergoods/controller/ComPlayerGoodsController.java

@@ -248,16 +248,18 @@ public class ComPlayerGoodsController extends CommonController<ComPlayerGoodsVo,
         }
 
         //需要redis 加锁
-        long time = System.currentTimeMillis() + RedisData.getPlayerGoodsTimeout();
+        //long time = System.currentTimeMillis() + RedisData.getPlayerGoodsTimeout();
         //获取用户的plantFlag,因为之前的用户没有设置这个flag,所以设为第一次,用 userId 和 landId 组合成key
         String _redisKey = comPlayerLand.getPlantFlag();
         if (!StringUtils.hasText(_redisKey)) {
             //return Result.of(null, false, ResultEnum.LAND_PLANT_FLAG_IS_NULL.getMessage(), ResultEnum.LAND_PLANT_FLAG_IS_NULL.getCode());
             _redisKey = comPlayerLand.getUserId() + "or" + comPlayerLand.getConfigLandId();
         }
+        long landTime = System.currentTimeMillis() + RedisData.getLandTimeout();
+
         //受灾时候,不给收获
-        String _disasterKey = RedisData.getPlayerDisastersFirstKey() + comPlayerLand.getConfigLandId() + comPlayerLand.getUserId();
-        long _disasterTime = System.currentTimeMillis() + RedisData.getPlayerDisastersFirstTimeout();
+        //String _disasterKey = RedisData.getPlayerDisastersFirstKey() + comPlayerLand.getConfigLandId() + comPlayerLand.getUserId();
+        //long _disasterTime = System.currentTimeMillis() + RedisData.getPlayerDisastersFirstTimeout();
 
         Map map = new HashMap();
         //todo 总共偷去的数量
@@ -266,12 +268,12 @@ public class ComPlayerGoodsController extends CommonController<ComPlayerGoodsVo,
         Double _disasterProfits = 0d;
         try {
             //加一层受灾锁
-            if (!redisLock.lock(_disasterKey, String.valueOf(_disasterTime))) {
-                return Result.of(null, false, ResultEnum.LAND_DISATER_LOCK.getMessage(), ResultEnum.LAND_DISATER_LOCK.getCode());
-            }
+            //if (!redisLock.lock(_disasterKey, String.valueOf(_disasterTime))) {
+            //    return Result.of(null, false, ResultEnum.LAND_DISATER_LOCK.getMessage(), ResultEnum.LAND_DISATER_LOCK.getCode());
+            //}
 
             // 如果存在plantFlag 说明是新种植的
-            if (!redisLock.lock(_redisKey, String.valueOf(time))) {
+            if (!redisLock.lock(_redisKey, String.valueOf(landTime))) {
                 return Result.of(null, false, ResultEnum.LAND_STEAL_LOCK.getMessage(), ResultEnum.LAND_STEAL_LOCK.getCode());
             }
 
@@ -382,12 +384,12 @@ public class ComPlayerGoodsController extends CommonController<ComPlayerGoodsVo,
             comPlayerLogService.save(_playerLogVo);
 
             //对应的,存在plantFlag则解锁
-            redisLock.unlock(_redisKey, String.valueOf(time));
-            redisLock.unlock(_disasterKey, String.valueOf(_disasterTime));
+            redisLock.unlock(_redisKey, String.valueOf(landTime));
+            //redisLock.unlock(_disasterKey, String.valueOf(_disasterTime));
         } catch (Exception e) {
             //对应的,存在plantFlag则解锁
-            redisLock.unlock(_redisKey, String.valueOf(time));
-            redisLock.unlock(_disasterKey, String.valueOf(_disasterTime));
+            redisLock.unlock(_redisKey, String.valueOf(landTime));
+            //redisLock.unlock(_disasterKey, String.valueOf(_disasterTime));
             throw new RuntimeException(e.getMessage());
         }
         map.put("msg", "成功收取果实!");
@@ -481,6 +483,10 @@ public class ComPlayerGoodsController extends CommonController<ComPlayerGoodsVo,
         ComPlayersAttriVo playersAttribute = comPlayersAttriService.findByUserId(userId);
         Integer _out = _maxStrength - Math.abs(playersAttribute.getStrength());
         Double _userAllSnb = DoubleUtil.add(comUsersVo.getSnb().doubleValue(), comUsersVo.getSnbPart());
+        if (DoubleUtil.compare(_userAllSnb, 0.0).equals(-1)) {
+            map.put("msg", "snb异常");
+            return Result.of(map, false, ResultEnum.WALLET_SNB_ABNORMAL.getMessage(), ResultEnum.WALLET_SNB_ABNORMAL.getCode());
+        }
         //判断是否有足够的snb
         if (DoubleUtil.compare(_userAllSnb, comSettingVo.getDeductSnb()) == -1) {
             _hasReduceSnb = false;
@@ -510,44 +516,57 @@ public class ComPlayerGoodsController extends CommonController<ComPlayerGoodsVo,
         if (otherPlayerLand == null) {
             return Result.of(null, false, ResultEnum.LAND_CAN_STEAL_IS_NULL.getMessage(), ResultEnum.LAND_CAN_STEAL_IS_NULL.getCode());
         }
+        if (otherPlayerLand.getIsPlant().equals(0) && otherPlayerLand.getPlantSteal().equals(0)) {
+            return Result.of(null, false, ResultEnum.LAND_CAN_STEAL_IS_NULL.getMessage(), ResultEnum.LAND_CAN_STEAL_IS_NULL.getCode());
+        }
         //snb 的key
         String _redisSNBKey = "SNB_SAVE_" + userId;
+        long snbTime = System.currentTimeMillis() + RedisData.getSnbTimeout();
+
         //获取用户的plantFlag,因为之前的用户没有设置这个flag,所以设为第一次,用 userId 和 landId 组合成key
         String _redisKey = otherPlayerLand.getPlantFlag();
         if (!StringUtils.hasText(_redisKey)) {
             //return Result.of(null, false, ResultEnum.LAND_PLANT_FLAG_IS_NULL.getMessage(), ResultEnum.LAND_PLANT_FLAG_IS_NULL.getCode());
             _redisKey = otherPlayerLand.getUserId() + "or" + otherPlayerLand.getConfigLandId();
         }
-        //todo 先判断是否偷取过
-        ComPlayerProfit comPlayerProfit = comPlayerProfitService.findByUserIdAndOtherUserIdAndPlantFlag(userId, otherUserId, _redisKey);
-        if (comPlayerProfit != null) {
-            return Result.of(null, false, ResultEnum.LAND_HARVEST_STOLEN.getMessage(), ResultEnum.LAND_HARVEST_STOLEN.getCode());
-        }
-        //获取当前种植的种子
-        ComMallSeedVo comMallSeedVo = comMallSeedService.findById(otherPlayerLand.getPlantId());
-        //需要redis 加锁
-        long time = System.currentTimeMillis() + RedisData.getPlayerGoodsTimeout();
+        long landTime = System.currentTimeMillis() + RedisData.getLandTimeout();
 
         //受灾时候,不给收获
-        String _disasterKey = RedisData.getPlayerDisastersFirstKey() + otherPlayerLand.getConfigLandId() + otherPlayerLand.getUserId();
-        long _disasterTime = System.currentTimeMillis() + RedisData.getPlayerDisastersFirstTimeout();
-
+        //String _disasterKey = RedisData.getPlayerDisastersFirstKey() + otherPlayerLand.getConfigLandId() + otherPlayerLand.getUserId();
+        //long _disasterTime = System.currentTimeMillis() + RedisData.getPlayerDisastersFirstTimeout();
 
         try {
+
             //加一层受灾锁
-            if (!redisLock.lock(_disasterKey, String.valueOf(_disasterTime))) {
-                return Result.of(null, false, ResultEnum.LAND_DISATER_LOCK.getMessage(), ResultEnum.LAND_DISATER_LOCK.getCode());
-            }
+            //if (!redisLock.lock(_disasterKey, String.valueOf(_disasterTime))) {
+            //    return Result.of(null, false, ResultEnum.LAND_DISATER_LOCK.getMessage(), ResultEnum.LAND_DISATER_LOCK.getCode());
+            //}
 
-            if (!redisLock.lock(_redisSNBKey, String.valueOf(time))) {
+            //snb 是个人锁
+            if (!redisLock.lock(_redisSNBKey, String.valueOf(snbTime))) {
                 //如果有snb冲突锁
                 return Result.of(null, false, ResultEnum.USER_LOGIN_LOCK.getMessage(), ResultEnum.USER_LOGIN_LOCK.getCode());
 
             }
-            if (!redisLock.lock(_redisKey, String.valueOf(time))) {
+            if (!redisLock.lock(_redisKey, String.valueOf(landTime))) {
                 //如果有冲突锁
                 return Result.of(null, false, ResultEnum.LAND_STEAL_LOCK.getMessage(), ResultEnum.LAND_STEAL_LOCK.getCode());
             }
+
+            //todo 先判断是否偷取过
+            //ComPlayerProfit comPlayerProfit = comPlayerProfitService.findByUserIdAndOtherUserIdAndPlantFlag(userId, otherUserId, _redisKey);
+            //if (comPlayerProfit != null) {
+            //    return Result.of(null, false, ResultEnum.LAND_HARVEST_STOLEN.getMessage(), ResultEnum.LAND_HARVEST_STOLEN.getCode());
+            //}
+            List<ComPlayerProfit> comPlayerProfits = comPlayerProfitService.findByUserIdAndPlantFlagAndLandId(otherUserId, _redisKey, otherPlayerLand.getConfigLandId());
+            for (int i = 0; i < comPlayerProfits.size(); i++) {
+                ComPlayerProfit temp = comPlayerProfits.get(i);
+                if (temp.getUserId().equals(userId)) {
+                    return Result.of(null, false, ResultEnum.LAND_HARVEST_STOLEN.getMessage(), ResultEnum.LAND_HARVEST_STOLEN.getCode());
+                }
+            }
+            //获取当前种植的种子
+            ComMallSeedVo comMallSeedVo = comMallSeedService.findById(otherPlayerLand.getPlantId());
             //todo 如果当前人员偷窃水果。记录一个信息,存储当前玩家已偷过的水果的信息
             //计算一个偷取的收获量, 租赁倍数* 租赁日期下的产量
             Integer _otherAmount = 0;
@@ -578,11 +597,11 @@ public class ComPlayerGoodsController extends CommonController<ComPlayerGoodsVo,
             //这里根据plantFlag判断目标用户当前种植被偷取完,记录更新用户 comPlayerLand plantSteal 字段;保存一个偷取状态
             //这里只拿去被偷的利润,灾难扣除的不算再这里,但是总利润需要限制计算
             //Double _sumStolen = comPlayerProfitService.getStolenSumByOtherUserIdAndPlantFlagAndLossType(otherUserId, _redisKey,0);
-            Double _sumStolen = 0d,_allStolen = 0d;
-            List<ComPlayerProfit> comPlayerProfits = comPlayerProfitService.findByUserIdAndPlantFlagAndLandId(otherUserId, _redisKey, otherPlayerLand.getConfigLandId());
+            Double _sumStolen = 0d, _allStolen = 0d;
+
             for (int i = 0; i < comPlayerProfits.size(); i++) {
                 ComPlayerProfit temp = comPlayerProfits.get(i);
-                if(temp.getLossType().equals(0)){
+                if (temp.getLossType().equals(0)) {
                     //偷取时候的利润总和
                     _sumStolen = DoubleUtil.add(_sumStolen, temp.getStolen());
                 }
@@ -608,32 +627,32 @@ public class ComPlayerGoodsController extends CommonController<ComPlayerGoodsVo,
             //Double _diff = Math.abs(DoubleUtil.sub(_maxAmount, _sumStolen));
             Double _diff = DoubleUtil.sub(_maxAmount, _sumStolen);
             Boolean isUpdateCanSteal = false;
-            if (DoubleUtil.compare(_diff,0.0).equals(1)) {
-                if(DoubleUtil.compare(_stolenAmount, _diff).equals(1)){
+            if (DoubleUtil.compare(_diff, 0.0).equals(1)) {
+                if (DoubleUtil.compare(_stolenAmount, _diff).equals(1)) {
                     _stolenAmount = _diff;
                     isUpdateCanSteal = true;
                 }
-            }else{
+            } else {
                 _stolenAmount = 0d;
                 isUpdateCanSteal = true;
             }
             //这里需要拦截处理最终偷取的利润,比如 总利润_profit=530(可能会加上收益),
             // _allStolen + _stolenAmount 不能大于总利润
-            Double _endLossProfit = DoubleUtil.add(_allStolen,_stolenAmount);
-            Double _endLossDiff = DoubleUtil.sub(_profit,_endLossProfit);
-            if(!DoubleUtil.compare(_sumStolen, _maxAmount).equals(-1) || DoubleUtil.compare(_endLossDiff,0.0).equals(-1)){
+            Double _endLossProfit = DoubleUtil.add(_allStolen, _stolenAmount);
+            Double _endLossDiff = DoubleUtil.sub(_profit, _endLossProfit);
+            if (!DoubleUtil.compare(_sumStolen, _maxAmount).equals(-1) || DoubleUtil.compare(_endLossDiff, 0.0).equals(-1)) {
                 //如果差值为零
                 // 需要redis 解锁
-                redisLock.unlock(_redisKey, String.valueOf(time));
-                redisLock.unlock(_redisSNBKey, String.valueOf(time));
-                redisLock.unlock(_disasterKey, String.valueOf(_disasterTime));
+                redisLock.unlock(_redisKey, String.valueOf(landTime));
+                redisLock.unlock(_redisSNBKey, String.valueOf(snbTime));
+                //redisLock.unlock(_disasterKey, String.valueOf(_disasterTime));
                 //记录一个不可偷取的状态
                 otherPlayerLand.setPlantSteal(0);
                 comPlayerLandService.save(CopyUtil.copy(otherPlayerLand, ComPlayerLandVo.class));
                 map.put("plant_steal", otherPlayerLand.getPlantSteal());
                 return Result.of(map, false, ResultEnum.LAND_CAN_STEAL_IS_MAX.getMessage(), ResultEnum.LAND_CAN_STEAL_IS_MAX.getCode());
             }
-            if(isUpdateCanSteal){
+            if (isUpdateCanSteal) {
                 //记录一个不可偷取的状态
                 otherPlayerLand.setPlantSteal(0);
                 comPlayerLandService.save(CopyUtil.copy(otherPlayerLand, ComPlayerLandVo.class));
@@ -669,7 +688,7 @@ public class ComPlayerGoodsController extends CommonController<ComPlayerGoodsVo,
             comPlayerGoodsService.save(comPlayerGoodsVo);
 
             //todo 偷窃损失,处理目标用户收取果实时候,减扣一部分被偷取的数量
-            comPlayerProfit = new ComPlayerProfit();
+            ComPlayerProfit comPlayerProfit = new ComPlayerProfit();
             comPlayerProfit.setUserId(userId);
             comPlayerProfit.setTargetId(otherUserId);
             comPlayerProfit.setPlantFlag(_redisKey);
@@ -730,8 +749,6 @@ public class ComPlayerGoodsController extends CommonController<ComPlayerGoodsVo,
             _landMap.put("finallyGetRatioConfig", finallyGetRatioConfig);
 
             _finalStealAmountSum = DoubleUtil.add(_finalStealAmount, _finalStealAmountSum);
-            // 需要redis 解锁
-            redisLock.unlock(_redisKey, String.valueOf(time));
 
             map.put("msg", "偷取果实.");
             map.put("stealInfo", _landMap);
@@ -813,16 +830,20 @@ public class ComPlayerGoodsController extends CommonController<ComPlayerGoodsVo,
             map.put("snb", comUsersVo.getSnb());
             map.put("snbPart", comUsersVo.getSnbPart());
 
+            //2l 之后,解锁
+            //Thread.sleep(2L);
+            //解除land锁
+            redisLock.unlock(_redisKey, String.valueOf(landTime));
             //解除snb锁
-            redisLock.unlock(_redisSNBKey, String.valueOf(time));
-
-            redisLock.unlock(_disasterKey, String.valueOf(_disasterTime));
+            redisLock.unlock(_redisSNBKey, String.valueOf(snbTime));
+            //解除灾难锁
+            //redisLock.unlock(_disasterKey, String.valueOf(_disasterTime));
             return Result.of(map);
         } catch (Exception e) {
             // 需要redis 解锁
-            redisLock.unlock(_redisKey, String.valueOf(time));
-            redisLock.unlock(_redisSNBKey, String.valueOf(time));
-            redisLock.unlock(_disasterKey, String.valueOf(_disasterTime));
+            redisLock.unlock(_redisKey, String.valueOf(landTime));
+            redisLock.unlock(_redisSNBKey, String.valueOf(snbTime));
+            //redisLock.unlock(_disasterKey, String.valueOf(_disasterTime));
             throw new RuntimeException(e.getMessage());
         }
 

+ 70 - 69
src/main/java/com/td/boss/game/complayerland/controller/ComPlayerLandController.java

@@ -157,7 +157,7 @@ public class ComPlayerLandController extends CommonController<ComPlayerLandVo, C
 
         } catch (Exception e) {
             //throw new RuntimeException(e.getMessage());
-            return  Result.of(null,false,"服务器繁忙,请刷新游戏重新进入!",ResultEnum.REDIS_IS_LOCK.getCode());
+            return Result.of(null, false, "服务器繁忙,请刷新游戏重新进入!", ResultEnum.REDIS_IS_LOCK.getCode());
         }
 
         return Result.of(_list);
@@ -485,7 +485,7 @@ public class ComPlayerLandController extends CommonController<ComPlayerLandVo, C
     @Transactional(rollbackFor = Exception.class)
     public Result<Map> getDisasterMap(@RequestParam(value = "userId") String userId) {
         List<ComPlayerDisasterProtected> protectList = disasterProtectedService.getComPlayerDisasterProtectedByUserIdOrderByProtectTimeDesc(userId);
-       ComPlayerDisasterProtected _naturalDisasterProtected = protectList.stream()
+        ComPlayerDisasterProtected _naturalDisasterProtected = protectList.stream()
                 .filter(a -> a.getDsasterType().equals(2))
                 .sorted(Comparator.comparing(ComPlayerDisasterProtected::getProtectTime).reversed())
                 .findFirst().orElse(null);
@@ -494,8 +494,8 @@ public class ComPlayerLandController extends CommonController<ComPlayerLandVo, C
                 .sorted(Comparator.comparing(ComPlayerDisasterProtected::getProtectTime).reversed())
                 .findFirst().orElse(null);
         Map map = new HashMap();
-        map.put("naturalProtected",_naturalDisasterProtected == null? null: CopyUtil.copy(_naturalDisasterProtected, ComPlayerDisasterProtectedSimpleVo.class));
-        map.put("beastProtected",_beastDisasterProtected == null? null:CopyUtil.copy(_beastDisasterProtected, ComPlayerDisasterProtectedSimpleVo.class));
+        map.put("naturalProtected", _naturalDisasterProtected == null ? null : CopyUtil.copy(_naturalDisasterProtected, ComPlayerDisasterProtectedSimpleVo.class));
+        map.put("beastProtected", _beastDisasterProtected == null ? null : CopyUtil.copy(_beastDisasterProtected, ComPlayerDisasterProtectedSimpleVo.class));
         return Result.of(map);
     }
 
@@ -503,85 +503,86 @@ public class ComPlayerLandController extends CommonController<ComPlayerLandVo, C
         //这里处理一次判断是否发生过第一次灾难
         //todo 添加一个灾难损失,灾难损失的时间点是种植开始到成熟阶段的一个随机时间
         // 加个锁判断,是否在其他地方触发了这次灾难计算(自解锁)
-        long time = System.currentTimeMillis() + RedisData.getPlayerDisastersFirstTimeout();
+        long _disasterTime = System.currentTimeMillis() + RedisData.getPlayerDisastersFirstTimeout();
         String _disasterKey = RedisData.getPlayerDisastersFirstKey() + comPlayerLandAndPlantVo.getConfigLandId() + comPlayerLandAndPlantVo.getUserId();
         try {
-            if (redisLock.lock(_disasterKey, String.valueOf(time))) {
-                //查询当前人员购买防护历史记录
-                List<ComPlayerDisasterProtected> protectList = disasterProtectedService.getComPlayerDisasterProtectedByUserIdOrderByProtectTimeDesc(comPlayerLandAndPlantVo.getUserId());
-
-                //灾难发生时间
-                Date endDate = DateUtil.getOldDateAddDay(comPlayerLandAndPlantVo.getPlantStart(), comPlayerLandAndPlantVo.getPlantMature());
-                //log.info(comPlayerLandAndPlantVo.getPlantStart().getTime() + "= " + endDate.getTime());
-                long randomDate =comPlayerLandAndPlantVo.getPlantStart().compareTo(endDate) == 0?
-                        endDate.getTime(): RandomUtil.randomLong(comPlayerLandAndPlantVo.getPlantStart().getTime(), endDate.getTime());
-                Date disasterDate = new Date(randomDate);
-                //获取损失的数据
-                List<ComPlayerProfit> comPlayerProfits = comPlayerProfitService.findByUserIdAndPlantFlagAndLandId(comPlayerLandAndPlantVo.getUserId(), comPlayerLandAndPlantVo.getPlantFlag(), comPlayerLandAndPlantVo.getConfigLandId());
-                //todo 总共受损的数量
-                Double _allLossProfit = 0d;
-                boolean isNaturalProfit = false, isBeastProfit = false;
-                for (int j = 0; j < comPlayerProfits.size(); j++) {
-                    ComPlayerProfit _profit = comPlayerProfits.get(j);
-                    _allLossProfit = DoubleUtil.add(_allLossProfit, _profit.getStolen());
-                    if (_profit.getLossType().equals(2)) {
-                        if(DoubleUtil.compare(-1D, _profit.getDsasterId().doubleValue()).equals(0)){
-                            isNaturalProfit = true;
-                        }
-                    } else if (_profit.getLossType().equals(3)) {
-                        if(DoubleUtil.compare(-1D, _profit.getDsasterId().doubleValue()).equals(0)){
-                            isBeastProfit = true;
-                        }
+            if (!redisLock.lock(_disasterKey, String.valueOf(_disasterTime))) {
+                log.info("锁住_disasterKey:" + _disasterKey);
+            }
+            //查询当前人员购买防护历史记录
+            List<ComPlayerDisasterProtected> protectList = disasterProtectedService.getComPlayerDisasterProtectedByUserIdOrderByProtectTimeDesc(comPlayerLandAndPlantVo.getUserId());
+
+            //灾难发生时间
+            Date endDate = DateUtil.getOldDateAddDay(comPlayerLandAndPlantVo.getPlantStart(), comPlayerLandAndPlantVo.getPlantMature());
+            //log.info(comPlayerLandAndPlantVo.getPlantStart().getTime() + "= " + endDate.getTime());
+            long randomDate = comPlayerLandAndPlantVo.getPlantStart().compareTo(endDate) == 0 ?
+                    endDate.getTime() : RandomUtil.randomLong(comPlayerLandAndPlantVo.getPlantStart().getTime(), endDate.getTime());
+            Date disasterDate = new Date(randomDate);
+            //获取损失的数据
+            List<ComPlayerProfit> comPlayerProfits = comPlayerProfitService.findByUserIdAndPlantFlagAndLandId(comPlayerLandAndPlantVo.getUserId(), comPlayerLandAndPlantVo.getPlantFlag(), comPlayerLandAndPlantVo.getConfigLandId());
+            //todo 总共受损的数量
+            Double _allLossProfit = 0d;
+            boolean isNaturalProfit = false, isBeastProfit = false;
+            for (int j = 0; j < comPlayerProfits.size(); j++) {
+                ComPlayerProfit _profit = comPlayerProfits.get(j);
+                _allLossProfit = DoubleUtil.add(_allLossProfit, _profit.getStolen());
+                if (_profit.getLossType().equals(2)) {
+                    if (DoubleUtil.compare(-1D, _profit.getDsasterId().doubleValue()).equals(0)) {
+                        isNaturalProfit = true;
+                    }
+                } else if (_profit.getLossType().equals(3)) {
+                    if (DoubleUtil.compare(-1D, _profit.getDsasterId().doubleValue()).equals(0)) {
+                        isBeastProfit = true;
                     }
                 }
-                log.info("用户编号:{},防护历史记录:{}", comPlayerLandAndPlantVo.getUserId(), JSONUtil.toJsonStr(protectList));
-                //获得对应灾难类型的防护记录    并得到这个 防护到期时间. 自然灾害类型
+            }
+            log.info("用户编号:{},防护历史记录:{}", comPlayerLandAndPlantVo.getUserId(), JSONUtil.toJsonStr(protectList));
+            //获得对应灾难类型的防护记录    并得到这个 防护到期时间. 自然灾害类型
+            //如果没有防护或者防护到期。则直接发生灾难进行减产
+
+            if (!isNaturalProfit) {
+                Date _protectedDate = protectList.stream()
+                        .filter(a -> a.getDsasterType().equals(2))
+                        .sorted(Comparator.comparing(ComPlayerDisasterProtected::getProtectTime).reversed())
+                        .map(ComPlayerDisasterProtected::getProtectTime)
+                        .findFirst().orElse(cn.hutool.core.date.DateUtil.parse(null));
                 //如果没有防护或者防护到期。则直接发生灾难进行减产
-
-                if (!isNaturalProfit) {
-                    Date _protectedDate = protectList.stream()
-                            .filter(a -> a.getDsasterType().equals(2))
-                            .sorted(Comparator.comparing(ComPlayerDisasterProtected::getProtectTime).reversed())
-                            .map(ComPlayerDisasterProtected::getProtectTime)
-                            .findFirst().orElse(cn.hutool.core.date.DateUtil.parse(null));
-                    //如果没有防护或者防护到期。则直接发生灾难进行减产
-                    if (_protectedDate == null || disasterDate.after(_protectedDate)) {
-                        //灾难的随机时间比防护包时间后,说明防护包到期
-                        //成熟的时候触发第一次自然灾难
-                        ComPlayerProfitVo naturalProfitVo = comPlayerProfitService.addFirstDisasterAndLoss(CopyUtil.copy(comPlayerLandAndPlantVo, ComPlayerLand.class),
-                                comMallSeedVo, 2, _allLossProfit,-1);
-                        //多次执行需要加上当前操作的利润
-                        _allLossProfit += naturalProfitVo.getStolen();
-
-                        //添加自然灾害灾难记录
-                        comPlayerDisasterLogService.addDisasterEnable(comPlayerLandAndPlantVo.getUserId(),-1L,2,_protectedDate);
-                    }
+                if (_protectedDate == null || disasterDate.after(_protectedDate)) {
+                    //灾难的随机时间比防护包时间后,说明防护包到期
+                    //成熟的时候触发第一次自然灾难
+                    ComPlayerProfitVo naturalProfitVo = comPlayerProfitService.addFirstDisasterAndLoss(CopyUtil.copy(comPlayerLandAndPlantVo, ComPlayerLand.class),
+                            comMallSeedVo, 2, _allLossProfit, -1);
+                    //多次执行需要加上当前操作的利润
+                    _allLossProfit += naturalProfitVo.getStolen();
+
+                    //添加自然灾害灾难记录
+                    comPlayerDisasterLogService.addDisasterEnable(comPlayerLandAndPlantVo.getUserId(), -1L, 2, _protectedDate);
                 }
-                if (!isBeastProfit) {
-                    Date _protectedDate = protectList.stream()
-                            .filter(a -> a.getDsasterType().equals(3))
-                            .sorted(Comparator.comparing(ComPlayerDisasterProtected::getProtectTime).reversed())
-                            .map(ComPlayerDisasterProtected::getProtectTime)
-                            .findFirst().orElse(cn.hutool.core.date.DateUtil.parse(null));
-                    //如果没有防护或者防护到期。则直接发生灾难进行减产
-                    if (_protectedDate == null || disasterDate.after(_protectedDate)) {
-                        //灾难的随机时间比防护包时间后,说明防护包到期
-                        //成熟的时候触发第一次自然灾难
-                        ComPlayerProfitVo beastProfitVo = comPlayerProfitService.addFirstDisasterAndLoss(CopyUtil.copy(comPlayerLandAndPlantVo, ComPlayerLand.class),
-                                comMallSeedVo, 3, _allLossProfit,-1);
+            }
+            if (!isBeastProfit) {
+                Date _protectedDate = protectList.stream()
+                        .filter(a -> a.getDsasterType().equals(3))
+                        .sorted(Comparator.comparing(ComPlayerDisasterProtected::getProtectTime).reversed())
+                        .map(ComPlayerDisasterProtected::getProtectTime)
+                        .findFirst().orElse(cn.hutool.core.date.DateUtil.parse(null));
+                //如果没有防护或者防护到期。则直接发生灾难进行减产
+                if (_protectedDate == null || disasterDate.after(_protectedDate)) {
+                    //灾难的随机时间比防护包时间后,说明防护包到期
+                    //成熟的时候触发第一次自然灾难
+                    ComPlayerProfitVo beastProfitVo = comPlayerProfitService.addFirstDisasterAndLoss(CopyUtil.copy(comPlayerLandAndPlantVo, ComPlayerLand.class),
+                            comMallSeedVo, 3, _allLossProfit, -1);
 //                    //多次执行需要加上当前操作的利润
 //                    _allLossProfit += beastProfitVo.getStolen();
 
-                        //添加野兽灾害灾难记录
-                        comPlayerDisasterLogService.addDisasterEnable(comPlayerLandAndPlantVo.getUserId(),-1L,3,_protectedDate);
+                    //添加野兽灾害灾难记录
+                    comPlayerDisasterLogService.addDisasterEnable(comPlayerLandAndPlantVo.getUserId(), -1L, 3, _protectedDate);
 
-                    }
                 }
-
-                redisLock.unlock(_disasterKey, String.valueOf(time));
             }
+            redisLock.unlock(_disasterKey, String.valueOf(_disasterTime));
         } catch (Exception e) {
             log.error("触发_InitFirstDisasterProfit异:" + e.getMessage());
+            redisLock.unlock(_disasterKey, String.valueOf(_disasterTime));
         }
 
     }

+ 5 - 4
src/main/java/com/td/boss/game/complayerland/service/ComPlayerDisasterLogServiceImpl.java

@@ -232,7 +232,8 @@ public class ComPlayerDisasterLogServiceImpl extends CommonServiceImpl<ComPlayer
         if (!disasterLog.isProtect()) {
             log.info("灾难结果:减产");
             //todo 插入受灾减产数据
-            long time = System.currentTimeMillis() + RedisData.getPlayerDisastersFirstTimeout();
+            long _disasterTime = System.currentTimeMillis() + RedisData.getPlayerDisastersFirstTimeout();
+
             //查找用户的全部土地
             List<ComPlayerLand> comPlayerLands = comPlayerLandService.findAllByUserIdAndPlantAndMature(disasterLog.getUserId());
             for (int i = 0; i < comPlayerLands.size(); i++) {
@@ -244,7 +245,7 @@ public class ComPlayerDisasterLogServiceImpl extends CommonServiceImpl<ComPlayer
                 // 加个锁判断,是否在其他地方触发了这次灾难计算(自解锁)
                 String _disasterKey = RedisData.getPlayerDisastersFirstKey() + _comPlayerLand.getConfigLandId() + _comPlayerLand.getUserId();
                 try {
-                    if (!redisLock.lock(_disasterKey, String.valueOf(time))) {
+                    if (!redisLock.lock(_disasterKey, String.valueOf(_disasterTime))) {
                         log.info("锁住key:"+_disasterKey);
                        continue;
                     }
@@ -309,9 +310,9 @@ public class ComPlayerDisasterLogServiceImpl extends CommonServiceImpl<ComPlayer
                     comPlayerProfitService.addOtherDisasterAndLoss(CopyUtil.copy(_comPlayerLand, ComPlayerLand.class),
                             comMallSeedVo, disasterLog.getDsasterType(), _allLossProfit, _disasterCount,disasterLog.getDsasterId());
 
-                    redisLock.unlock(_disasterKey, String.valueOf(time));
+                    redisLock.unlock(_disasterKey, String.valueOf(_disasterTime));
                 } catch (Exception e) {
-                    redisLock.unlock(_disasterKey, String.valueOf(time));
+                    redisLock.unlock(_disasterKey, String.valueOf(_disasterTime));
                     log.error("额外灾难加锁异常:" + e.getMessage());
                 }
             }

+ 2 - 2
src/main/java/com/td/boss/game/complayerprofit/service/ComPlayerProfitServiceImpl.java

@@ -90,7 +90,7 @@ public class ComPlayerProfitServiceImpl extends CommonServiceImpl<ComPlayerProfi
         Double _profit =  DoubleUtil.add(_profitInt.doubleValue(),landLevelInCome);
         //todo 计算减产,第一次灾难按利润的 50% 减产,两次就是减到 0 了。
 
-        //必然发生的灾难,减产50%
+        //必然发生的灾难,减产40%
         Double _firstRatio = 0.4d;
         Double _reduceProfit = DoubleUtil.mul(_profit, _firstRatio);
         // 100 - 80 = 20
@@ -153,7 +153,7 @@ public class ComPlayerProfitServiceImpl extends CommonServiceImpl<ComPlayerProfi
         //todo 计算减产,第一次灾难按利润的 100 减产 50,两次就是 50 减到 25。
 
         //额外发生的灾难,按照次数计算减产 50% 发生已经发生1次计算后当次等于 25%,
-        double _startRatio = 1;
+        double _startRatio = 0.5;
         for(int i = disasterCount;i>0;i--){
             _startRatio =  DoubleUtil.mul(_startRatio,0.5);
         }

+ 8 - 0
src/main/java/com/td/boss/util/RedisData.java

@@ -31,6 +31,14 @@ public class RedisData {
         return PLAYER_GOODS_TIMEOUT;
     }
 
+    /**
+     * 土地操作锁
+     */
+    private static final int LAND_TIMEOUT = 60 * 1000; //超时时间 60s
+    public static int getLandTimeout() {
+        return LAND_TIMEOUT;
+    }
+
     /**
      * 10s 第一次触发灾难锁
      */

+ 216 - 0
src/test/java/com/td/boss/game/complayergoods/controller/ComPlayerGoodsControllerTest.java

@@ -0,0 +1,216 @@
+package com.td.boss.game.complayergoods.controller;
+
+import com.td.boss.common.pojo.Result;
+import com.td.boss.game.commallseed.service.ComMallSeedService;
+import com.td.boss.game.commallseed.vo.ComMallSeedVo;
+import com.td.boss.game.complayerland.pojo.ComPlayerLand;
+import com.td.boss.game.complayerland.service.ComPlayerLandService;
+import com.td.boss.game.complayerprofit.pojo.ComPlayerProfit;
+import com.td.boss.game.complayerprofit.service.ComPlayerProfitService;
+import com.td.boss.game.complayerprofit.vo.ComPlayerProfitVo;
+import com.td.boss.game.complayersattri.service.ComPlayersAttriService;
+import com.td.boss.game.complayersattri.vo.ComPlayersAttriVo;
+import com.td.boss.game.comusers.pojo.ComUsers;
+import com.td.boss.game.comusers.service.ComUsersService;
+import com.td.boss.game.comusers.vo.ComUsersVo;
+import com.td.boss.util.CopyUtil;
+import com.td.boss.util.DoubleUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.junit.jupiter.api.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CountDownLatch;
+import java.util.stream.Collectors;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+@Slf4j
+@RunWith(SpringRunner.class)
+@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
+class ComPlayerGoodsControllerTest {
+    private int threadCount = 5; // 子线程
+    private CountDownLatch countDownLatch = new CountDownLatch(threadCount);
+
+    private String otherUserId = "4";
+    private Integer otherLandId = 5;
+
+    @Autowired
+    private ComPlayerGoodsController comPlayerGoodsController;
+
+    @Autowired
+    private ComUsersService comUsersService;
+
+    @Autowired
+    private ComPlayersAttriService comPlayersAttriService;
+
+    @Autowired
+    private ComPlayerProfitService comPlayerProfitService;
+
+    @Autowired
+    private ComPlayerLandService comPlayerLandService;
+
+    @Autowired
+    private ComMallSeedService comMallSeedService;
+
+    @Test
+    public void test() {
+        //全部玩家,进行偷取测试
+        ComPlayersAttriVo comPlayersAttriVo = new ComPlayersAttriVo();
+        comPlayersAttriVo.setSidx("desc");
+        comPlayersAttriVo.setSord("createTime");
+        List<ComPlayersAttriVo> comPlayersAttriVoList = comPlayersAttriService.list(comPlayersAttriVo).getData();
+        List<String> userIdList = new ArrayList<>();
+        for (int a = 0; a < threadCount; a++) {
+            //for(int j = 0;j<10;j++){
+            //    userIdList.add(comPlayersAttriVoList.get(a*5 + j ).getUserId());
+            //}
+            Collections.shuffle(comPlayersAttriVoList);
+            userIdList = comPlayersAttriVoList.stream().map(e -> e.getUserId()).collect(Collectors.toList());
+            MyThread myThread = new MyThread(countDownLatch, userIdList);
+            Thread thread = new Thread(myThread);
+            thread.start();
+            try {
+                Thread.sleep(1L);
+            } catch (InterruptedException e) {
+                e.printStackTrace();
+            }
+        }
+
+        try {
+            countDownLatch.await();
+        } catch (Exception e) {
+
+        }
+    }
+
+    class MyThread implements Runnable {
+        private CountDownLatch countDownLatch;
+        List<String> searchVoList;
+
+        public MyThread(CountDownLatch countDownLatch, List<String> searchVoList) {
+            this.countDownLatch = countDownLatch;
+            this.searchVoList = searchVoList;
+        }
+
+        @Override
+        public void run() {
+
+            try {
+                for (String userIds : this.searchVoList) {
+                    if (userIds.equals(otherUserId)) {
+
+                        //测试受灾情况
+                        //disasterFunction();
+                        continue;
+                    }
+
+                    Thread.sleep(1L);
+                    Result<Map> result = comPlayerGoodsController.stealFruitFunction(userIds, otherUserId, otherLandId);
+                    if(result.getCode().equals(713)){
+
+                        //目标结束后收取果实
+                        comPlayerGoodsController.addFruitFunction(otherUserId, otherLandId);
+                        return;
+                    }
+                }
+
+                countDownLatch.await();
+            } catch (Exception e) {
+
+            }
+            //执行业务代码
+            countDownLatch.countDown();
+        }
+    }
+
+    @Test
+    void addFruitFunction() {
+        comPlayerGoodsController.addFruitFunction(otherUserId, otherLandId);
+    }
+
+    @Test
+    void disasterFunction() {
+
+        ComPlayerLand _comPlayerLand = comPlayerLandService.findByUserIdAndLandId(otherUserId,otherLandId);
+        ComMallSeedVo comMallSeedVo =  comMallSeedService.findById(_comPlayerLand.getPlantId());
+        List<ComPlayerProfit> comPlayerProfits = comPlayerProfitService.findByUserIdAndPlantFlagAndLandId(_comPlayerLand.getUserId(), _comPlayerLand.getPlantFlag(), _comPlayerLand.getConfigLandId());
+        //todo 总共受损的数量
+        Double _allLossProfit = 0d;
+        boolean isNaturalProfit = false, isBeastProfit = false;
+        Integer _disasterCount = 0;
+        for (int j = 0; j < comPlayerProfits.size(); j++) {
+            ComPlayerProfit _profit = comPlayerProfits.get(j);
+            _allLossProfit = DoubleUtil.add(_allLossProfit, _profit.getStolen());
+            if (_profit.getLossType().equals(2)) {
+                if(DoubleUtil.compare(-1D, _profit.getDsasterId().doubleValue()).equals(0)){
+                    isNaturalProfit = true;
+                }
+                //出现灾难的次数
+                _disasterCount++;
+            } else if (_profit.getLossType().equals(3)) {
+                if(DoubleUtil.compare(-1D, _profit.getDsasterId().doubleValue()).equals(0)){
+                    isBeastProfit = true;
+                }
+                //出现灾难的次数
+                _disasterCount++;
+            }
+        }
+
+
+        try {
+            ComPlayerProfitVo naturalProfitVo = comPlayerProfitService.addFirstDisasterAndLoss(CopyUtil.copy(_comPlayerLand, ComPlayerLand.class),
+                    comMallSeedVo, 2, _allLossProfit, -1);
+            //多次执行需要加上当前操作的利润
+            _allLossProfit += naturalProfitVo.getStolen();
+            _disasterCount ++;
+
+            ComPlayerProfitVo beastProfitVo = comPlayerProfitService.addFirstDisasterAndLoss(CopyUtil.copy(_comPlayerLand, ComPlayerLand.class),
+                    comMallSeedVo, 3, _allLossProfit, -1);
+            //多次执行需要加上当前操作的利润
+            _allLossProfit += beastProfitVo.getStolen();
+            _disasterCount ++;
+
+            //测试用
+            ComPlayerProfitVo _profitVo1 = comPlayerProfitService.addOtherDisasterAndLoss(CopyUtil.copy(_comPlayerLand, ComPlayerLand.class),
+                    comMallSeedVo, 2, _allLossProfit, _disasterCount, -2);
+            _allLossProfit += _profitVo1.getStolen();
+            _disasterCount ++;
+
+            Thread.sleep(10L);
+
+            ComPlayerProfitVo _profitVo2 = comPlayerProfitService.addOtherDisasterAndLoss(CopyUtil.copy(_comPlayerLand, ComPlayerLand.class),
+                    comMallSeedVo, 2, _allLossProfit, _disasterCount, -2);
+            _allLossProfit += _profitVo2.getStolen();
+            _disasterCount ++;
+
+            Thread.sleep(10L);
+
+            ComPlayerProfitVo _profitVo3 = comPlayerProfitService.addOtherDisasterAndLoss(CopyUtil.copy(_comPlayerLand, ComPlayerLand.class),
+                    comMallSeedVo, 2, _allLossProfit, _disasterCount, -2);
+            _allLossProfit += _profitVo3.getStolen();
+            _disasterCount ++;
+        }catch (Exception e){
+
+        }
+
+    }
+
+    @Test
+    void stealFruitFunction() {
+    }
+
+    @Test
+    void saleFruitFunction() {
+    }
+
+    @Test
+    void grantFruitFunction() {
+    }
+}