|
|
@@ -0,0 +1,237 @@
|
|
|
+package com.td.boss.game.complayerland.service;
|
|
|
+
|
|
|
+import cn.hutool.core.date.DateField;
|
|
|
+import cn.hutool.core.date.DateRange;
|
|
|
+import cn.hutool.core.date.DateTime;
|
|
|
+import cn.hutool.core.date.DateUtil;
|
|
|
+import cn.hutool.core.util.EnumUtil;
|
|
|
+import cn.hutool.core.util.NumberUtil;
|
|
|
+import cn.hutool.core.util.RandomUtil;
|
|
|
+import cn.hutool.json.JSONUtil;
|
|
|
+import com.td.boss.common.service.CommonServiceImpl;
|
|
|
+import com.td.boss.game.complayerland.pojo.ComPlayerDisaster;
|
|
|
+import com.td.boss.game.complayerland.pojo.ComPlayerDisasterLog;
|
|
|
+import com.td.boss.game.complayerland.pojo.ComPlayerDisasterProtected;
|
|
|
+import com.td.boss.game.complayerland.repository.ComPlayerDisasterLogRepository;
|
|
|
+import com.td.boss.game.complayerland.scheduled.ComPlayerDisasterDateUtil;
|
|
|
+import com.td.boss.game.complayerland.vo.ComPlayerDisasterEnum;
|
|
|
+import com.td.boss.game.complayerland.vo.ComPlayerDisasterLogVo;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.data.jpa.domain.Specification;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+import org.springframework.transaction.annotation.Transactional;
|
|
|
+import javax.persistence.criteria.CriteriaBuilder;
|
|
|
+import javax.persistence.criteria.CriteriaQuery;
|
|
|
+import javax.persistence.criteria.Predicate;
|
|
|
+import javax.persistence.criteria.Root;
|
|
|
+import java.util.*;
|
|
|
+import java.util.stream.Collectors;
|
|
|
+
|
|
|
+@Slf4j
|
|
|
+@Service
|
|
|
+@Transactional
|
|
|
+public class ComPlayerDisasterLogServiceImpl extends CommonServiceImpl<ComPlayerDisasterLogVo, ComPlayerDisasterLog, String> implements ComPlayerDisasterLogService {
|
|
|
+ @Autowired
|
|
|
+ private ComPlayerDisasterLogRepository disasterLogRepository;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private ComPlayerDisasterProtectedService disasterProtectedService;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private ComPlayerDisasterService disasterService;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 伤害 会减产50%
|
|
|
+ */
|
|
|
+ private int damage = 50;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 防御 90%概率防御灾难
|
|
|
+ */
|
|
|
+ private double defend = 90;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取经历的灾难记录
|
|
|
+ *
|
|
|
+ * @param userId
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public List<ComPlayerDisasterLog> getHistory(String userId) {
|
|
|
+ //获取已发生未读的灾难集合
|
|
|
+ List<ComPlayerDisasterLog> list = disasterLogRepository.getUnShowAndEnabled(userId).stream().sorted(Comparator.comparing(ComPlayerDisasterLog::getCreateTime)).collect(Collectors.toList());
|
|
|
+ log.info("获取灾难记录:{}", JSONUtil.toJsonStr(list));
|
|
|
+ //设置成已读
|
|
|
+ list.forEach(a -> a.setShow(true));
|
|
|
+ disasterLogRepository.saveAll(list);
|
|
|
+ return list;
|
|
|
+ }
|
|
|
+
|
|
|
+ //region 灾难模式周任务:同步每个用户上周收入支出
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 定时任务核心方法 同步每个用户上周收入支出
|
|
|
+ * 灾难模式每周统计一次,如果这个期间新用户也需要这个功能。新注册的用户直接调用该方法。
|
|
|
+ *
|
|
|
+ * @param userId
|
|
|
+ */
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
+ @Override
|
|
|
+ public void asyncDisaster(String userId) {
|
|
|
+ //获取“收入支出数据”,下一步计算灾难场数
|
|
|
+ ComPlayerDisaster comPlayerDisaster = disasterService.getAndSave(userId);
|
|
|
+ //如果从链端接口拉到数据了。那么就计算灾难发生明细
|
|
|
+ if (comPlayerDisaster != null) {
|
|
|
+ //本周内应该出现的灾难次数
|
|
|
+ int disasterTimes = getDisasterTimes(comPlayerDisaster.getPayment(), comPlayerDisaster.getIncome());
|
|
|
+ log.info("用户编号:{}本周发生灾难:{}次", userId, disasterTimes);
|
|
|
+
|
|
|
+ //获得本周还剩下几天可以发生灾难,每周从周日到下周6
|
|
|
+ Date now = new Date();
|
|
|
+ DateRange dayRange = DateUtil.range(now, ComPlayerDisasterDateUtil.getEnd(), DateField.DAY_OF_WEEK);
|
|
|
+ List<Date> hasDisasterDay = new ArrayList<>();
|
|
|
+ while (dayRange.hasNext()) {
|
|
|
+ hasDisasterDay.add(dayRange.next());
|
|
|
+ }
|
|
|
+ //发生灾难的时间点(本周具体哪天灾难),从可发生灾难【时间集合】中随机取【x】个时间点进行灾难
|
|
|
+ List<Date> realDisasterDayList = RandomUtil.randomEleList(hasDisasterDay, disasterTimes);
|
|
|
+ log.info("用户编号:{}本周发生灾难时间点:{}", userId, JSONUtil.toJsonStr(realDisasterDayList));
|
|
|
+
|
|
|
+ //生成灾难明细记录
|
|
|
+ List<ComPlayerDisasterLog> disasterLogList = getComPlayerDisasterLogVoList(userId, comPlayerDisaster.getId(), realDisasterDayList);
|
|
|
+ log.info("用户编号:{}本周发生灾难明细:{}", userId, JSONUtil.toJsonStr(disasterLogList));
|
|
|
+
|
|
|
+ //灾难明细持久化
|
|
|
+ disasterLogRepository.saveAll(disasterLogList);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获得本周灾难次数
|
|
|
+ * a)当某个村长所属农场的支出小于等于收入30%时,按照正常频率,每周出现1次
|
|
|
+ * b)当某个村长所属农场的支出大于收入30%时,每周出现2次
|
|
|
+ * c)当某个村长所属农场的支出大于收入50%时,每周出现4次
|
|
|
+ * d)当某个村长所属农场的支出大于收入80%时,每周出现6次
|
|
|
+ * 支出对应pay_amount,收入对应swap_amount
|
|
|
+ *
|
|
|
+ * @param pay_amount 支出对应
|
|
|
+ * @param swap_amount 收入对应
|
|
|
+ */
|
|
|
+ private int getDisasterTimes(double pay_amount, double swap_amount) {
|
|
|
+ if (pay_amount > NumberUtil.mul(swap_amount, 0.8)) {
|
|
|
+ return 6;
|
|
|
+ } else if (pay_amount > NumberUtil.mul(swap_amount, 0.5)) {
|
|
|
+ return 4;
|
|
|
+ } else if (pay_amount > NumberUtil.mul(swap_amount, 0.3)) {
|
|
|
+ return 2;
|
|
|
+ } else {
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 根据用户编号和灾难时间点 生成灾难表
|
|
|
+ *
|
|
|
+ * @param userId 用户id
|
|
|
+ * @param ComPlayerDisasterTableId 主表id
|
|
|
+ * @param realDisasterDayList 发生灾难的时间点(本周具体哪天灾难)
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private List<ComPlayerDisasterLog> getComPlayerDisasterLogVoList(String userId, long ComPlayerDisasterTableId, List<Date> realDisasterDayList) {
|
|
|
+ List<ComPlayerDisasterLog> list = new ArrayList<>();
|
|
|
+ ComPlayerDisasterLog disasterLog;
|
|
|
+ for (Date disasterDay : realDisasterDayList) {
|
|
|
+ //随机获取一种灾难方式灾难对象
|
|
|
+ List<String> disasterEnumFields = (List) EnumUtil.getFieldValues(ComPlayerDisasterEnum.class, "msg");
|
|
|
+ ComPlayerDisasterEnum disasterEnum = EnumUtil.likeValueOf(ComPlayerDisasterEnum.class, RandomUtil.randomEle(disasterEnumFields));
|
|
|
+
|
|
|
+ disasterLog = new ComPlayerDisasterLog();
|
|
|
+ disasterLog.setDsasterId(ComPlayerDisasterTableId);
|
|
|
+ disasterLog.setDsasterName(disasterEnum.getMsg());
|
|
|
+ disasterLog.setDsasterType(disasterEnum.getCode());
|
|
|
+ disasterLog.setUserId(userId);
|
|
|
+ disasterLog.setDamage(damage);
|
|
|
+ disasterLog.setDefend(defend);
|
|
|
+ disasterLog.setCreateTime(new Date());
|
|
|
+ disasterLog.setShow(false);
|
|
|
+ disasterLog.setEnabled(false);
|
|
|
+ disasterLog.setDisasterTime(disasterDay);
|
|
|
+ list.add(disasterLog);
|
|
|
+ }
|
|
|
+ return list;
|
|
|
+ }
|
|
|
+ //endregion
|
|
|
+
|
|
|
+ //region 灾难模式天任务:触发所有用户今日灾难和保护机制
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 灾难模式天任务:触发所有用户今日灾难和保护机制
|
|
|
+ */
|
|
|
+ @Transactional(rollbackFor = Exception.class)
|
|
|
+ @Override
|
|
|
+ public void ComPlayerDisasterDayTask(ComPlayerDisasterLog disasterLog) {
|
|
|
+ Date now = new Date();
|
|
|
+ //查询当前人员购买防护历史记录
|
|
|
+ List<ComPlayerDisasterProtected> protectList = disasterProtectedService.getComPlayerDisasterProtectedByUserIdOrderByProtectTimeDesc(disasterLog.getUserId());
|
|
|
+ log.info("用户编号:{},防护历史记录:{}", disasterLog.getUserId(), JSONUtil.toJsonStr(protectList));
|
|
|
+ //获得对应灾难类型的防护记录 并得到这个 防护到期时间
|
|
|
+ Date protectedDate = protectList.stream()
|
|
|
+ .filter(a -> disasterLog.getDsasterType().equals(a.getDsasterType()))
|
|
|
+ .sorted(Comparator.comparing(ComPlayerDisasterProtected::getProtectTime).reversed())
|
|
|
+ .map(ComPlayerDisasterProtected::getProtectTime)
|
|
|
+ .findFirst().orElse(DateUtil.parse(null));
|
|
|
+
|
|
|
+ log.info("用户编号:{},灾难:{},防护到期时间:{}", disasterLog.getUserId(), JSONUtil.toJsonStr(disasterLog), protectedDate);
|
|
|
+
|
|
|
+ //存储防护到期时间,可能是null代表没有购买过防护
|
|
|
+ disasterLog.setProtectTime(protectedDate);
|
|
|
+ //设置本次灾难已经发生
|
|
|
+ disasterLog.setEnabled(true);
|
|
|
+ //灾难具体触发时间,代表每天的周期任务时间
|
|
|
+ disasterLog.setUpdateTime(now);
|
|
|
+ //默认是没有防护的
|
|
|
+ disasterLog.setProtect(false);
|
|
|
+
|
|
|
+ //如果没有防护或者防护到期。则直接发生灾难进行减产
|
|
|
+ if (protectedDate != null && now.before(protectedDate)) {
|
|
|
+ int randomProtect = RandomUtil.randomInt(0, 101);
|
|
|
+ log.info("灾难几率:{}", randomProtect);
|
|
|
+ if (randomProtect > (100 - defend)) {
|
|
|
+ disasterLog.setProtect(true);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ log.info("灾难日志:{}", JSONUtil.toJsonStr(disasterLog));
|
|
|
+ disasterLogRepository.save(disasterLog);
|
|
|
+ //todo 减产接口 减产逻辑
|
|
|
+ if (!disasterLog.isProtect()) {
|
|
|
+ log.info("灾难结果:减产");
|
|
|
+ } else {
|
|
|
+ log.info("灾难结果:已防御");
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取今天的灾难,并且没有触发过的灾难
|
|
|
+ *
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public List<ComPlayerDisasterLog> getTodayDisasterUnEnabledList() {
|
|
|
+ Date now = new Date();
|
|
|
+ DateTime begin = DateUtil.beginOfDay(now);
|
|
|
+ DateTime end = DateUtil.endOfDay(now);
|
|
|
+ Specification specification = new Specification<ComPlayerDisasterLog>() {
|
|
|
+ @Override
|
|
|
+ public Predicate toPredicate(Root<ComPlayerDisasterLog> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
|
|
|
+ List<Predicate> predicates = new ArrayList<>();
|
|
|
+ predicates.add(criteriaBuilder.between(root.get("disasterTime"), begin, end));
|
|
|
+ predicates.add(criteriaBuilder.equal(root.get("isEnabled"), 0));
|
|
|
+ return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
|
|
|
+ }
|
|
|
+ };
|
|
|
+ return disasterLogRepository.findAll(specification);
|
|
|
+ }
|
|
|
+ //endregion
|
|
|
+}
|