游戏福利系统设计实践

简介

作为一款游戏要拉动用户日活必须要有一点的奖励或者是付费,这就要设计到福利系统的,包括每日登录,日卡,月卡等等的。而我们要面对这么多的福利功能的时候,一个设计得当的福利系统框架会减少我们很多的工作量,而且系统稳定,后续维护少等优点。

哪问题来了,该如何设计了?

设计的思路

要设计一个系统或一个框架的时候,我们第一时间需要搬出来的就是设计模式。对设计模式六大原则中的两个原则进项

  • 里氏替换原则(LSP liskov substitution principle):子类可以扩展父类的功能,但不能改变原有父类的功能(目的:增强程序的健壮性)实际项目中,每个子类对应不同的业务含义,使父类作为参数,传递不同的子类完成不同的业务逻辑。
  • 开闭原则(open closed principle):用抽象构建架构,用实现扩展原则

基于上面的原则,那么我们就需要对类和类之间进行处理了。

设计流程图

在这里插入图片描述

  1. 使用枚举的方式来管理和初始化要福利管理类
  2. 在福利管理类中通过泛型的方式转换为要处理的具体的福利对象

具体的实战代码

/**
 * 个人福利数据
 * */
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, property = "name")
public class OtherWelfareRoleData{

    /**
     * 福利活动配置id
     * */
    private int otherWelfareId;

    public int getOtherWelfareId() {
        return otherWelfareId;
    }

    public void setOtherWelfareId(int otherWelfareId) {
        this.otherWelfareId = otherWelfareId;
    }
}

如下是具体的数据库中的福利数据
在这里插入图片描述

/**
 * 事件监听者接口
 */
public interface EventListenerIF {

	/**
	 * 初始化监听的事件类型
	 */
	void initStruct();

	/**
	 * 增加事件监听
	 */
	default void addEventListener(EventType eventType) {
		ListenerMgrHolder.getInstance().addEventListener(eventType, this);
	}

	/**
	 * 事件监听
	 */
	void onListener(EventType<?> eventType, EventParam eventParam);

}
package com.server.game.scene.otherWelfare;


import com.server.game.listener.EventType;
import com.server.game.listener.event.EventListenerIF;
import com.server.game.listener.event.EventParam;
import com.server.game.scene.otherWelfare.mgr.OtherWelfareManager;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.util.HashMap;


/**
 * 其他福利服务基类
 */
public abstract class OtherWelfareService implements EventListenerIF {

	public static final Logger log = LogManager.getLogger(OtherWelfareService.class);

	protected OtherWelfareEnum otherWelfareEnum;

	@Override
	public void onListener(EventType<?> eventType, EventParam eventParam) {

	}

	/**
	 * 初始化监听器那些
	 */
	public void initStruct() {

	}

	/**
	 * 点击页签执行
	 */
	public void onClick(long roleId) {

	}

	/**
	 * 登陆初始数据执行
	 */
	public void onLoginInitData(long roleId) {

	}

	/**
	 * 登陆监听执行
	 */
	public void onLogin(long roleId) {

	}

	/**
	 * 当功能开启
	 */
	public void onFuncOpen(long roleId) {

	}

	/**
	 * 登录是否下发
	 */
	public boolean loginPush(long roleId) {
		return true;
	}

	/**
	 * 取出玩家数据
	 */
	@SuppressWarnings("unchecked")
	protected <R extends OtherWelfareRoleData> R getRoleData(long roleId) {
		HashMap<Integer, OtherWelfareRoleData> roleDataHashMap = OtherWelfareManager.getInstance().getById(roleId).getData();
		R roleData = (R) roleDataHashMap.get(otherWelfareEnum.getType());
		if (roleData == null) {
			roleData = createRoleData(roleId);
			if (roleDataHashMap.putIfAbsent(otherWelfareEnum.getType(), roleData) == null) {
				return roleData;
			}
			return (R) roleDataHashMap.get(otherWelfareEnum.getType());
		}
		return roleData;
	}

	/**
	 * 新建玩家数据
	 */
	protected abstract <R extends OtherWelfareRoleData> R createRoleData(long roleId);

	public void setOtherWelfareEnum(OtherWelfareEnum otherWelfareEnum) {
		this.otherWelfareEnum = otherWelfareEnum;
	}

}

在这里插入图片描述

package com.server.game.scene.otherWelfare.impl.giftPush;

import com.server.core.thread.GlobalThreadPool;
import com.server.game.constant.ModuleConst;
import com.server.game.data.config.bean.ActivityGiftPushRewardConfig;
import com.server.game.data.config.container.ActivityGiftConditionConfigContainer;
import com.server.game.data.config.container.ActivityGiftPushRewardConfigContainer;
import com.server.game.data.config.container.PayConfigConfigContainer;
import com.server.game.data.config.decorator.ActivityGiftConditionConfigDecorator;
import com.server.game.data.config.decorator.ActivityGiftPushRewardConfigDecorator;
import com.server.game.data.config.decorator.PayConfigConfigDecorator;
import com.server.game.listener.EventType;
import com.server.game.listener.event.EventParam;
import com.server.game.listener.event.paramImpl.TwoIntParam;
import com.server.game.listener.requirement.ConditionCompareUtil;
import com.server.game.listener.requirement.RequireGroup;
import com.server.game.logic.PushEventLogic;
import com.server.game.quartz.QuartzMgr;
import com.server.game.recharge.RechargeType;
import com.server.game.scene.item.manager.ResourceLogic;
import com.server.game.scene.otherWelfare.OtherWelfareRoleData;
import com.server.game.scene.otherWelfare.OtherWelfareService;
import com.server.game.scene.otherWelfare.impl.giftPush.data.GiftPushInfo;
import com.server.game.scene.otherWelfare.impl.giftPush.dto.SCActivityGiftPushData;
import com.server.game.scene.otherWelfare.impl.giftPush.job.GiftPushJob;
import com.server.game.utils.DateUtil;

import java.util.AbstractMap;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

/**
 * 礼包推送服务
 * */
public class GiftPushService extends OtherWelfareService {

    /**
     * 上次的定时的礼物推送时间
     */
    private static long lastTimeGift = 0L;

    @Override
    public void onListener(EventType<?> eventType, EventParam eventParam) {
        if(eventType == EventType.Recharge){
            TwoIntParam twoIntParam = (TwoIntParam) eventParam;
            PayConfigConfigDecorator payConfig = PayConfigConfigContainer.getInstance().getDecorator(twoIntParam.getParam1());
            if(payConfig.getType() == RechargeType.GIFT_PUSH.getType()) {
                ActivityGiftPushRewardConfigDecorator config = ActivityGiftPushRewardConfigContainer.getInstance().getByPayId(payConfig.getId());
                ResourceLogic.addResourceNotEnoughEmail(eventParam.getRoleId(), config.getReward(), ModuleConst.GiftPush);
                GiftPushData giftPushData = getRoleData(eventParam.getRoleId());
                if(config.getId() == giftPushData.getGiftPushRewardId()){
                    giftPushData.setGiftPushRewardId(0);
                    giftPushData.setOverTime(0L);
                    pushData(eventParam.getRoleId(), giftPushData, false);
                }
            }
        }
    }

    @Override
    public void initStruct() {
        addEventListener(EventType.Recharge);
    }

    /**
     * 初始化数据
     * */
    public void initData(){
        for (ActivityGiftConditionConfigDecorator config : GiftPushEnum.CRONTIME_TYPE.getConfigs()) {
            long nextTime = config.getTime();
            if(nextTime < DateUtil.getSecondLevelMillis())
                continue;
            GlobalThreadPool.schedule(new GiftPushJob(config), nextTime - DateUtil.getSecondLevelMillis(), TimeUnit.MILLISECONDS);
        }
    }

    @Override
    protected <R extends OtherWelfareRoleData> R createRoleData(long roleId) {
        GiftPushData giftPushData = new GiftPushData();
        giftPushData.setAlreadyFinish(new HashSet<>());
        giftPushData.setCondition(new ConcurrentHashMap<>());
        return (R) giftPushData;
    }

    @Override
    public void onLoginInitData(long roleId) {
        GiftPushData giftPushData = getRoleData(roleId);
        //登陆初始化条件
        for (ActivityGiftConditionConfigDecorator config : GiftPushEnum.CONDITION_TYPE.getConfigs()) {
            if (giftPushData.getAlreadyFinish().contains(config.getId()))
                continue;
            Map<Integer, GiftPushInfo> conditions = giftPushData.getCondition();
            if (conditions.containsKey(config.getId())) {
                GiftPushInfo giftPushInfo = conditions.get(config.getId());
                RequireGroup newRequire = ConditionCompareUtil.transToRequireGroup(config.getCondition());
                giftPushInfo.setProgress(ConditionCompareUtil.compareUpdateRequire(giftPushInfo.getProgress(), newRequire));
                giftPushInfo.loadByProgress();
            } else {
                GiftPushInfo giftPushInfo = new GiftPushInfo();
                conditions.put(config.getId(), giftPushInfo);
                giftPushInfo.setConditionId(config.getId());
                giftPushInfo.setRoleId(roleId);
                giftPushInfo.initProgressByOne(ConditionCompareUtil.transToRequireGroup(config.getCondition()));
            }
        }
    }


    @Override
    public void onLogin(long roleId) {
        GiftPushData data = getRoleData(roleId);
        int rewardId = data.getGiftPushRewardId();
        ActivityGiftPushRewardConfigDecorator timeConfig = GiftPushEnum.CRONTIME_TYPE.getRewardConfig(roleId, null);
        ActivityGiftPushRewardConfigDecorator myConfig = ActivityGiftPushRewardConfigContainer.getInstance().getDecorator(data.getGiftPushRewardId());
        long timeStartTime = lastTimeGift;
        if (myConfig == null || timeStartTime > data.getOverTime() - myConfig.getDuration() * DateUtil.MINUTE) {
            data.setOverTime(lastTimeGift + timeConfig.getDuration() * DateUtil.MINUTE);
            data.setGiftPushRewardId(timeConfig.getId());
        }
        if (data.getGiftPushRewardId() != 0 && data.getOverTime() >= DateUtil.getSecondLevelMillis()) {
            pushData(roleId, data, rewardId != data.getGiftPushRewardId());
        }
    }

    @Override
    public void onFuncOpen(long roleId) {
        onLogin(roleId);
    }

    /**
     * 完成对应档位
     * */
    public void finish(long roleId, int giftConditionId){
        ActivityGiftConditionConfigDecorator conditionConfig = ActivityGiftConditionConfigContainer.getInstance().getDecorator(giftConditionId);
        if(conditionConfig == null) {
            log.error("推送礼包配置不存在{}", giftConditionId);
            return;
        }
        GiftPushData data = getRoleData(roleId);
        if(data.getAlreadyFinish().contains(giftConditionId))
            return;
        data.getAlreadyFinish().add(giftConditionId);
        data.getCondition().remove(giftConditionId);
        //推送礼包
        pushGift(roleId, conditionConfig.getRewardId());
    }

    /**
     * 推送礼包
     * */
    public void pushGift(long roleId, int giftRewardId){
        GiftPushData data = getRoleData(roleId);
        ActivityGiftPushRewardConfigDecorator rewardConfig = ActivityGiftPushRewardConfigContainer.getInstance().getDecorator(giftRewardId);
        if(rewardConfig == null) {
            log.error("推送礼包配置不存在{}", giftRewardId);
            return;
        }
        data.setGiftPushRewardId(rewardConfig.getId());
        data.setOverTime(DateUtil.getSecondLevelMillis() + rewardConfig.getDuration() * DateUtil.MINUTE);
        pushData(roleId, data, true);
    }

    /**
     * 推送
     */
    private void pushData(long roleId, GiftPushData data, boolean isShow){
        SCActivityGiftPushData scActivityGiftPushData = new SCActivityGiftPushData();
        scActivityGiftPushData.setOverTime(data.getOverTime());
        scActivityGiftPushData.setGiftRewardId(data.getGiftPushRewardId());
        scActivityGiftPushData.setTip(isShow);
        PushEventLogic.pushEvent(roleId, scActivityGiftPushData);
    }

    /**
     * 设置定时的时间礼包
     * */
    public static void setTimeGift(){
        lastTimeGift = DateUtil.getSecondLevelMillis();
    }

}

最后通过一个枚举类联系服务类和数据类

package com.server.game.scene.otherWelfare;


import com.server.game.scene.funcOpen.FuncType;
import com.server.game.scene.otherWelfare.impl.dayGift.DayGiftWelfareService;
import com.server.game.scene.otherWelfare.impl.firstRecharge.FirstRechargeService;
import com.server.game.scene.otherWelfare.impl.giftPush.GiftPushService;
import com.server.game.scene.otherWelfare.impl.levelInvest.LevelInvestWelfareService;
import com.server.game.scene.otherWelfare.impl.warTrophies.service.WarTrophiesService;

import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;


public enum OtherWelfareEnum {

	/**
	 * 每日礼包
	 */
	DAY_GIFT(2, new DayGiftWelfareService(), FuncType.ActivityDayGift),

	/**
	 * 等级投资
	 */
	LEVEL_INVEST(4, new LevelInvestWelfareService(), FuncType.ActivityLevelInvest),

	/**
	 * 战利品
	 */
	WAR_TROPHIES(5, new WarTrophiesService(), FuncType.Activitytreasury),

	/**
	 * 礼包推送
	 */
	GIFT_PUSH(6, new GiftPushService(), FuncType.ActivityGiftPush),

	/**
	 * 首冲
	 */
	FirstRecharge(7, new FirstRechargeService(), FuncType.FirstRecharge),

	;

	private final int type;

	private final OtherWelfareService service;

	private final FuncType funcType;

	OtherWelfareEnum(int type, OtherWelfareService service, FuncType funcType) {
		this.type = type;
		this.service = service;
		this.service.setOtherWelfareEnum(this);
		this.funcType = funcType;
	}

	public int getType() {
		return type;
	}

	public OtherWelfareService getService() {
		return service;
	}

	public FuncType getFuncType() {
		return funcType;
	}

	private static Map<Integer, OtherWelfareEnum> map = Stream.of(OtherWelfareEnum.values()).collect(Collectors.toMap(v -> v.type, v -> v));

	public static OtherWelfareEnum getByType(int type) {
		return map.get(type);
	}
}

调用的方式如下:

 GiftPushService service = (GiftPushService) OtherWelfareEnum.GIFT_PUSH.getService();
 service.pushGift(onlineRole.getRoleId(), GiftPushEnum.CRONTIME_TYPE.getRewardConfig(onlineRole.getRoleId(), null).getId());

总结

就是通过枚举的方式获得对应的福利的服务类,然后通过服务类和福利的具体数据来出来相应的数据。其中服务类中继承需要从父服务类中继承的接口来处理具体的逻辑。

结语

通过上面的方式可以设计一个只需要定义好具体福利即可,其他具体的处理放入到具体的服务类和数据类中。这样方便后续服务的扩张。

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值