活动系统解析

活动系统解析

Scroll Down

前言

活动分为限时活动和永久活动,活动开放时间读取活动配置表,我们来看下通过活动解析器管理活动类

ActivityParser活动解析接口

/**
 * 活动解析接口
 * @author CharonWang
 */
public interface ActivityParser extends OnEventListener {
	/**
	 * 记录玩家活动
	 * @param gamerId
	 * @param activityId
	 * @param id
	 * @return
	 */
	TResult<ActivityActionResponse> receiveReward(long actorId, int activityId, int id, Map<Integer, Object> parmeterMap);
	/**
	 * 获取登录时客户端数据
	 * @return
	 */
	TResult<ActivityRecordVO> getRecord2Client(long actorId, int activityId);
	/**
	 * 获取活动公共数据
	 * @param activityId
	 * @return
	 */
	TResult<ActivityGlobalVO> getGlobal2Client(long actorId, int activityId);
}

AbstractActivityParser活动解析抽象类

公司大佬写的活动,直接贴代码看吧

/**
 * 活动解析抽象类
 * @author CharonWang
 *
 */
public abstract class AbstractActivityParser extends ScheduleCronJob implements ActivityParser {
	protected final Logger LOGGER = LoggerFactory.getLogger(this.getClass());
	@Autowired
	private ActivityContext context;
	@Autowired
	protected ActivityGlobalDao activityGlobalDao;
	@Autowired
	protected ActivityRecordDao activityRecordDao;
	@Autowired
	protected DBQueue dbQueue;
	@Autowired
	protected GlobalConfigService globalConfigService;
	@Autowired
	protected Schedule schedule;
	@PostConstruct
	private void initialize() {
		context.register(getType(), this);
	}
	protected abstract ActivityType getType();
	/**
	 * 活动开始时触发一次
	 */
	protected abstract void onActivityOpen(List<ActivityOpenConfig> openActivityIds);
	/**
	 * 活动结束时触发一次
	 */
	protected abstract void onActivityEnd(List<ActivityOpenConfig> endActivityIds);
	/**
	 * 活动展示状态触发一次 
	 */
	protected void onActivityShow(List<ActivityOpenConfig> endActivityIds) {
	};
	@Override
	public String jobName() {
		return "ActivityParser:" + getType();
	}
	@Override
	protected String[] getCronExpressions() {
		return new String[] { "*/1 * * * * ?" };
	}
	@Override
	public void execute() {
		// LOGGER.error("AbstractActivityParser every second excute, className:{}",
		// this.getClass().getName());
		Collection<ActivityOpenConfig> result = ActivityOpenConfigService.getByType(getType());
		if (result.isEmpty()) {
			return;
		}
		List<ActivityOpenConfig> listClose = Lists.newArrayList();
		List<ActivityOpenConfig> listOpen = Lists.newArrayList();
		List<ActivityOpenConfig> listShow = Lists.newArrayList();
		for (ActivityOpenConfig activityOpenConfig : result) {
			ActivityGlobal activityGlobal = activityGlobalDao.getActivityGlobal(activityOpenConfig.getId());
			if (activityGlobal == null || activityGlobal.getStatus() == ActivityStatus.CLOSE.getId()) {
				Date now = new Date();
				ActivityTime activityTime = ActivityOpenConfigService.getOpenTime(activityOpenConfig.getId(), new Date());
				if (activityTime == null) {
					continue;
				}
				if (now.before(activityTime.getCloseTime()) && now.after(activityTime.getOpenTime())) {
					activityGlobalDao.createActivityGlobal(activityOpenConfig.getId(), activityTime.getOpenTime().getTime(),
							activityTime.getCloseTime().getTime(), activityTime.getShowTime().getTime());
					listOpen.add(activityOpenConfig);
				}
			} else {
				if (activityGlobal.getStatus() == ActivityStatus.RUNNING.getId() || activityGlobal.getStatus() == ActivityStatus.SHOW.getId()) {
					if (System.currentTimeMillis() >= activityGlobal.getCloseTime()) {
						LOGGER.info("activityGlobal:{},status:{},closeTime:{}", activityGlobal.getActivityId(), activityGlobal.getStatus(),
								DateUtils.formatTime(activityGlobal.getCloseTime()));
						listClose.add(activityOpenConfig);
						activityGlobal.setStatus(ActivityStatus.CLOSE);
						dbQueue.updateQueue(activityGlobal);
					} else {
						ActivityTime activityTime = ActivityOpenConfigService.getOpenTime(activityOpenConfig.getId(), new Date());
						if (activityTime == null) {
							LOGGER.info("activityGlobal:{},status:{},closeTime:{}", activityGlobal.getActivityId(), activityGlobal.getStatus(),
									DateUtils.formatTime(activityGlobal.getCloseTime()));
							listClose.add(activityOpenConfig);
							activityGlobal.setStatus(ActivityStatus.CLOSE);
							dbQueue.updateQueue(activityGlobal);
							continue;
						}
						if (activityGlobal.getOpenTime() != activityTime.getOpenTime().getTime()
								|| activityGlobal.getCloseTime() != activityTime.getCloseTime().getTime()) {
							try {
								boolean isClose = activityGlobal.refreshTime(activityTime.getOpenTime().getTime(),
										activityTime.getCloseTime().getTime(), activityTime.getShowTime().getTime());
								if (isClose) {
									LOGGER.info("Close activity activityId:{}, status:{}", activityGlobal.getActivityId(),
											activityGlobal.getStatus());
									listClose.add(activityOpenConfig);
								}
								dbQueue.updateQueue(activityGlobal);
								LOGGER.info("RefreshActivityTime activityId:{},status:{},openTime:{},closeTime:{}", activityGlobal.getActivityId(),
										activityGlobal.getStatus(), DateUtils.formatTime(activityGlobal.getOpenTime()),
										DateUtils.formatTime(activityGlobal.getCloseTime()));
							} catch (Exception e) {
								LOGGER.error("{}", e);
							}
						}
					}
				}
				if (activityGlobal.getStatus() == ActivityStatus.RUNNING.getId()) {
					if (System.currentTimeMillis() > activityGlobal.getShowTime()) {
						LOGGER.debug("activityGlobal:{},status:{},closeTime:{}", activityGlobal.getActivityId(), activityGlobal.getStatus(),
								DateUtils.formatTime(activityGlobal.getCloseTime()));
						listShow.add(activityOpenConfig);
						activityGlobal.setStatus(ActivityStatus.SHOW);
						dbQueue.updateQueue(activityGlobal);
					}
				}
			}
		}
		if (!listClose.isEmpty()) {
			LOGGER.debug("activity end:{}", StringUtils.collection2SplitString(listClose, ","));
			onActivityEnd(listClose);
			for (ActivityOpenConfig openConfig : listClose) {
				List<Long> actorIds = activityRecordDao.getActorIds(openConfig.getId());
				for (Long actorId : actorIds) {
					activityRecordDao.delete(actorId, openConfig.getId());
				}
			}
		}
		if (!listOpen.isEmpty()) {
			LOGGER.debug("activity open:{}", StringUtils.collection2SplitString(listOpen, ","));
			long mergeServerTime = SettingsHelper.getSettingValue(SettingKey.MERGE_SERVER_TIME);
			List<Integer> activityTypeList = globalConfigService
					.findGlobalObject(GlobalConfigKey.MERGE_SERVER_NOT_CLOSE_ACTIVITY_TYPE, IntListConfig.class).getVs();
			for (ActivityOpenConfig openConfig : listOpen) {
				if (DateUtils.isToday(mergeServerTime)) {
					if (activityTypeList.contains(openConfig.getActivityType())) {
						continue;
					}
				}
				List<Long> actorIds = activityRecordDao.getActorIds(openConfig.getId());
				for (Long actorId : actorIds) {
					activityRecordDao.delete(actorId, openConfig.getId());
				}
			}
			onActivityOpen(listOpen);
			Set<Long> onlineActorList = PlayerChannel.onlineActorList();
			for (ActivityOpenConfig activityOpenConfig : listOpen) {
				for (Long actorId : onlineActorList) {
					this.pushActivity(actorId, activityOpenConfig.getId());
				}
			}
		}
		if (!listShow.isEmpty()) {
			onActivityShow(listShow);
			Set<Long> onlineActorList = PlayerChannel.onlineActorList();
			for (ActivityOpenConfig activityOpenConfig : listOpen) {
				for (Long actorId : onlineActorList) {
					this.pushActivity(actorId, activityOpenConfig.getId());
				}
			}
		}
	}
	/**
	 * 推送活动信息
	 * @param actorId
	 * @param activityId
	 */
	protected void pushActivity(long actorId, int activityId) {
		TResult<ActivityRecordVO> recordResult = this.getRecord2Client(actorId, activityId);
		if (recordResult.isFail()) {
			return;
		}
		TResult<ActivityGlobalVO> globalResult = this.getGlobal2Client(actorId, activityId);
		pushActivity(actorId, activityId, globalResult.item, recordResult.item);
	}

	/**
	 * 推送活动信息
	 * @param actorId
	 * @param activityId
	 * @param global
	 * @param record
	 */
	protected void pushActivity(long actorId, int activityId, ActivityGlobalVO global, ActivityRecordVO record) {
		ActivityInfoVO vo = ActivityInfoVO.valueOf(activityId, global, record);
		ActivityInfoResponse response = ActivityInfoResponse.valueOf(Lists.newArrayList(vo));
		ActivityPushHelper.pushActivity(actorId, response);
	}
	@EventOnline(trigger = TriggerTime.FIXED_HOUR, triggerValue = 24)
	public void onEvery0Hour(GameEvent e) {
		List<ActivityOpenConfig> activityOpenConfigList = ActivityOpenConfigService.getActivityOpenConfigList(getType());
		for (ActivityOpenConfig activityOpenConfig : activityOpenConfigList) {
			pushActivity(e.getUniqueId(), activityOpenConfig.getId());
		}
	}
}

具体活动实现

冲级大赛活动示例,活动主要接口是getRecord2Client查询活动数据,receiveReward领取奖励,onEvent事件触发,onActivityOpen活动开启,onActivityEnd活动结束。
这个活动只需要在活动关闭时调用sendActorLevelActivityReard,计算玩家等级发放奖励邮件即可

**
 * 冲级大赛活动解析器
 * @author xyq
 */
@Component
public class ActivityParser8 extends AbstractActivityParser {
	@Autowired
	private DataConfig dataConfig;
	@Autowired
	private ActorFacade actorFacade;
	@Override
	public TResult<ActivityActionResponse> receiveReward(long actorId, int activityId, int id, Map<Integer, Object> parmeterMap) {
		return null;
	}
	@Override
	public TResult<ActivityRecordVO> getRecord2Client(long actorId, int activityId) {
		return TResult.sucess(new ActivityRecordVO() {
			@Override
			public ActivityType getType() {
				return ActivityType.ACTIVITY_TYPE_8;
			}
		});
	}
	@Override
	public TResult<ActivityGlobalVO> getGlobal2Client(long actorId, int activityId) {
		return TResult.fail();
	}
	@Override
	public void registerEvent(Set<String> eventSet) {
	}
	@Override
	public void onEvent(GameEvent e) {
	}
	@Override
	protected ActivityType getType() {
		return ActivityType.ACTIVITY_TYPE_8;
	}
	@Override
	protected void onActivityOpen(List<ActivityOpenConfig> openActivityIds) {
	}
	@Override
	protected void onActivityEnd(List<ActivityOpenConfig> endActivityIds) {
		for (ActivityOpenConfig activityOpenConfig : endActivityIds) {
			sendActorLevelActivityReard(activityOpenConfig);
		}
	}
	/**
	 * 发放邮件奖励
	 * @param activityOpenConfig
	 */
	private void sendActorLevelActivityReard(ActivityOpenConfig activityOpenConfig) {
		TreeMap<Long, List<RewardObject>> rewardMap = Maps.newTreeMap();
		Collection<LevelRankActivityConfig> configList = dataConfig.getList(LevelRankActivityConfig.class);
		for (LevelRankActivityConfig config : configList) {
			if (activityOpenConfig.getData() == config.getData()) {
				rewardMap.put(config.getRank(), config.getRewardList());
			}
		}
		String date = DateUtils.SDF_SHORT_DATE.format(new Date());
		TResult<ActorLevelRankResponse> result = actorFacade.getLevelRankResponse(1);
		if (result.isFail()) {
			return;
		}
		ActorLevelRankResponse response = result.item;
		int maxRank = globalConfigService.findGlobalConfig(GlobalConfigKey.ACTOR_LEVEL_MAX_RANK).findInt();
		for (ActorLevelRankVO actorLevelRankVO : response.getRanks()) {
			if (actorLevelRankVO.getRank() > maxRank || actorLevelRankVO.getRank() > rewardMap.lastKey()) {
				continue;
			}
			List<RewardObject> rewardList = rewardMap.ceilingEntry(actorLevelRankVO.getRank()).getValue();
			Map<String, String> params = Maps.newHashMap();
			params.put("name", (String) actorLevelRankVO.getAttributes().get(ActorKey.ACTOR_NAME.getId()));
			params.put("rank", String.valueOf(actorLevelRankVO.getRank()));
			params.put("date", date);
			MailAddEvent event = new MailAddEvent((Long) actorLevelRankVO.getAttributes().get(ActorKey.ACTOR_ID.getId()),
					MailTemplateType.ACTOR_LEVEL_ACTIVITY_REWARD, params, rewardList);
			DispatchHelper.postEvent(event);
			LOGGER.debug("sendActorLevelActivityReward actorId:{},params:{}", (Long) actorLevelRankVO.getAttributes().get(ActorKey.ACTOR_ID.getId()),
					params);
		}
		LOGGER.info("sendActorLevelActivityReward Completed !");
	}
}

ScheduleCronJob活动调度器

/**
 * Cron表达式调度
 * @author CharonWan
 */
public abstract class ScheduleCronJob implements ScheduleJob {
	protected final Logger LOGGER = LoggerFactory.getLogger(this.getClass());
	@Autowired
	private TaskScheduler taskScheduler;
	@Override
	public void ready() {
		String[] crons = getCronExpressions();
		for (String cron : crons) {
			Trigger trigger = new CronTrigger(cron);
			taskScheduler.schedule(this, trigger);
			LOGGER.info("ScheduleCronJob:{},cron:{} ready!...", jobName(), cron);
		}
	}
	/**
	 * 调度时间
	 * @return
	 */
	protected abstract String[] getCronExpressions();

	@Override
	public void run() {
		try {
			LOGGER.trace("ScheduleCronJob:{},execute start...", jobName());
			execute();
			LOGGER.trace("ScheduleCronJob:{},execute complete...", jobName());
		} catch (Exception e) {
			LOGGER.error("ScheduleCronJob:{},execute error...", jobName());
			LOGGER.info("{}", e);
		}
	}
	/**
	 * 执行任务
	 */
	public abstract void execute();
}

定时任务

/**
 * 定时任务
 * @author CharonWang
 */
public interface ScheduleJob extends Runnable {
	/**
	 * 准备任务
	 */
	void ready();
	/**
	 * 任务名称
	 * @return
	 */
	String jobName();
}

主要难点就是活动解析器,大部分时间我也是在使用,分享下一起学习